关于redis:redis-系列总结篇

4次阅读

共计 3405 个字符,预计需要花费 9 分钟才能阅读完成。

Redis 总体介绍

Redis 是 key-value 型的 memory 缓存中间件,置信大部分程序员都在我的项目中应用过它。咱们也能够利用 memory 来实现缓存,只是应用 redis 的话,能够将缓存性能对立到一个组件里,不便后续重用拓展。

在底层上,redis 应用了 IO 多路复用技术,像 select、epoll 等。能较好的保障吞吐量。而且 redis 采纳了单线程解决申请,防止了线程切换和锁竞争锁带来的额定耗费。

加上 redis 自身也对一些数据结构进行了优化设计,所以 redis 的性能十分好,官网给出的测试报告是单机能够反对约 10w/s 的 QPS。

Redis 通信协议

redis 是基于 tcp 长连贯的 C/S 架构,采纳的是文本序列化协定,并且和 http 一样,也是一个申请一个响应,客户端接到响应后再持续申请。

当然,也能够将屡次申请发送过来,而后一次响应回所有执行后果,这就是所谓的管道 pipeline 技术。

redis 的文本序列化协定比较简单,通过一些标准格局去解析文本,大略如下:

  • \r\n 示意解析完结
  • 简略字符串,以“+”结尾
  • 谬误 Errors,以“-”结尾
  • 整数类型,以“:”结尾
  • 大字符串类型,以“$”结尾
  • 数组类型,以“*”结尾

例如,客户端向服务器发送命令:

SET key value

将被解析为:

*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n

下面的命令能够看成:

*< 参数数量 > CR LF

$< 参数 1 的字节数量 > CR LF
< 参数 1 的数据 > CR LF
...
$< 参数 N 的字节数量 > CR LF
< 参数 N 的数据 > CR LF

而服务器的回复则有很多类型,个别由响应数据的第一个字节决定:

状态回复(status reply)的第一个字节是 "+"

谬误回复(error reply)的第一个字节是 "-"

整数回复(integer reply)的第一个字节是 ":"

批量回复(bulk reply)的第一个字节是 "$"

多条批量回复(multi bulk reply)的第一个字节是 "*"

例如,响应回来的状态回复如下:

+OK

redis 的数据结构

为了让开发者能更好的应用缓存,redis 反对了 5 种数据类型。底层是由 6 种数据结构组成的。

5 种数据类型

字符串:字符串类型是 redis 里最根底的数据类型,像 set name "hello" 操作后,在 get name 时返回的就是字符串,而且还反对了对位的操作。个别一个键能存储 512MB 的值。

hash:哈希类型次要是用来存储对象的,个别咱们如果有一整个对象要存储,外面蕴含了多个字段,则能够应用 hash 来存储,因为 redis 提供了对这些字段的提取和设置,缩小了开发者对它的二次解决,比方序列化反序列化操作。

list:一个简略的字符串列表,它容许咱们从两端进行 push,pop 操作, 还反对肯定范畴的列表元素。能够看成是双向列表。

set:汇合是一个不反复值的组合,为咱们提供了交加、并集、差集等操作,像找出独特好友这种需要就能够应用汇合操作了。

sorted set:有序汇合,在下面汇合的根底上提供了排序功能,通过一个 score 属性来进行排序。

6 种底层数据结构

下面的数据类型实际上在 redis 底层是有对应的数据结构来实现的,都是 redis 通过精心设计的,能很好的进步解决效率。

简略动静字符串:redis 是应用 C 语言写的,而 C 语言里的字符串类型比拟原始,比方应用 \0 作为字符结束符。所以 redis 实现了属于本人的字符串类型,比方字符串长度,事后分配内存,动静拓展等特点,也保障了解决安全性。

链表:一个双端链表,有 prev,next 指针去获取前后节点,带有 len 属性,能保留多种类型的值。

字典 :通过哈希算法来实现 key-value 的映射操作,采纳 链地址法 解决了 hash 抵触,个别工夫复杂度能达到 O(1)。

跳跃表:一个多层有序链表,每一层都是对上面一层的有序提取,能升高搜寻次数,有点像有序二叉树的搜寻一样。

整数汇合:一个有序的整数汇合,不会有反复元素。

压缩列表(ziplist):通过非凡编码的一块间断内存,能无效的节俭内存。

疾速列表:将 ziplist 组织为了一个双向链表,因为 ziplist 的外部连续性,能升高链表的内存碎片问题,进步内存利用率。

redis 的淘汰策略

redis 的淘汰策略次要是 LRU 淘汰、TTL 淘汰和随机淘汰这三种机制。

  • LRU 淘汰:最近起码应用的淘汰掉
  • TTL 淘汰:越早过期的越先淘汰掉。
  • 随机淘汰:采纳随机算法淘汰掉。

因为 redis 能够对键设置过期工夫,也能够不设置,所以淘汰策略还得再细分:

  • volatile-lru:针对设置了过期工夫的 key 执行 LRU 淘汰策略,没有设置过期工夫的不会被淘汰。
  • volatile-ttl:只针对设置了过期工夫的 key 执行 TTL 淘汰。
  • volatile-random:只针对设置了过期工夫的 key 执行随机淘汰。
  • allkeys-lru:针对所有键进行 LRU 淘汰策略
  • allkeys-random:针对所有键进行随机淘汰策略
  • no-enviction:不执行淘汰策略,如果有写入操作,则报错;读申请能够持续进行。

在 Redis 的配置文件 redis.conf 里咱们能够进行淘汰策略的设置:

# 数据达到多大后执行淘汰策略
maxmemory 300mb

# 淘汰策略的设置
maxmemory-policy volatile-lru

Redis 应用场景

Redis 的应用场景有很多,最罕用的莫过于数据缓存了。但因为它提供了多种数据类型,因而咱们还能够进行其余场景的开发,比方:

  • 排行榜:后面提到过有序汇合(sorted set),因为每次写入都会进行排序,而且不含反复值,所以咱们能够将用户的惟一标识,比方 userId 作为 key,分数作为 score,而后就能够进行 ZADD 操作,以失去排行榜。
  • 签到:签到往往只有 2 种状态,已签到和未签到。这就跟 0 和 1 一样,所以 redis 的 setbitgetbit 这种对位的操作就适宜签到场景。
  • 计数:redis 是单线程操作,这种计数性能,比方点赞数、粉丝数的操作能够交给 redis 以防止并发竞争问题。当然,也得思考长久化问题。

对于分布式锁

有的时候咱们可能会应用 redis 作为分布式锁的辅助应用,通过对 redis 操作响应以判断以后是否能够获取到锁。

不过这样的解决方案会有单节点的瓶颈,如果 redis 宕机了,就会导致锁的不可用。

有的敌人可能会说 redis 也有它的高可用计划。但实际上 redis 的高可用计划还是不适宜分布式锁的利用,会有多节点同时获取到锁的危险。

如果真的须要比拟谨严的分布式锁,还是得应用 zookeeperetcd等分布式协调计划,能保障强一致性。

Redis 应用留神点

缓存雪崩和穿透

Redis 通过缓存冗余的数据,为咱们的程序提供了高性能的保障。但须要留神的是一旦缓存生效,那么就会有大量的申请过去,压垮零碎,这就是缓存雪崩。

除了缓存雪崩,还有缓存穿透的可能。比方每次拜访不一样的数据,则申请还是会落到前方。

为了避免缓存雪崩,咱们能够对申请做管制,比方退出到音讯队列,缓缓消化它;又或者间接开启限流性能,将流量管制在正当的范畴内。

而针对缓存穿透,咱们能够建设黑白名单,将一些歹意申请拎进去,而后间接回绝掉。如果是失常的申请,那能够将筛选进去的后果也临时缓存起来,即便失去的值是 NULL 值。

数据并发问题

因为 Redis 是以组件模式存在,所以实际上咱们的程序通信能够认为是分布式的了,也就是会有缓存和后端数据一致性的问题。

常见的做法是在有新数据到来时,将缓存 key 删除掉,期待下次的查问从新填补上缓存。

之所以在更新数据时不让 Redis 也做更新动作,是为了避免多个更新动作一起产生,可能因为网络起因,导致后更新的比后面更新的先一步达到 Redis,这样就会跟原来的流程不一样了。所以只采取了删除动作,不做其余。

不过,就算是删除 key 这种计划也有肯定概率跟下面的状况一样,真的要谨严的话,个别会设置定时过期工夫,让数据最多在这段时间不统一。

总结

Redis 的应用很简略,但实际上波及的常识挺多的,特地须要留神它的并发数据统一问题。只有理解 Redis 越多,咱们能力更好的把握它,更多细节大伙能够自行深刻理解,心愿本文能帮到大家,谢谢!


感兴趣的敌人能够搜一搜公众号「阅新技术」,关注更多的推送文章。
能够的话,就顺便点个赞、留个言、分享下,感激各位反对!
阅新技术,浏览更多的新常识。

正文完
 0