redis
2020-10-20 21:17:11 0 举报
AI智能生成
Redis核心技术
作者其他创作
大纲/内容
master-slave架构
主从同步相关内容
1、复制的完整流程
(1)slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始
master host和ip是从哪儿来的,redis.conf里面的slaveof配置的
(2)slave node内部有个定时任务,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接
(3)slave node发送ping命令给master node
(4)口令认证,如果master设置了requirepass,那么salve node必须发送masterauth的口令过去进行认证
(5)master node第一次执行全量复制,将所有数据发给slave node
(6)master node后续持续将写命令,异步复制给slave node
2、数据同步相关的核心机制
指的就是第一次slave连接msater的时候,执行的全量复制,那个过程里面你的一些细节的机制
(1)master和slave都会维护一个offset
master会在自身不断累加offset,slave也会在自身不断累加offset
slave每秒都会上报自己的offset给master,同时master也会保存每个slave的offset
这个倒不是说特定就用在全量复制的,主要是master和slave都要知道各自的数据的offset,才能知道互相之间的数据不一致的情况
(2)backlog
master node有一个backlog,默认是1MB大小
master node给slave node复制数据时,也会将数据在backlog中同步写一份
backlog主要是用来做全量复制中断候的增量复制的
(3)master run id
info server,可以看到master run id
如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id区分,run id不同就做全量复制
如果需要不更改run id重启redis,可以使用redis-cli debug reload命令
(4)psync
从节点使用psync从master node进行复制,psync runid offset
master node会根据自身的情况返回响应信息,可能是FULLRESYNC runid offset触发全量复制,可能是CONTINUE触发增量复制
3、全量复制
(1)master执行bgsave,在本地生成一份rdb快照文件
(2)master node将rdb快照文件发送给salve node,如果rdb复制时间超过60秒(repl-timeout),那么slave node就会认为复制失败,可以适当调节大这个参数
(3)对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s
(4)master node在生成rdb时,会将所有新的写命令缓存在内存中,在salve node保存了rdb之后,再将新的写命令复制给salve node
(5)client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败
(6)slave node接收到rdb之后,清空自己的旧数据,然后重新加载rdb到自己的内存中,同时基于旧的数据版本对外提供服务
(7)如果slave node开启了AOF,那么会立即执行BGREWRITEAOF,重写AOF
rdb生成、rdb通过网络拷贝、slave旧数据的清理、slave aof rewrite,很耗费时间
如果复制的数据量在4G~6G之间,那么很可能全量复制时间消耗到1分半到2分钟
4、增量复制
(1)如果全量复制过程中,master-slave网络连接断掉,那么salve重新连接master时,会触发增量复制
(2)master直接从自己的backlog中获取部分丢失的数据,发送给slave node,默认backlog就是1MB
(3)msater就是根据slave发送的psync中的offset来从backlog中获取数据的
5、heartbeat
主从节点互相都会发送heartbeat信息
master默认每隔10秒发送一次heartbeat,salve node每隔1秒发送一个heartbeat
6、异步复制
master每次接收到写命令之后,现在内部写入数据,然后异步发送给slave node
1、复制的完整流程
(1)slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始
master host和ip是从哪儿来的,redis.conf里面的slaveof配置的
(2)slave node内部有个定时任务,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接
(3)slave node发送ping命令给master node
(4)口令认证,如果master设置了requirepass,那么salve node必须发送masterauth的口令过去进行认证
(5)master node第一次执行全量复制,将所有数据发给slave node
(6)master node后续持续将写命令,异步复制给slave node
2、数据同步相关的核心机制
指的就是第一次slave连接msater的时候,执行的全量复制,那个过程里面你的一些细节的机制
(1)master和slave都会维护一个offset
master会在自身不断累加offset,slave也会在自身不断累加offset
slave每秒都会上报自己的offset给master,同时master也会保存每个slave的offset
这个倒不是说特定就用在全量复制的,主要是master和slave都要知道各自的数据的offset,才能知道互相之间的数据不一致的情况
(2)backlog
master node有一个backlog,默认是1MB大小
master node给slave node复制数据时,也会将数据在backlog中同步写一份
backlog主要是用来做全量复制中断候的增量复制的
(3)master run id
info server,可以看到master run id
如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id区分,run id不同就做全量复制
如果需要不更改run id重启redis,可以使用redis-cli debug reload命令
(4)psync
从节点使用psync从master node进行复制,psync runid offset
master node会根据自身的情况返回响应信息,可能是FULLRESYNC runid offset触发全量复制,可能是CONTINUE触发增量复制
3、全量复制
(1)master执行bgsave,在本地生成一份rdb快照文件
(2)master node将rdb快照文件发送给salve node,如果rdb复制时间超过60秒(repl-timeout),那么slave node就会认为复制失败,可以适当调节大这个参数
(3)对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s
(4)master node在生成rdb时,会将所有新的写命令缓存在内存中,在salve node保存了rdb之后,再将新的写命令复制给salve node
(5)client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败
(6)slave node接收到rdb之后,清空自己的旧数据,然后重新加载rdb到自己的内存中,同时基于旧的数据版本对外提供服务
(7)如果slave node开启了AOF,那么会立即执行BGREWRITEAOF,重写AOF
rdb生成、rdb通过网络拷贝、slave旧数据的清理、slave aof rewrite,很耗费时间
如果复制的数据量在4G~6G之间,那么很可能全量复制时间消耗到1分半到2分钟
4、增量复制
(1)如果全量复制过程中,master-slave网络连接断掉,那么salve重新连接master时,会触发增量复制
(2)master直接从自己的backlog中获取部分丢失的数据,发送给slave node,默认backlog就是1MB
(3)msater就是根据slave发送的psync中的offset来从backlog中获取数据的
5、heartbeat
主从节点互相都会发送heartbeat信息
master默认每隔10秒发送一次heartbeat,salve node每隔1秒发送一个heartbeat
6、异步复制
master每次接收到写命令之后,现在内部写入数据,然后异步发送给slave node
单线程问题
redis为什么使用单线程
- 多线程切换的开销
- 多线程访问共享资源时为了保证数据的一致性需要做加锁限制。例如两个线程对一个List操作,一个线程做入队Lpush,一个线程做Lpop为了数据正确必须串行化执行.带来额外的开销
redis单线程为什么快?
- 操作读取、写入都是在内存中完成的
- 多路复用机制
redis是单线程的吗?
redis并不是严格意义上的单线程。网络Io和数据的读写是由单线程来完成的,集群数据同步、数据持久化。数据异步删除是由额外线程来完成的。
多路复用
Linux中的IO多路复用机制就是指,一个线程可以处理多个IO流操作。也就是select/epoll
该机制允许内核中,同时存在多个监听套接字和已连接套接字
为了在请求到达时能通知到 Redis 线程,select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数。
该机制允许内核中,同时存在多个监听套接字和已连接套接字
为了在请求到达时能通知到 Redis 线程,select/epoll 提供了基于事件的回调机制,即针对不同事件的发生,调用相应的处理函数。
Cluster集群
哈希槽 Hash Solt
一个集群分片总共有16384个哈希槽,每个数据的KEY会根据CRC16算法得到一个16bit的值,然后对16384取模得到一个0~16383的值,来确定数据存放在哪个哈希槽中
节点分配哈希槽
例如有三个节点的集群,我们可以根据机器配置的不同分配出5个哈希槽
redis-cli -h 172.16.19.3 –p 6379 cluster addslots 0,1
redis-cli -h 172.16.19.4 –p 6379 cluster addslots 2,3
redis-cli -h 172.16.19.5 –p 6379 cluster addslots 4
redis-cli -h 172.16.19.3 –p 6379 cluster addslots 0,1
redis-cli -h 172.16.19.4 –p 6379 cluster addslots 2,3
redis-cli -h 172.16.19.5 –p 6379 cluster addslots 4
灾备
RDB
策略
默认
- save 900 1 十五分钟有一条写入即生成一次rdb
- save 300 10 五分钟有十条写入即生成一次rdb
- save 60 10000 一分钟有一万次写入生成一次rbd
生成RDB文件命令
- Save 在主线程中执行,会阻塞线程
- bgsave 创建一个子线程,专门用于写RDB文件。避免主线程的阻塞,这也是默认配置
写时复制COW(Copy on write)
bgsave是主线程fork出一个子线程去生成快照,为了在生成快照时主线程收到一个修改的操作不应该生成快照的准确性会生成一个数据副本,bgsave会把这个副本数据写入RDB文件
潜在风险
如果写的操作很多,在进行RDB时,由于写时复制会分配新的内存空间这个可能会导致OOM,如果主机开启了Swap机制有一部分数据可以被换到磁盘上性能也是会急剧下降的
AOF
策略
默认关闭
- appendonly 设置为yes 打开
- always:每次写入一条数据,立即把这个数据对应的日志写入到fsync到磁盘上去 性能很差一般不推荐使用
- everysec:每秒将os cache中的数据fsync到磁盘 这个是最常用的
- no:仅仅将数据写入到os cache就不管了,后面os自己将数据刷到磁盘上。因为不可控 用的比较少
日志
AOF日志写入时为了速度够快不会进行语法检查为了保证语法的正确性
使用写后日志也就是redis做完对应的操作后,再写入日志中.这样的好处就是 1.速度快2不会阻塞当前写操作
使用写后日志也就是redis做完对应的操作后,再写入日志中.这样的好处就是 1.速度快2不会阻塞当前写操作
潜在风险
redis主线程fork子进程创建bgrewriteaof时,内核需要创建管理子进程的相关数据结构和拷贝父线程的页表,这个和redis的实例内存大小有关,实例内存越大页表也就越大,fork耗时就会长会带来阻塞主线程的风险
数据结构
哈希表
哈希桶中存放的是具体指的指针
哈希冲突是不可避免的,解决哈希冲突的方法是使用链式哈希,就是同一个哈希桶的数据使用链表来保存
为了使 rehash 操作更高效,Redis 默认使用了两个全局哈希表:哈希表 1 和哈希表 2。一开始,当你刚插入数据时,默认使用哈希表 1,此时的哈希表 2 并没有被分配空间。随着数据逐步增多,Redis 开始执行 rehash,这个过程分为三步:
给哈希表 2 分配更大的空间,例如是当前哈希表 1 大小的两倍;
把哈希表 1 中的数据重新映射并拷贝到哈希表 2 中;
释放哈希表 1 的空间。
其中第二部看似简单,但是如果数据量够大的话势必会造成redis线程阻塞.无法服务其他请求.为了解决这个问题,使用的方法是渐进式redash.在渐进式 rehash 进行期间, 字典的删除(delete)、查找(find)、更新(update)等操作会在两个哈希表上进行: 比如说, 要在字典里面查找一个键的话, 程序会先在 ht[0] 里面进行查找, 如果没找到的话, 就会继续到 ht[1] 里面进行查找, 诸如此类。
另外, 在渐进式 rehash 执行期间, 新添加到字典的键值对一律会被保存到 ht[1] 里面, 而 ht[0] 则不再进行任何添加操作: 这一措施保证了 ht[0] 包含的键值对数量会只减不增, 并随着 rehash 操作的执行而最终变成空表。
另外, 在渐进式 rehash 执行期间, 新添加到字典的键值对一律会被保存到 ht[1] 里面, 而 ht[0] 则不再进行任何添加操作: 这一措施保证了 ht[0] 包含的键值对数量会只减不增, 并随着 rehash 操作的执行而最终变成空表。
压缩列表
压缩列表类似于数组,数组中的每一个元素都对应保存一个数据,和数组不同的时在数组头部保存三个值
zlbytes(列表的长度)、zltail(列表尾部的偏移量) 和 zllen(列表中entity的个数)。因此如果我们要查找一个和最后一个元素时间复杂度戳O(1),如果要查找其他数据就需要遍历了O(n)
zlbytes(列表的长度)、zltail(列表尾部的偏移量) 和 zllen(列表中entity的个数)。因此如果我们要查找一个和最后一个元素时间复杂度戳O(1),如果要查找其他数据就需要遍历了O(n)
跳表
跳表类似于链表,和链表不同的是在链表的基础上增加了多级索引,根据索引可以快速定位到数据
整数数组和双向链表
都是需要遍历查找时间复杂度O(n)
哨兵
监控
监控是指哨兵周期性的给所有主从库发送PING命令检测他们是否在运行
选主
当哨兵集群有N/2 + 1 个实例认为主库挂了才会把主库标记为下线状态,然后进行选举
筛选:筛选掉一些之前总是和主库断链的从库。down-after-milliseconds * 10 即主从库断连的最大连接超时时间 断联10次就说明从库网络不好
打分第一轮 从库优先级最高的作为新主库 配置项:slave-priority 设置从库的优先级
打分第二轮 和旧主库同步程度最接近的从库得分高, slave_repl_offset 需要最接近 master_repl_offset
打分第三轮 每个实例都会有一个 ID,这个 ID 就类似于这里的从库的编号。目前,Redis 在选主库时,有一个默认的规定:在优先级和复制进度都相同的情况下,ID 号最小的从库得分最高,会被选为新主库。
通知
哨兵会把新的主库连接信息发送给其他从库,让他们执行replicaof命令和新主库建立连接
收藏
收藏
0 条评论
下一页