redis数据类型之二

redis数据类型之二

第一部分:列表

redis列表就是redis的字符串类型的集合,按照插入顺序排序.
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)一个列表最多可以包含 2^32 - 1 个元素 (4294967295, 每个列表超过40亿个元素)
1.lpush 从左边插入数据(排序顺序是:先进后出)
127.0.0.1:6379> lpush people meiyangyang
(integer) 1
127.0.0.1:6379> lpush people chouyangyang
(integer) 2
127.0.0.1:6379> lpush people bayangyang jiyangyang
(integer) 4
127.0.0.1:6379> lrange people 0 -1
1) "jiyangyang"
2) "bayangyang"
3) "chouyangyang"
4) "meiyangyang"
2.rpush 从右边插入数据(排序顺序是:先进先出)
127.0.0.1:6379> rpush people 111
(integer) 5
127.0.0.1:6379> rpush people 222 333 444
(integer) 8
127.0.0.1:6379> lrange people 0 -1
1) "jiyangyang"
2) "bayangyang"
3) "chouyangyang"
4) "meiyangyang"
5) "111"
6) "222"
7) "333"
8) "444"

3.从左边追加数据:lpushx(与sting类型中的nx类似,只有当list存在时才会从左边依次追加元素)
127.0.0.1:6379> lpushx people daxiongmao beijixiong
(integer) 10
127.0.0.1:6379> lrange people 0 -1
 1) "beijixiong"
 2) "daxiongmao"
 3) "jiyangyang"
 4) "bayangyang"
 5) "chouyangyang"
 6) "meiyangyang"
 7) "111"
 8) "222"
 9) "333"
10) "444"

4.从右边追加数据:rpushx(与sting类型中的nx类似,只有当list存在时才会从左边依次追加元素)
127.0.0.1:6379> rpushx people 555 666
(integer) 12
127.0.0.1:6379> lrange people 0 -1
 1) "beijixiong"
 2) "daxiongmao"
 3) "jiyangyang"
 4) "bayangyang"
 5) "chouyangyang"
 6) "meiyangyang"
 7) "111"
 8) "222"
 9) "333"
10) "444"
11) "555"
12) "666"

5.在某个key的前面或者后面插入一个数据:linsert key before / after values new values
127.0.0.1:6379> linsert people before beijixiong 123
(integer) 13
127.0.0.1:6379> lrange people 0 -1
 1) "123"
 2) "beijixiong"
 3) "daxiongmao"
 4) "jiyangyang"
 5) "bayangyang"
 6) "chouyangyang"
 7) "meiyangyang"
 8) "111"
 9) "222"
10) "333"
11) "444"
12) "555"
13) "666"
127.0.0.1:6379> linsert people after beijixiong 123
(integer) 14
127.0.0.1:6379> lrange people 0 -1
 1) "123"
 2) "beijixiong"
 3) "123"
 4) "daxiongmao"
 5) "jiyangyang"
 6) "bayangyang"
 7) "chouyangyang"
 8) "meiyangyang"
 9) "111"
10) "222"
11) "333"
12) "444"
13) "555"
14) "666"

6.从左侧开始移除几个值:lrem(意思就是把列表里相同的几个字符串删除。也可以是一个一个的移除)
127.0.0.1:6379> lrange people 0 -1
 1) "123"
 2) "beijixiong"
 3) "123"
 4) "daxiongmao"
 5) "jiyangyang"
 6) "bayangyang"
 7) "chouyangyang"
 8) "meiyangyang"
 9) "111"
10) "222"
11) "333"
12) "444"
13) "555"
14) "666"
127.0.0.1:6379> lrem people 2 123
(integer) 2
127.0.0.1:6379> lrange people 0 -1
 1) "beijixiong"
 2) "daxiongmao"
 3) "jiyangyang"
 4) "bayangyang"
 5) "chouyangyang"
 6) "meiyangyang"
 7) "111"
 8) "222"
 9) "333"
10) "444"
11) "555"
12) "666"

7.根据下标修改数据:lset
127.0.0.1:6379> lrange people 0 -1
1) "daxiongmao"
2) "jiyangyang"
3) "bayangyang"
4) "111"
5) "222"
6) "333"
127.0.0.1:6379> lset people 2 000
OK
127.0.0.1:6379> lrange people 0 -1
1) "daxiongmao"
2) "jiyangyang"
3) "000"
4) "111"
5) "222"
6) "333"

8.根据下标截取数据:ltrim
127.0.0.1:6379> lrange people 0 -1
1) "daxiongmao"
2) "000"
3) "111"
127.0.0.1:6379> ltrim people 1 3
OK
127.0.0.1:6379> lrange people 0 -1
1) "000"
2) "111"

9.查询列表长度:llen
127.0.0.1:6379> lrange people 0 -1
1) "000"
2) "111"
127.0.0.1:6379> llen people 
(integer) 2

10.根据下标查询values:lindex
127.0.0.1:6379> lrange people 0 -1
1) "000"
2) "111"

127.0.0.1:6379> lindex people 0
"000"
127.0.0.1:6379> lindex people 1
"111"

11.消费pop
127.0.0.1:6379> lrange people 0 -1
1) "3333"
2) "2222"
3) "000"
4) "111"
5) "222"

##从左边开始消费
127.0.0.1:6379> lpop people
"3333"

##从右边开始消费
127.0.0.1:6379> rpop people
"222"

127.0.0.1:6379> lrange people 0 -1
1) "2222"
2) "000"
3) "111"

12.消费一个值加到另外一个新表里:rpoplpush +旧表+新表

(注意:这里是消费一个最右边的一个值并返回同时添加到新表的最左边)

127.0.0.1:6379> lrange newlist 0 -1
(empty array)
127.0.0.1:6379> rpoplpush people newlist
"111"
127.0.0.1:6379> lrange newlist 0 -1
1) "111"

13.监控:实时获取某一个值(我觉得消费更准确)
# 
列表中左侧查询元素,返回列表的key和左侧第一个元素,若所有查询的列表中都没有元素,则会阻塞等待至设置的timeout秒之后返回空,若在这期间,这些列表新增了元素,则会立刻消费并返回该元素。
127.0.0.1:6379> BLPOP people 1000
1) "people"
2) "12345"
127.0.0.1:6379> 

第二部分:redis数据类型之无序集合

Redis 的 Set 是 string 类型的无序集合。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)

1.增加/查看数据:sadd
##增加

127.0.0.1:6379> sadd people 111 222 333
(integer) 3

##查看
127.0.0.1:6379> smembers people
1) "111"
2) "222"
3) "333"

##删除
127.0.0.1:6379> smembers people
1) "111"
2) "222"
3) "333"
127.0.0.1:6379> srem people 111
(integer) 1
127.0.0.1:6379> smembers people
1) "222"
2) "333"

##移动
127.0.0.1:6379> smembers people
1) "222"
2) "333"
127.0.0.1:6379> smembers newpeople
1) "abc"
127.0.0.1:6379> smove people newpeople 222
(integer) 1
127.0.0.1:6379> smembers newpeople
1) "abc"
2) "222"

##返回集合中的个数
127.0.0.1:6379> scard people
(integer) 1
127.0.0.1:6379> scard newpeople
(integer) 2

##随机返回无序集合中n个数值
127.0.0.1:6379> srandmember newpeople 2
1) "abc"
2) "222"
127.0.0.1:6379> srandmember people 1
1) "333"


##判断是否值在这个集合里,存在返回1,不存在返回0
127.0.0.1:6379> smembers newpeople
1) "abc"
2) "222"

127.0.0.1:6379> sismember  newpeople abc
(integer) 1
127.0.0.1:6379> sismember  newpeople abc123
(integer) 0


##随机消费一个成员
127.0.0.1:6379> smembers newpeople
1) "abc"
2) "222"
127.0.0.1:6379> spop newpeople
"abc"
127.0.0.1:6379> smembers newpeople
1) "222"

# 返回多个集合中的交集
127.0.0.1:6379> sadd myseta 1 2 3 4 5
(integer) 5
127.0.0.1:6379> sadd mysetb 4 5 6 7 8
(integer) 5
127.0.0.1:6379> sadd mysetc 5 6 7 8 9
(integer) 5
127.0.0.1:6379> SINTER myseta mysetb  mysetc
1) "5"

# 返回多个集合的并集(去重)
127.0.0.1:6379> sadd myseta 1 2 3 4 5
(integer) 5
127.0.0.1:6379> sadd mysetb 4 5 6 7 8
(integer) 5
127.0.0.1:6379> sadd mysetc 5 6 7 8 9
(integer) 5
127.0.0.1:6379> SUNION myseta mysetb  mysetc
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
8) "8"
9) "9"

# 返回几个集合的差集(注意:取多个集合的差集,以最左边的为主集合,返回左集合中有而其他集合没有的成员。)
127.0.0.1:6379> SDIFF mysetc myseta  mysetb
1) "9"




第三部分:redis数据类型之有序列表

Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。

# 添加数据
格式: zadd +集合+分数(可以是整数也可以是小数)+数据
127.0.0.1:6379> ZADD myzety 1 one
(integer) 1
127.0.0.1:6379> ZADD myzety 2 two
(integer) 1
127.0.0.1:6379> ZADD myzety 20 twos
(integer) 1
127.0.0.1:6379> ZADD myzety 3 three
(integer) 1

# 查询数据
127.0.0.1:6379> ZRANGE myzety 0 -1
1) "one"
2) "two"
3) "three"
4) "twos"

#删除数据
127.0.0.1:6379> ZRANGE myzety 0 -1
1) "one"
2) "two"
3) "three"
4) "twos"
127.0.0.1:6379> ZREM myzety three
(integer) 1
127.0.0.1:6379> ZRANGE myzety 0 -1
1) "one"
2) "two"
3) "twos"

第四部分:key常用命令

##查看所有key
127.0.0.1:6379> keys *
 1) "city"
 2) "myset"
 3) "num1"
 4) "newpeople"
 5) "person"
 6) "zone"
 7) "people"
 8) "name"
 9) "name1"
10) "newlist"
11) "country"

##查看key的类型
127.0.0.1:6379> type country
string
127.0.0.1:6379> type person
hash

##随机返回一个key
127.0.0.1:6379> randomkey
"newlist"
127.0.0.1:6379> randomkey
"name1"
127.0.0.1:6379> randomkey
"name"
127.0.0.1:6379> randomkey
"name"

##删除一个key
127.0.0.1:6379> del key name1
(integer) 1

##判断一个key是否存在
127.0.0.1:6379> keys *
 1) "city"
 2) "myset"
 3) "num1"
 4) "newpeople"
 5) "person"
 6) "zone"
 7) "people"
 8) "name"
 9) "newlist"
10) "country"
127.0.0.1:6379> exists city
(integer) 1
127.0.0.1:6379> exists num1
(integer) 1
127.0.0.1:6379> exists num22
(integer) 0

##重命名一个key
127.0.0.1:6379> rename num1 num
OK

##秒和毫秒分别查询过期key的时间
127.0.0.1:6379> ttl city
(integer) -1
127.0.0.1:6379> pttl city
(integer) -1


第五部分:数据持久化

1.总体基本概念:
    edis持久化存储有两种持久化方案,RDB(Redis DataBase)和 AOF(Append-Only File)。
    RDB是将内存中的数据进行快照存储到磁盘
    AOF是将可回放的命令日志记录redis内的所有操作。
    它们各有特点也相互独立。Redis4之后支持RDB-AOF混合持久化的方式,结合了两者的优点,可以通过 aof-use-rdb-preamble 配置项可以打开混合开关

2.RDB持久化

默认有三种策略
第一种:save原理

image-20210501170538827

save会阻塞服务器进程,在进行save的过程中,服务器不能处理任何请求,而bgsave会通过一个子进程在后台处理rdb持久化。事实上save和bgsave调用的都是rdbSave函数,因此Redis不允许save和bgsave同时运行,这也是为了避免出现竞争导致rdb文件数据不准确。
第二种:bgsave
bgsave操作使用CopyOnWrite机制进行写时复制,是由一个子进程将内存中的最新数据遍历写入临时文件,此时父进程仍旧处理客户端的操作,当子进程操作完毕后再将该临时文件重命名为dump.rdb替换掉原来的dump.rdb文件,因此无论bgsave是否成功,dump.rdb都不会受到影响。

image-20210501170904704

第三种:配置文件触发
# 修改持久化文件存储的目录
[root@jenkins01 data]# vim /usr/local/redis/conf/redis.conf 
dir /usr/local/redis/data

# 开启数据持久化
[root@jenkins01 data]# vim /usr/local/redis/conf/redis.conf 
save 900 1
save 300 10
save 60 10000

# RDB 致命性的缺点
数据易丢失
1.RDB 优缺点
优点:
RDB是一种表示某个即时点的Redis数据的紧凑文件。RDB文件适合用于备份。例如,你可能想要每小时归档最近24小时的RDB文件,每天保存近30天的RDB快照。这允许你很容易的恢复不同版本的数据集以容灾。
RDB非常适合于灾难恢复,作为一个紧凑的单一文件,可以被传输到远程的数据中心。
RDB最大化了Redis的性能,因为Redis父进程持久化时唯一需要做的是启动(fork)一个子进程,由子进程完成所有剩余工作。父进程实例不需要执行像磁盘IO这样的操作。
RDB在重启保存了大数据集的实例时比AOF要快

缺点:
当你需要在Redis停止工作(例如停电)时最小化数据丢失,RDB可能不太好。你可以配置不同的保存点(save point)来保存RDB文件(例如,至少5分钟和对数据集100次写之后,但是你可以有多个保存点)。然而,你通常每隔5分钟或更久创建一个RDB快照,所以一旦Redis因为任何原因没有正确关闭而停止工作,你就得做好最近几分钟数据丢失的准备了。
RDB需要经常调用fork()子进程来持久化到磁盘。如果数据集很大的话,fork()比较耗时,结果就是,当数据集非常大并且CPU性能不够强大的话,Redis会停止服务客户端几毫秒甚至一秒。AOF也需要fork(),但是你可以调整多久频率重写日志而不会有损(trade-off)持久性(durability)。


总结一句:
优点:速度快,适合于用作备份,主从复制也是基于RDB持久化功能实现的。
缺点:会有数据丢失、导致服务停止几秒
2.快照持久化快照相关配置
在配置文件中配置触发的条件
#配置快照(rdb)促发规则,格式:save <seconds> <changes>
#save 900 1  900秒内至少有1个key被改变则做一次快照
#save 300 10  300秒内至少有300个key被改变则做一次快照
#save 60 10000  60秒内至少有10000个key被改变则做一次快照

#关闭该规则使用svae “”  或在命令行中 config set save “”

dbfilename  dump.rdb
#rdb持久化存储数据库文件名,默认为dump.rdb

stop-write-on-bgsave-error yes 
#yes代表当使用bgsave命令持久化出错时候停止写RDB快照文件,no表明忽略错误继续写文件。

rdbchecksum yes
#在写入文件和读取文件时是否开启rdb文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动。

dir "/etc/redis"
#数据文件存放目录,rdb快照文件和aof文件都会存放至该目录,请确保有写权限

rdbcompression yes
#是否开启RDB文件压缩,该功能可以节约磁盘空间、
3.save 和bgsave 对比

image-20210501181919870

3.AOF持久化默认策略
3.1AOF原理
1.客户端的请求写命令会被append追加到AOF缓冲区内;
2.AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
3.AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
4.Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
3.2 开启aof(开启了AOF之后,RDB就默认不使用了)
[root@jenkins01 data]# vi /usr/local/redis/conf/redis.conf 
将appendonly no 改为 yes
[root@jenkins01 data]# systemctl restart redis
[root@jenkins01 data]# ll
总用量 4
-rw-r--r-- 1 root root   0 5月   1 18:37 appendonly.aof

开启了AOF之后,RDB就默认不使用了。使用下面的配置开启AOF以及策略。(如果使用AOF,推荐选择always方式持久化,否则在高并发场景下,每秒钟会有几万甚至百万条请求,如果使用everysec的方式的话,万一服务器挂了那几万条数据就丢失了)。
3.3 配置文件
#开启AOF持久化
appendonly yes
 
#AOF文件名
appendfilename "appendonly.aof"
 
#AOF文件存储路径 与RDB是同一个参数
dir "/opt/app/redis6/data"
 
#AOF策略,一般都是选择第一种[always:每个命令都记录],[everysec:每秒记录一次],[no:看机器的心情高兴了就记录]
appendfsync always
#appendfsync everysec
# appendfsync no
 
 
#aof文件大小比起上次重写时的大小,增长100%(配置可以大于100%)时,触发重写。[假如上次重写后大小为10MB,当AOF文件达到20MB时也会再次触发重写,以此类推]
auto-aof-rewrite-percentage 100 
 
#aof文件大小超过64MB时,触发重写
auto-aof-rewrite-min-size 64mb 

#是否在后台写时同步单写,默认值no(表示需要同步).这里的后台写,表示后台正在重写文件(包括bgsave和bgrewriteaof.bgrewriteaof网上很多资料都没有涉及到。其实关掉bgsave之后,主要的即是aof重写文件了).no表示新的主进程的set操作会被阻塞掉,而yes表示新的主进程的set不会被阻塞,待整个后台写完成之后再将这部分set操作同步到aof文件中。但这可能会存在数据丢失的风险(机率很小),如果对性能有要求,可以设置为yes,仅在后台写时会异步处理命令.
no-appendfsync-on-rewrite no

# 指redis在恢复时,会忽略最后一条可能存在问题的指令。默认值yes。即在aof写入时,可能存在指令写错的问题(突然断电,写了一半),这种情况下,yes会log并继续,而no会直接恢复失败.
aof-load-truncated
3.4 AOF持久化策略
always       每次执行,都会持久化到AOF文件中     不丢失数据

everysec     每秒持久化一次                   减少IO

no           根据服务器性能持久化              全自动
3.5 AOF持久化选择

总计一句:高并发场景最好是always策略,巨大数据的话选择everysec

image-20210501190114964

3.6 AOF重写策略
AOF持久化机制记录每个写命令,当服务重启的时候会复现AOF文件中的所有命令,会消耗太多的资源且重启很慢。因此为了避免AOF文件中的写命令太多文件太大,Redis引入了AOF的重写机制来压缩AOF文件体积。AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。


image-20210501190439807

3.7 AOF重写触发机制
根据配置,AOF持久化触发机制如下:
1.aof_current_size > auto-aof-rewrite-min-size  ##触发重写的最小尺寸
2.(aof_current_size - aof_base_size) / aof_base_size > auto-aof-rewrite-percentage  ##

3.8 AOF重写流程

image-20210501191001418

image-20210501191114695

3.9 RDB与AOF抉择

image-20210501191214056

RDB的优点

1.压缩后的二进制文件,适用于备份、全量复制及灾难恢复。
RDB恢复数据性能优于AOF方式

RDB的缺点
1.无法做到实时持久化,每次都要创建子进程,频繁操作成本过高
2.保存后的二进制文件,不同版本直接存在兼容性问题

AOF的优点
1.以文本形式保存,易读
2.记录写操作保证数据不丢失

AOF的缺点
1.存储所有写操作命令,且文件为文本格式保存,未经压缩,文件体积高。
恢复数据时重放AOF中所有代码,恢复性能弱于RDB方式。

4.AOF与RDB混合

看了上面的RDB和AOF的介绍后,我们可以发现,使用RDB持久化会有数据丢失的风险,但是恢复速度快,而使用AOF持久化可以保证数据完整性,但恢复数据的时候会很慢。于是从Redis4之后新增了混合AOF和RDB的模式,先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB何AOF两部分恢复数据,即保证了数据完整性,又提高了恢复的性能。

开启混合模式后,每当bgrewriteaof命令之后会在AOF文件中以RDB格式写入当前最新的数据,之后的新的写操作继续以AOF的追加形式追加写命令。当redis重启的时候,加载 aof 文件进行恢复数据:先加载 rdb 的部分再加载剩余的 aof部分

开启混合持久化模式后,重写之后的aof文件里和rdb一样存储二进制的快照数据,继续往redis中进行写操作,后续操作在aof中仍然是以命令的方式追加。因此重写后aof文件由两部分组成,一部分是类似rdb的二进制快照,另一部分是追加的命令文本。

实验记录:

总计一句,就是我们开启 bgrewriteaof后,aof文件由类似旧的的数据由rdb的二进制快照,另外一种是aof的追加命令文本

# step: 进入Redis, 写入数据
[root@alvin-test-os redis]# redis-cli --raw
127.0.0.1:6379> set name alvin
OK
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> set add 上海
OK
127.0.0.1:6379> exit
# Step 2: 查看备份文件
[root@alvin-test-os redis]# ll data/
总用量 8
-rw-r--r--. 1 root root 121 11月 24 15:39 appendonly.aof
-rw-r--r--. 1 root root 116 11月 24 15:39 dump.rdb
[root@alvin-test-os redis]# cat data/appendonly.aof | grep add
add
[root@alvin-test-os redis]# cat data/appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$4
name
$5
alvin
*3
$3
set
$3
age
$2
18
*3
$3
set
$3
add
$6
上海
# Step 3: 启动备份
[root@alvin-test-os redis]# redis-cli --raw
127.0.0.1:6379> BGREWRITEAOF
Background append only file rewriting started
127.0.0.1:6379> exit
# Step 4: 查看配置文件发现AOF备份文件变成了二进制文件
[root@alvin-test-os redis]# cat data/appendonly.aof
REDIS0009�	redis-ver6.0.9�
�edis-bits�@�ctime��_used-mem��4
 aof-preamble���namealvinadd上海age���6����&[root@alvin-test-os redis]#
# Step 5: 再次写入文件
[root@alvin-test-os redis]# redis-cli --raw
127.0.0.1:6379> set company 上海老男孩
OK
127.0.0.1:6379> exit

# Step 6:再次查看备份文件发现被分成了两份,一份二进制,一份AOF备份
[root@alvin-test-os redis]# cat data/appendonly.aof
REDIS0009�	redis-ver6.0.9�
�edis-bits�@�ctime��_used-mem��4
 aof-preamble���namealvinadd上海age���6����&*2
$6
SELECT
$1
0
*3
$3
set
$7
company
$15
上海老男孩
[root@alvin-test-os redis]#
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值