02-redis的持久化和数据类型

发布时间 2023-12-26 19:41:05作者: EJW

一、redis持久化

1.1 持久化类型

|持久化类型 | 介绍|优点|缺点
|-------------|-----------------|-----------------|-------------|--
|RDB持久化 | 可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。|速度快,适合于用做备份,主从复制也是基于RDB持久化功能实现的。|会有丢失部分数据
AOF 持久化 | 记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。|可以最大程度保证数据不丢|日志记录量级比较大

1.2 RDB持久化配置

vim /data/6379/redis.conf
dir /data/6379 #存放路径
dbfilename dump.rdb #RDB持久化文件名
save 900 1
save 300 10
save 60 10000

配置分别表示:
900秒(15分钟)内有1个更改 会save一次
300秒(5分钟)内有10个更改会save一次
60秒内有10000个更改会save一次

RDB 持久化高级配置

stop-writes-on-bgsave-error yes //后台备份进程出错时,主进程停不停止写入? 主进程不停止容易造成数据不一致 

rdbcompression yes  //导出的rdb文件是否压缩 如果rdb的大小很大的话建议这么做



1.3 AOF持久化配置

appendonly yes  //是否打开aof日志功能
appendfsync always //每做一次更改就会记录一次

appendfsync everysec //每秒持久化一次
appendfsync no //不做持久话

AOF 持久化其他配置

no-appendfsync-on-rewrite yes/no //正在导出rdb快照的过程中,要不要停止同步aof
auto-aof-rewrite-percentage 100   //aof文件大小比起上次重写时的大小,增长率100%时重写,缺点:业务开始的时候,会重复重写多次
auto-aof-rewrite-min-size 64mb   //aof文件,至少超过64M时,重写

例子:

vim /data/6379/redis.conf
appendonly yes
appendfsync everysec 

二、Redis的数据类型

2.1 数据类型基本定义
数据类型
string类型 name "zhangsan"
hash类型(字典类型) stu
LIST类型 wechat (v1,v2,v3)
SET(集合类型)) set1 [m1,m2,m3]
Sorted SET(有序) zset1 [socre m1,score m2,score m3]

说明:出去了普通的string类型,其他都会有一个下标索引的东西

2.2 数据类型应用场景及基本操作

1 、 String类型

  • 应用场景:
    • 非常基本的键值对存储
    • 计数器:
      互联网当中,点击量,访问量,关注量等
      网页游戏应用当中的,血量、蓝量等
基本操作
127.0.0.1:6379> set name zhangsan 
OK
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> mset id 101 name zhangsan age 20 gender male 
OK
127.0.0.1:6379> mget id name age gender
计数器应用
127.0.0.1:6379> incr fensi
127.0.0.1:6379> DECR fensi
127.0.0.1:6379> INCRBY fensi 10000
127.0.0.1:6379> DECRBY fensi 10003

127.0.0.1:6379> get fensi

2、 HASH类型(字典类型)

  • 应用场景:最接近于MySQL表结构的数据类型
    存储部分变更的数据,如用户信息,缓存mysql的数据等。
基本操作:
127.0.0.1:6379> hset zhangsan name zs
(integer) 1
127.0.0.1:6379> hmset student id 101 name zs age 20 gender male
OK
127.0.0.1:6379> hmset stu id 102 name lisi age 21 gender male
OK
127.0.0.1:6379> hmget stu id name age gender
1) "102"
2) "lisi"
3) "21"
4) "male"
127.0.0.1:6379> hgetall stu
1) "id"
2) "102"
3) "name"
4) "lisi"
5) "age"
6) "21"
7) "gender"
8) "male"

3、 小扩展:

MySQL 中 city表中数据,灌入到redis中

思路:通过mysql的concat命令拼接出我们我们想要的rdis命令格式,然后导入到redis中

mysql> select concat("hmset Name_",Name, "  CountryCode  " ,CountryCode, "  District  ",District,"  Population  ",Population) from world.city limit 5;
+-----------------------------------------------------------------------------------------------------------------+
| concat("hmset Name_",Name, "  CountryCode  " ,CountryCode, "  District  ",District,"  Population  ",Population) |
+-----------------------------------------------------------------------------------------------------------------+
| hmset Name_Kabul  CountryCode  AFG  District  Kabol  Population  1780000                                        |
| hmset Name_Qandahar  CountryCode  AFG  District  Qandahar  Population  237500                                   |
| hmset Name_Herat  CountryCode  AFG  District  Herat  Population  186800                                         |
| hmset Name_Mazar-e-Sharif  CountryCode  AFG  District  Balkh  Population  127800                                |
| hmset Name_Amsterdam  CountryCode  NLD  District  Noord-Holland  Population  731200                             |
+-----------------------------------------------------------------------------------------------------------------+
5 rows in set (0.00 sec)

mysql> select * from world.city limit 5;
+----+----------------+-------------+---------------+------------+
| ID | Name           | CountryCode | District      | Population |
+----+----------------+-------------+---------------+------------+
|  1 | Kabul          | AFG         | Kabol         |    1780000 |
|  2 | Qandahar       | AFG         | Qandahar      |     237500 |
|  3 | Herat          | AFG         | Herat         |     186800 |
|  4 | Mazar-e-Sharif | AFG         | Balkh         |     127800 |
|  5 | Amsterdam      | NLD         | Noord-Holland |     731200 |
+----+----------------+-------------+---------------+------------+
5 rows in set (0.01 sec)

在命令行生成文件

mysql -uroot -p123   -e   'select concat("hmset Name_",Name, "  CountryCode  " ,CountryCode, "  District  ",District,"  Population  ",Population) from world.city;'>city_redis.sql 2>/dev/null && sed -i '1d' city_redis.sql 

导入到redis中

#bin/bash
sed -i 's/hmset /&"/g' city_redis.sql
sed -i 's/  CountryCode  /"&"/g' city_redis.sql
sed -i 's/  District  /"&"/g'  city_redis.sql
sed -i 's/  Population  /"&/g' city_redis.sql
while read line
do
echo redis-cli -h 10.0.0.11 $line >> city_redis_new.sh
done</data/6379/city_redis.sql
/bin/bash city_redis_new.sh

4 、List列表类型

  • 应用场景:朋友圈应用
    在Redis中我们的最新微博ID使用了常驻缓存,这是一直更新的。
    但是做了限制不能超过5000个ID,因此获取ID的函数会一直询问Redis。
    只有在start/count参数超出了这个范围的时候,才需要去访问数据库。 
    系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。
    SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。

例子:微信朋友圈应用

127.0.0.1:6379> LPUSH wechat "today is 1"
(integer) 1
127.0.0.1:6379> LPUSH wechat "today is 2"
(integer) 2
127.0.0.1:6379> LPUSH wechat "today is 3"
(integer) 3
127.0.0.1:6379> LPUSH wechat "today is 4"
(integer) 4
127.0.0.1:6379> LPUSH wechat "today is 5"

127.0.0.1:6379> LRANGE wechat 0 -1
1) "today is 5"
2) "today is 4"
3) "today is 3"
4) "today is 2"
5) "today is 1"
127.0.0.1:6379> 

5、 SET 集合类型

  • 应用场景:
    案例:在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。
    Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,
    对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。
127.0.0.1:6379> sadd lxl pg1 pg2 baoqiang masu marong 
(integer) 5
127.0.0.1:6379> sadd jnl baoqiang yufan baobeier zhouxingchi 
(integer) 4
127.0.0.1:6379> SUNION lxl jnl  //求并集
1) "zhouxingchi"
2) "baobeier"
3) "pg2"
4) "yufan"
5) "masu"
6) "baoqiang"
7) "pg1"
8) "marong"
127.0.0.1:6379> 
127.0.0.1:6379> SINTER lxl jnl //求交集
1) "baoqiang"
127.0.0.1:6379> SDIFF lxl jnl  //求差集(lxl有jnl没有的)
1) "masu"
2) "pg1"
3) "marong"
4) "pg2"
127.0.0.1:6379> SDIFF jnl lxl 
1) "yufan"
2) "zhouxingchi"
3) "baobeier"

6、 Sorted Set 有序集合

  • 排行榜应用,取TOP N操作 
    这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,
    比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score
    ,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。

例子: 歌曲排行榜

127.0.0.1:6379> zadd music 0 fskl 0 fshkl 0 lzlsfs 0 tm 0 ass 
(integer) 5
127.0.0.1:6379> 
127.0.0.1:6379> ZINCRBY music 1000 fskl 
"1000"
127.0.0.1:6379> ZINCRBY music 10000  fshkl
"10000"
127.0.0.1:6379> ZINCRBY music 100000 lzlsfs
"100000"
127.0.0.1:6379> ZINCRBY music 1000000 tm
"1000000"
127.0.0.1:6379> ZINCRBY music 100 ass
"100"
127.0.0.1:6379> ZREVRANGE music 0 -1 withscores //所有键从高到底排名
 1) "tm"

三、消息队列

1、 消息队列的介绍

image

  • Redis发布消息通常有两种模式:
    • 队列模式(queuing)
    • 发布-订阅模式(publish-subscribe)

任务队列的好处:松耦合。易于扩展

2、发布订阅

(1) 订阅频道,可以同时订阅多个频道

SUBSCRIBE channel [channel ...]

(2) 将信息 message 发送到指定的频道 channel

 PUBLISH channel msg

(3) 取消订阅指定的频道, 如果不指定频道,则会取消订阅所有频道

UNSUBSCRIBE [channel ...]

(4) 订阅一个或多个符合给定模式的频道,每个模式以 * 作为匹配符,比如 it* 匹配所 有以 it 开头的频道( it.news 、 it.blog 、 it.tweets 等等), news.* 匹配所有 以 news. 开头的频道( news.it 、 news.global.today 等等),诸如此类

PSUBSCRIBE pattern [pattern ...]

(5) 退订指定的规则, 如果没有参数则会退订所有规则

PUNSUBSCRIBE [pattern [pattern ...]]

(6) 查看订阅与发布系统状态

PUBSUB subcommand [argument [argument ...]]

注意:使用发布订阅模式实现的消息队列,当有客户端订阅channel后只能收到后续发布到该频道的消息,之前发送的不会缓存,必须Provider和Consumer同时在线。

发布订阅的例子

窗口1:

127.0.0.1:6379> SUBSCRIBE baodi 

窗口2:

127.0.0.1:6379> PUBLISH baodi "jin tian zhen kaixin!"

订阅多频道:
窗口1:
127.0.0.1:6379> PSUBSCRIBE wang*
窗口2:
127.0.0.1:6379> PUBLISH wangbaoqiang "jintian zhennanshou "

3、消息队列系统对比

客户端在执行订阅命令之后进入了订阅状态,只能接收 SUBSCRIBE 、PSUBSCRIBE、 UNSUBSCRIBE 、PUNSUBSCRIBE 四个命令。 开启的订阅客户端,无法收到该频道之前的消息,因为 Redis 不会对发布的消息进行持久化。 和很多专业的消息队列系统(例如Kafka、RocketMQ)相比,Redis的发布订阅略显粗糙,例如无法实现消息堆积和回溯。但胜在足够简单,如果当前场景可以容忍的这些缺点,也不失为一个不错的选择