redis原理和使用-基本特性

上一篇blog中介绍了redis的分布式安装和集群方式,本文将介绍redis支持的数据结构,持久化方式和数据过期策略。


redis支持的数据结构

Redis支持的数据结构类型有:String(字符串),List(列表),Set(集合),Hash(哈希),Zset(有序集合)。

各种数据类型的操作如下:

增加删除查询返回长度
Stringset或msetdelget-
Listlpush, rpushlpop, rpoplrangellen
Hashhset, hmsethdelhget, hkeys, hvals, hgetallhlen
Setsaddsrem, spopsmembers/sismemberscard
Zsetzaddzremzrangezcard

下面是一个简单的例子:
在这里插入图片描述

跳表

跳表是redis的一个核心组件,同时也被广泛地运用到了各种缓存的实现中。zset的底层就是通过跳表来实现的。跳表是一种有序的数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。

跳表的演进

跳表是在有序链表的基础上进行演进的。对于有序链表,查找某个元素的时候,是从头结点往后一个一个地查找,时间复杂度为O(n)。如下图有序链表:
在这里插入图片描述
既然是有序的,那有没有什么方法可以实现有序链表的二分查找呢?方法就是使用跳跃链表。把一些节点从有序表中提取出来,缓存一级索引,就组成了下面这样的结构:
在这里插入图片描述
如果要查找元素11,就从L1层的1开始,向右到6,再向右发现是15,比11大,此路不通。于是跳到L0层,从下面的6往右走,到7,再到11。同样地,一级索引也可以往上再提取一层,组成二级索引,如下:
在这里插入图片描述
如果要查找元素17,则只需要经过6、15、17这几个元素就可以找到17了。

总结:跳表在有序链表的基础上,通过空间换取时间,提升了查询效率。查询的时间复杂度为O(logN)

假设每两个元素往上提取一个元素,形成一个标准跳表,如下所示:
在这里插入图片描述
设层级为k,则所需的额外存储空间为:2^1+2^2+...+2^k = 2^(k+1) - 1,其中L1的元素个数为2^k = n/2,则2^(k+1) = n,所需的额外存储空间为n-1,所以空间复杂度为O(n)。

跳表的插入和删除

假如要向上面的跳表中添加一个元素8。首先,随机选取一个层数,决定8要占据的层数,例如L1。然后找到8这个元素在下面两层的前置节点,通过链表的插入操作将其插到后面即可,如下图所示:
在这里插入图片描述
删除也是类似的,先找到各层中包含元素x的节点,然后使用标准的链表删除元素即可,如下所示:
在这里插入图片描述

Redis中zset为什么用跳表,而不是用红黑树来实现呢?

  • 有序集合的主要操作包括:(1)插入元素;(2)删除元素;(3)查找元素;(4)有序输出所有元素;(5)查找区间内的所有元素
  • 在这5个操作中,前4个红黑树都可以完成,且时间复杂度跟跳表一致,但最后一项,红黑树的效率就不如跳表高了。此外,相对红黑树来说,跳表实现容易且易读。

Redis持久化

Redis支持RDB和AOF两种持久化机制。
众所周知,redis是一个内存数据库。而内存中的数据会在机器宕机或者进程退出时丢失。有了持久化机制之后,就可以在重启时利用之前持久化的文件进行数据恢复。

RDB持久化

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。它是Redis默认采用的持久化方式。快照文件默认存放在当前执行redis服务的根目录的dump.rdb中。
当redis服务关闭后,内存数据清空。此时再开启redis,就会从dump.rdb持久化文件中恢复数据。如果将dump.rdb删除,重启redis时就无法通过持久化数据文件恢复数据,redis里的数据就会为空。

RDB的相关配置在redis配置文件redis.conf中。在标识SNAPSHOTTING注释的模块下,可以通过修改该配置文件设置触发快照生成的情况。默认的配置为:当900秒内有1个key被修改,或者300秒内有10个key被修改,或者60秒内有10000个key被修改,会触发快照的生成。如下图所示:
在这里插入图片描述
如果不希望将数据同步到快照文件中,可以设置为save “”。此外,当执行save,bgsave,flushall,shutdown命令时,也会生成快照文件。

Redis生成RDB快照文件的过程为:

  • Fork一个子进程作为主进程的副本。主进程负责接收并处理客户端请求,子进程负责将内存中的数据写入磁盘中的临时文件。待持久化过程结束后,会用此临时文件替换旧的dump.rdb,到此,一次快照生成完毕。

根据RDB持久化机制可知,当一次快照生成完毕而下一次尚未触发时,此时机器发生故障导致宕机,则最后的增量数据就会丢失。

AOF持久化

AOF即append only file,redis将每一个收到的写命令(包括flushall命令)都通过write函数追加到文件appendonly.aof中。

默认情况下redis并未开启AOF,需要将配置文件中的appendonly no项修改为appendonly yes,同时关闭RDB。appendfsync配置项指定了AOF持久化的时机,默认采用appendfsync everysec,表示每秒钟同步。

Redis还对aof文件进行了优化,主要是指当aof文件大小超过所设定的阈值时,会将aof文件进行重写,只保留可以恢复数据的最小指令集(例如删除已过期的数据的相关指令),以压缩文件大小。当然,也可以通过命令bgrewriteaof进行手动压缩。默认的自动重写触发的配置如下:
在这里插入图片描述

混合持久化

实际上,可以将RDB和AOF混合使用。将RDB文件的内容和增量的AOF日志文件存放在一起。这里的AOF日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量AOF日志。

RDB和AOF对比

上文说过,RDB的问题在于:当机器宕机时最后一次快照生成之后的增量数据可能会丢失。而AOF的缺点是:相比于RDB,AOF文件的体积更大。在恢复大数据集时,AOF的恢复速度比RDB慢。另外,根据同步策略的不同,AOF在运行效率上往往慢于RDB,除非使用禁用同步策略。

Redis键过期删除

Redis提供了3中针对过期键值的删除策略。

  • 定时删除(主动)
    在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时删除这个键。
  • 惰性删除(被动)
    查询键的时候判断有没有过期,如果过期则删除,没过期则返回。
  • 定期删除(主动)
    每隔一段时间对数据库进行一次检查,删除过期键。

显然,通过定时器的主动删除对内存是友好的,一旦数据过期则删除,但是对cpu是不友好的;惰性删除对内存不够友好,即使数据过期了,在没有查询的时候任然会存在,占用着内存;定期删除则是两种策略的折中方案。通常,将定期删除和惰性删除结合起来使用。通过定期删除来回收一定的内存空间,然后通过惰性删除来回收被查询的过期键所占用的内存空间。

Redis过期键对持久化和主从同步的影响

在redis持久化过程中,RDB模式下过期键不会被写到持久化数据文件中。
Redis通过RDB持久化文件进行数据恢复时,如果是以主服务器模式运行的,则不会载入已经过期的键,否则会载入。
主服务器删除过期键时,会向所有从服务器发一个DEL命令,告知从服务器删除过期键。

Redis Big Key

在redis中,一个字符串最大512M,一个二级数据结构(hash,list,set,zset)可以存大约40亿(2^32 - 1)个元素。

但实际上不会这么做。一旦value值过大,就会出现Big Key问题。对于string类型,超过10kb就是big key,对于其他类型,元素个数超过10240个认为是big key。

big key存在的问题

1.超时堵塞

操作big key通常比较耗时。由于Redis单线程的特性,这个长耗时就可能导致redis阻塞,进而造成客户端阻塞或着引起故障切换。

2.网络拥塞

big key意味着在网络上传输时产生的网络流量较大。假如每个big key为1mb,客户端每秒访问量为1000,则网络流量是1000mb/s。对于小一点的网卡,直接就会堵住。

3.内存使用不均匀

假设在redis集群中,key是均匀分布的。理论上使用的内存空间也应该是均匀的。而big key所在的节点会使用较大的内存空间,也就是内存使用不均匀。

4.过期删除

如果设置了big key的过期时间,则当其过期时会被删除。big key的删除耗时较长,存在阻塞redis的可能性(Redis4.0有异步删除机制,效果更好)。
而且这个删除不会出现在主节点的慢查中(因为不是客户端产生的),但可以从latency命令中获取或者从slave节点慢查中获取。

5.迁移困难

当需要对big key进行迁移时(如redis cluster的slot迁移),可能会迁移失败,而且可能会阻塞redis。

处理方式

对big key进行拆分。比如某个list是个big key,可以考虑分桶。例如:list中的元素是int,可以按照后两位数组来拆分,分成00~99这100个桶。

如果不能拆分,可以考虑能否使用其他组件存储。必须要用redis存的话,可以考虑迁移出集群,采用主备的架构来存储。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值