玛卡巴卡的卡巴卡玛 发表于 2024-6-15 03:36:25

中级开辟的经验之谈(redis篇)

一、前言

在我读书的时候,我曾经很喜欢redis,听了相关的分享、看了相关的博客、读了相关的书、看了喜欢的源码,然后我写了一个总结:《这是全网最硬核redis总结,谁赞成,谁反对?》六万字大合集
https://img-blog.csdnimg.cn/direct/bfd88379fd53494d9f0a92fb87f15da2.png
现在,这篇文章大概五万多阅读,三千多收藏,三千多点赞。
但是,随着时间的推移,我徐徐的有点看不上这篇文章,重要是以为写的太多太全了,像流水账一样,好像什么都说了,又好像什么都没说。
以是,现在我有了一些开辟经验,有了一些心得体会,我预备写一个浓缩全是精华的分享,写一个初中高级开辟看了,都能有收获的分享。
本文重要是告诉你为什么我们使用redis,以及使用时可能遇到的问题。
下文括号中,都是我在公司讲课时,详细讲到的地方,非括号是文章正文。

二、简介

2.2 应用举例

1、延时队列(股票定投/)
2、布隆过滤器


[*] 缓存,解决当地缓存命中率太低的问题
(举例发布时读db超时挂掉)

三、性能好

3.1 数据结构

3.1.1 字典

字典,是一种用于保存键值对的抽象数据结构,在Redis中的应用相称广泛,比如Redis的数据库就是使用字典作为底层实现的,对数据库的增编削查等操纵也是构建在对字典的操纵之上。
特点:


[*] 使用的哈希算法:murmurhash,链表处理惩罚辩论
(哈希打单点变乱的案例分享)
(即使输入的键是有规律的,算法仍能给出一个很好的随机分布性,计算速度非常快,使用简单。因此在多个开源项目中得到应用,包罗libstdc、libmemcached、nginx、hadoop等。)


[*] rehash
(元素个数=数组长度扩容/bgsave时五倍,小于10%缩容 1)为ht分共同理空间。2)将ht中的数据rehash到ht上。3)释放ht,将ht设置为ht,ht创建空表,为下次做预备。)


[*]渐进rehash
https://img-blog.csdnimg.cn/direct/2708bef3bb2047878fc9916f53829d4b.png

(我们维持一个变量rehashidx,设置为0,代表rehash开始,然后开始rehash,在这期间,每个对字典的操纵,步伐都会把索引rehashidx上的数据移动到ht。
随着操纵不断实行,最终我们会完成rehash,设置rehashidx为-1.)
3.1.2 简单动态字符串(SDC)

Redis没有直接使用C语言传统的字符串表示,而是自己构建了名为简单动态字符串(simple dynamic string ,SDS)的抽象类型,并将SDS用作Redis的默认字符串表示。(除了保存数据库中的字符串值之外,SDS还被用作缓冲区,比方AOF的AOF缓冲区、客户端状态中的输入缓冲区等。)
struct sdshdr {

int len;//buf已使用字节数量

int free;//未使用的字节数量

char buf[];//用来保存字符串的字节数组

}; 数据结构如图表示:
https://img-blog.csdnimg.cn/direct/cfb7137e40dc4c97b1787251110b7c01.png
相对c的改进:
(1)常数复杂度获取字符串长度
(2)杜绝缓冲区溢出(这里是指相加的时候)
(3)减少修改字符串时带来的内存重分配次数(空间预分配、惰性空间释放)
(另有二进制安全之类的)
3.1.3 skiplist

(Redis只在两个地方用到了跳跃表,一个是实现有序集合,另一个是集群节点中用作内部数据结构。)
跳跃表是一种有序数据结构,在大多数环境下,跳跃表的效率可以和平衡树相媲美,并且因为跳跃表的实现比平衡树更为简单,以是有不少步伐使用跳跃表代替平衡树。
https://img-blog.csdnimg.cn/direct/9962f06e51d7452fa231985862899b27.png
数据结构如图表示:
https://img-blog.csdnimg.cn/direct/59dadddb8bd145d7891542b982d7a2de.png
Redis为何不用红黑树?良好性和特殊性
todo:演示两个数据结构的操纵

3.1.4 链表/整数集合/压缩列表



[*] 链表:带表头、双端无环、带长度记录、多态
https://img-blog.csdnimg.cn/direct/3d05504327ce4bde8077a92324d39ae5.png


[*] 整数集合:各个项在数组中从小到大有序分列,并且数组中不包含任何重复项。
https://img-blog.csdnimg.cn/direct/9b7822a172e243519068e6e70a40dd9b.png


[*] 压缩列表
占空间小,由一系列特殊编码的一连内存块构成的顺序型数据结构,为了节省空间,Previous_entry_length乃至大小可以厘革
https://img-blog.csdnimg.cn/direct/254be31fd68a45a4898b47af211726a5.png
todo:数据结构精讲\布隆过滤器\HyperLogLog等
3.2 对象

3.2.1 构成

对象体系,这个体系包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象五种类型的对象,每种对象都用到了至少一种前面介绍的数据结构。
https://img-blog.csdnimg.cn/direct/057a009a8d6044c79749ced4d42870cf.png
数据结构如图表示:
https://img-blog.csdnimg.cn/direct/d760bc89f0e34e45971362d627112b15.png
通过 encoding 属性来设定对象所使用的编码, 而不是为特定类型的对象关联一种固定的编码, 极大地提升了 Redis 的机动性和效率。
(这种头脑在别的语言/组件/项目中也有体现。随机应变,根据场景选择适用的方案才是正路。
究竟上redis新版参加了压缩表+链表的结构,也是基于这种头脑。)
https://img-blog.csdnimg.cn/direct/fd569266211f490a8ebcca1b017ccfef.png
3.2.2 内存回收/对象共享

1.Redis在自己的对象体系中构建了一个引用计数技能(并未采用可达性分析)实现内存回收机制。
2.通过引用计数技能,实现对象共享机制,通过让多个数据库键共享一个对象来节省内存。数据库中相同值对象越多,对象共享机制就能节省越多的内存。
(引用计数:(1)在创建一个新对象时,引用计数的值会被初始化为1;
(2)当对象被一个新步伐使用时,它的引用计数值会被增一;
(3)当对象不再被一个步伐使用时,它的引用计数值会被减一;
(4)当对象的引用计数值变为0时,对象所占用的内存会被释放;
引用简单,可达性(图论,可达即有用)必要遍历。
循环引用的问题,可能是简便的头脑和对体系的自大吧)
3.3 单机数据库实现

3.3.1 访问框架

todo:动态链接库和网络框架
3.3.2 线程模型

我们之前所说的Redis 是单线程,重要是指 对外提供键值存储服务的重要流程是单线程的,也就是网络 IO 和键值对读写。别的功能如持久化、异步删除、集群数据同步等很早就是多线程。
那么Redis早先并不是多线程模型,重要缘故起因:没必要


[*] 性能瓶颈不在 CPU
[*] 单线程模型,可维护性更高,开辟/调试/维护的本钱更低
[*] 单线程模型制止了线程间切换带来的性能开销
[*] 在单线程中使用多路复用 I/O技能也能提升Redis的I/O使用率(固然本质还是阻塞的)
Linux多路复用技能,就是多个进程的IO可以注册到同一个管道上,这个管道会统一和内核进行交互。当管道中的某一个哀求必要的数据预备好之后,进程再把对应的数据拷贝到用户空间中。
(科普:多线程的目的,就是通过并发的方式提升I/O使用率和CPU使用率。)
Redis 将全部数据放在内存中,内存的响应时长约莫为 100 纳秒,对于小数据包,Redis 服务器可以处理惩罚 80,000 到 100,000 QPS。
todo:redis6.0
(redis6.0还是真香了。顺序、分身、监听。在select、poll、epoll这些调用会阻塞,收发消息不会阻塞。挖坑下次填)
四、高可靠

4.1 单机可靠

4.1.1 空间管理

机制一、设置最大空间:Redis 提供参数 maxmemory 设置 Redis 最大使用内存。
机制二、设置生存时间:可以给键设置生存时间(UNIX时间戳),到时间自动删除这个键。
redisdb结构的expires字典保存了全部的键的逾期时间,我们称这个字典为逾期字典。
机制三、逾期键删除计谋:
1)定时删除:创建一个定时器,到时间立刻实行删除操纵(对内存友好,因为能保证逾期了立马删除,但是对cpu不友好)
2)惰性删除:键逾期不管,每次获取键时查抄是否逾期,逾期就删除(对cpu友好,但是只有在使用的时候才可能删除,对内存不友好)
3)定期删除:隔一段时间查抄一次(详细算法决定查抄多少删多少,必要合理设置)
机制四、镌汰计谋
当Redis占用内存超出最大限定 (maxmemory) 时,采用可设置的一些计谋 (maxmemory-policy) ,让Redis镌汰一些数据:
•volatile-random: 在设置了逾期时间的key中,随机选择一些key,将其镌汰;
•allkeys-1Lru: 在全部的key中,选择最少使用的key (LRU) ,将其镌汰;
•allkeys-random: 在全部的key中,随机选择一些key,将其镌汰;
4.1.2 持久化

4.1.2.1 RDB(Redis DataBase)

通过天生数据集的时间点快照(point-in-time snapshot)来实现持久化。


[*] 自动触发:
自动触发使用 save 相关设置触发,比如 “save m n”,表示在 m 秒内数据库存在 n 次修改时,自动触发 BGSAVE 。
https://img-blog.csdnimg.cn/direct/e92c1f043197462897a3852eb67dfd5d.png



[*] 手动触发:
SAVE:实行一个同步保存操纵,将当前实例的全部数据快照以 RDB 文件的形式保存到磁盘中。
BGSAVE:用于在背景异步保存当前数据库的数据到磁盘。
下令savebgsveIO类型同步异步是否阻塞是是(fork内)复杂度O(n)O(n)客户端是否阻塞阻塞客户端下令不阻塞客户端下令是否消耗资源不额外消耗资源必要fork消耗资源
4.1.2.2 AOF(Append-only file)

AOF 持久化是通过保存 Redis 服务器所实行的写下令来记录数据库状态,重启时再重新实行 AOF 文件中的下令以完成数据恢复。AOF 的重要作用是解决了数据持久化的实时性,目前已经是 Redis 持久化的主流方式。
todo:自动重写

rdb优点:RDB 是一个非常紧凑(compact)的文件,它保存了 Redis 在某个时间点上的数据集。 这种文件非常适合用于进行备份: 比如说,你可以在迩来的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 如许的话,即使遇上问题,也可以随时将数据集还原到不同的版本。
RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中央。
RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork出一个子进程,然后这个子进程就会处理惩罚接下来的全部保存工作,父进程无须实行任何磁盘 I/O 操纵。
RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
缺点:发生故障时会丢失数据。固然 Redis 答应你设置不同的保存点(save point)来控制保存 RDB 文件的频率, 但是, 因为RDB 文件必要保存整个数据集的状态, 以是它并不是一个轻松的操纵。 因此你可能会至少 5 分钟才保存一次 RDB 文件。 在这种环境下, 一旦发生故障停机, 你就可能会丢失好几分钟的数据。
每次保存 RDB 的时候,Redis 都要 fork出一个子进程,并由子进程来进行实际的持久化工作。 在数据集比力庞大时, fork() 可能会非常耗时,造成服务器在某某毫秒内停止处理惩罚客户端; 如果数据集非常巨大,并且 CPU 时间非常紧张的话,那么这种停止时间乃至可能会长达整整一秒。
优点:


[*] 使用 AOF 持久化会让 Redis 变得非常耐久,可以设置多种计谋,发生故障停机,也最多只会丢失一秒钟的数据
[*] AOF 文件是一个只进行追加操纵的日志文件(append only log), 因此对 AOF 文件的写入不必要进行 seek , 即使日志因为某些缘故起因而包含了未写入完整的下令,也可以使用工具进行修复
[*] Redis 可以在 AOF 文件体积变得过大时,自动地在背景对 AOF 进行重写。
[*] AOF 文件有序地保存了对数据库实行的全部写入操纵, (如果你不小心实行了 FLUSHALL 下令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 下令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 实行之前的状态。)
缺点:


[*] 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
[*] 根据所使用的 fsync 计谋,AOF 的速度可能会慢于 RDB 。 在一样平常环境下, 每秒fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此
[*] AOF 在过去曾经发生过如许的 bug : 因为个别下令的缘故起因,导致 AOF 文件在重新载入时,无法将数据集恢复成保存时的原样
todo:RDB/AOF的详细介绍
todo:变乱
4.2 多机可靠

todo:多机可靠

4.2.1主从


4.2.2 哨兵


可扩展

todo:
一些坑

比如说,有做缓存的,有做数据库的,也有用做分布式锁的。不外,他们遇见的“坑”,总体来说集中在四个方面:
CPU 使用上的“坑”,比方数据结构的复杂度、跨 CPU 核的访问;
内存使用上的“坑”,比方主从同步和 AOF 的内存竞争;
存储持久化上的“坑”,比方在 SSD 上做快照的性能抖动;
网络通信上的“坑”,比方多实例时的异常网络丢包。
附录:参考资料

USFCA算法图像模仿器
压缩列表参考
小灰:什么是跳表
更严谨的跳表文章
知乎:redis为什么这么快
在线模仿redis
Redis 下令参考
《Redis设计与实现》
《Redis实战》
《Redis入门指南(第2版)》

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 中级开辟的经验之谈(redis篇)