Redis总结
什么是redis?
Redis是一个开源的使用ANSI C语言编写的,遵守 BSD 协议,支持网络,可以基于内存也可以持久化的Key-value型数据库
Redis的支持的数据类型
-
String(字符串)
格式:set key value/get key value
String类型是二进制安全的,可以包含任何数据,可以支持图片和序列化的对象,是redis最基础的类型,一 个键最大的储存是512M -
Hash(哈希)
格式: hmset name key1 value1 key2 value2
Redis hash 是一个键值(key=>value)对集合。
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。 -
List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
在 key 对应 list 的头部添加字符串元素
格式: rpush name value
在 key 对应 list 的尾部添加字符串元素
格式: lrem name index
key 对应 list 中删除 count 个和 value 相同的元素
格式: llen name
返回 key 对应 list 的长度 -
set(集合)
Set(集合)
格式: sadd name value
Redis的Set是string类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 -
zset(sorted set:有序集合)
格式: zadd name score value
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
Redis持久化的两种方式以及优缺点
持久化就是把内存中数据存到磁盘上,防止服务器宕机导致数据的丢失,持久化有两种方式,默认的RDB和AOF
-
RDB
RDB是Redis Database的缩写,核心是rdbSave和rdbLoad两个函数,一个是把内存的中数据生成RDB文件放到磁盘中,一个是加载磁盘的RDB文件 -
AOF
AOF是Append-only File的缩写,每当执行服务器定时任务时,都会执行flushAppendOnlyFile函数,主要执行两个操作,write将aof_buf中的缓存写到AOF文件中,save根据条件调用sync或fdatasync将AOF保存在磁盘中. -
RDB和AOF比较
- aof的文件要比rdb文件更新更频繁,在服务器宕机时不会损失太多数据
- aof比rdb要安全一些
- rdb性能比aof好
- 可以配置两个,但是优先加载aof
Redis主从复制
Redis虽然读写速度都很快,但是在数据量大的情况下,redis承受的压力也是很大的,为此我们可以用redis集群,主从模式,这就涉及主从同步,保证master和slave数据是一致的
-
全量同步
在slave初始化的时候,slave中没有任何数据,需要把master中的全部数据同步到slave中
首先从服务器连接主服务器,发送SYNC命令
主服务器收到SYNC命令后,通过BGSAVE生成RDB文件,并且用缓冲区记录此后的写操作
主服务器想所有从服务器发送RDB文件,并且缓冲区依旧需要记录之后的写操作
从服务器收到RDB文件之后,清除旧数据,载入收到的RDB文件
主服务器RDB文件发送完毕后开始向从服务器发送缓冲区中的写命令
从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令
如果从服务器执行载入RDB时间过长,主服务器写命令偏多,就会导致溢出,我们可以通过调整client-output-buffer-limit slave来配置缓冲区的大小 -
命令传播
在slave初始完成之后,master有写入了新的数据,如果用全量同步非常消耗资源,这里就可以用命令传播,就是把写的命令发送给slave进行执行,保持主从一致. -
同步优化
如果短时间网络中断,会有一小部分数据丢失,如果用全量同步,非常低效,这里我们可以用psync,在2.8之后就可以用psync代替sync去执行主从同步
部分重同步:
主从服务器的复制偏移量
主服务器的复制积压缓冲区
服务器的运行id(run id)-
主从服务器复制偏移量
假设主服务向从服务器传播30个字节数据,那么就在主服务器的复制偏移量(1000)+30,那么就是1030,从服务器的复制偏移量(1000),如果收到30个字节数据,从服务器复制偏移量+30,这样就可以得出主从是否数据一致,如果想知道同步那些数据给从服务器就要用到主服务器的复制积压缓冲区 -
主服务器复制积压缓冲区
主节点和从节点进行常规同步时,会把写命令也暂存在复制积压缓冲区中。如果从节点和主节点间发生了网络断连,等从节点再次连接后,可以从复制积压缓冲区中同步尚未复制的命令操作
如果从节点和主节点间的网络断连时间过长,复制积压缓冲区可能被新写入的命令覆盖。此时,从节点就没有办法和主节点进行增量复制了,而是只能进行全量复制。针对这个问题,应对的方法是调大复制积压缓冲区的大小 -
服务器运行id
这个是初次同步时,主服务器发送给从服务器的主服务器id,当重新连接是会发送给主服务器,如果一致执行部分重同步,如果不一致说明不是之前的主服务器,执行全量同步 -
心跳检测
当完成了同步之后,主从服务器就会进入命令传播阶段,此时从服务器会以每秒 1 次的频率,向 主服务器发送命令:REPLCONF ACK <replication_offset> 其中replication_offset 是从服务器当前的复制 偏移量master心跳:
指令:PING
周期:由repl-ping-slave-period决定,默认10秒
作用:判断slave是否在线
查询:info replication 获取slave最后一次连接时间间隔,lag项维持在0或1视为正常slave心跳:
指令:REPLCONF ACK {offset}
周期:1秒
作用1:检测命令丢失(若丢失,主服务器会将丢失的写命令重新发给从服务器)
作用2:判断master是否在线
作用3:辅助实现 min-slaves 选项
-
redis哨兵模式
Redis的哨兵模式是建立在主从的基础上的,实现主从的高可用,主服务器关掉后会选举新的从服务器做为主服务器
-
什么是哨兵机制
Redis的哨兵(sentinel)系统用于管理多个Redis,主要执行三个任务
监听:Sentinel会不断的检查你的master和slave是否正常运行
提醒:当被监控的某个 Redis出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
自动故障迁移:当Sentinel检测到master宕机了之后,会从master下的slave中选举一个slave做为新的master,并且通知其他的slave,当客户端连接旧的master时,集群也会向客户端返回新master的地址,使得集群可以使用master代替失效master -
sentinel状态持久化
sentinel的状态会被写入到sentinel的配置中,每次当收到一个新的配置时,或者新创建一个配置时,配置会被持久化到硬盘中,并带上配置的版本戳。这意味着,可以安全的停止和重启sentinel进程. -
sentinel的工作方式
Sentinel以每秒一次的方式给master.slave,其他的sentinel发送一个PING命令
如果一个实例最后一次有效回复PING命令的时间超过own-after-milliseconds设置的值,那么就会被sentinel标记为主观下线
如果一个Master被标记为主观下线,那么监听这个master的所有sentinel都回以每秒一次频率向master发送PING命令,确定这个master是否是主观下线状态
当足够数量的Sentinel(大于等于配置文件指定的值)确定这个Master主观下线,那么就会给这个Master标记为客观下线
在一般情况下,每个Sentinel 会以每10秒一次的频率向它已知的所有Master,Slave发送 INFO 命令
当Master被Sentinel标记为客观下线时,Sentinel 向下线的 Master 的所有Slave发送 INFO命令的频率会从10秒一次改为每秒一次
若没有足够数量的Sentinel同意Master已经下线,Master的客观下线状态就会被移除。 若 Master重新向Sentinel 的PING命令返回有效回复,Master的主观下线状态就会被移除 -
三个定时任务
Sentinel每十秒向master和slave发送info命令,发现slave,确定主从关系.
Sentinel每两秒通过Master的channel交换信息(pub/sub).master节点上有一个发布订阅的频道(sentinel:hello).sentinel节点通过__sentinel__:hello频道进行信息交换(对节点的"看法"和自身的信息),达成共识.
每1秒每个sentinel对其他sentinel和redis节点执行ping操作(相互监控),这个其实是一个心跳检测,是失败判定的依据。 -
主观下线
所谓主观下线指的是单个Sentinel实例对服务器做出的下线判断,即单个sentinel认为某个服务下线(有可能是接收不到订阅,之间的网络不通等等原因)
主观下线就是说如果服务器在down-after-milliseconds给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel 将这个服务器标记为主观下线(SDOWN )
sentinel配置文件中的down-after-milliseconds设置了判断主观下线的时间长度,如果实例在down-after-milliseconds毫秒内,返回的都是无效回复,那么sentinel回认为该实例已(主观)下线,修改其flags状态为SRI_S_DOWN。如果多个 -
客观下线
从主观下线状态切换到客观下线状态并没有使用严格的法定人数算法(strong quorum algorithm), 而是使用了流言协议: 如果 Sentinel 在给定的时间范围内, 从其他 Sentinel 那里接收到了足够数量的主服务器下线报告(大于等于配置监控主节点后边的那个数), 那么 Sentinel 就会将主服务器的状态从主观下线改变为客观下线。 如果之后其他 Sentinel 不再报告主服务器已下线, 那么客观下线状态就会被移除。 -
选举领导者哨兵节点
在master宕机后,我们需要去设置slave为master,而谁去设置,就需要我们选举领导者哨兵节点,
哨兵节点会发送一个请求给别的烧饼节点,同意他为选举人的命令,其他sentinel可以选择同意或不同意,选举使用的算法是Raft算法,如果哨兵3发现自己在选举的票数大于等于哨兵的个数/2+1时,将会成为领导者,如果没有超过,继续选举。。。 -
故障转移机制
slave节点执行slaveof no one命令,接触从节点,变成主节点,
其他slave节点执行slaveof new master命令,替换其他slave的主节点信息
若原主机节点恢复变成新主节点的从节点
通知应用程序新节点的地址 -
解决redis脑裂
redis脑裂就是两个主master,在master宕机后,设置新的slave为master,这个时候master又恢复了,就会出现两个master,而请求还是去旧的master,会导致数据丢失,可以设置(旧版本) min-slaves-to-write 3 min-slaves-max-lag 10 (新版本) min-replicas-to-write 3 min-replicas-max-lag 10
第一个是设置最后拥有几个从节点,第二个参数表示数据复制和同步的延迟不能超过10秒
如果连接到master的slave数量小于第一个参数且ping的延迟时间小于等于第二个参数那么master就会拒绝写请求配置了这两个参数后, 如果发生了集群脑裂原先的master节点接收到客户端的写入请求会拒绝就可以减少数据同步之后的数据丢失。 -
Slave的优先级
sentinel首先会根据slave-priority的优先级来进行排序
如果优先级相同,选择复制偏移量最大,也就是复制最完整的从节点。
如果优先级和复制偏移量都相同,就选择进程ID较小的那个。
一个redis无论是master还是slave,都必须在配置中指定一个slave优先级。要注意到master也是有可能通过failover变成slave的。
如果一个redis的slave优先级配置为0,那么它将永远不会被选为master。但是它依然会从master哪里复制数据。 -
sentinel基本命令
-
获取sentinel的状态
(1)info查看sentinel的zhuangtai
(2)sentinel masters
获取sentinel中监控的所有master的节点
(3)sentinel master
获取master-name节点redis的状态信息
(4)sentinel slaves
获取master-name节点下所有的slaves的状态信息。
(5) SENTINEL get-master-addr-by-name
通过sentinel中的节点名获取其ip地址
-
添加或删除监控节点
(1)sentinel monitorname: sentinel中节点的名字
port ip : 被监控的redis master实例
quorum : failover时,需要的法定人数。
(2)sentinel reset
重置redis name匹配制定的状态,包括正在failover的master。
该操作会删除该节点上的slave信息、已经发现和关联的sentinel节点信息。
sentinel将会重新发现sentinel和redis slave节点。
(3) sentinel remove
删除master节点,sentinel不再监控该节点。
-
manual failover
(1)sentinel failover
强制redis mater进行failover操作。 -
sentinel状态监测
1) redis的监测sentinel会每隔1s向redis master/slave发送一个ping命令。
2)和其他sentinel的发现
redis通过每隔2s进行PUB/SUB redis master/slave中__sentinel:hello channel中的数据,来发现新的sentinel节点和slaves节点。
3)redis slaves更新
A Sentinel sends INFO commands to the masters and slaves every ten seconds in order to take a fresh list of connected slaves, the state of the master, and so forth.
-
-
Sentinel如何获取主服务的信息
Sentinel默认会以每10秒一次的频率,通过命令连接向主服务器发送info命令,通过分析info命令的回复来获取主服务器的当前信息,就像在上篇讲到的复制功能,在客户端输入info replication 命令一样,Sentinel可以获取以下两方面的信息:
(1) 关于主服务器本身的信息,包括服务器run_id,role的服务器角色。
(2) 关于所有从服务器的信息,每个从服务器都由一个slave字符串开头的行记录,记录了从服务器IP和端口(主服务器中有从库的配置信息) -
Sentinel如何获取从服务器的信息
当Sentinel发现主服务器有新的从服务器出现时,Sentinel除了会为这个新的从服务器创建相应的实例结构(sentinelRedisInstance)之外,Sentinel还会创建连接到从服务器的命令连接和订阅连接。Sentinel默认会以每10秒一次的频率通过命令连接从服务器发送info命令,通过分析info命令的回复来获取从服务器的当前信息。包括:从服务器运行run_ID、从服务器角色role、主服务器的ip及端口、主从服务器的连接状态master_link_status、从服务器的优先级slave_priority。 -
Sentinel如何获取其他sentinel
当一个sentinel从_sentinel_:hello频道收到一条信息时,sentinel会对这条信息进行分析,提取出信息中sentinel 的 ip 、port、runID等8个参数,并进行以下检查:
(1) 如果信息中记录的sentinel运行ID和接收信息的sentinel运行ID相同,那么说明这条信息是sentinel自己发送的,sentinel将丢弃这条信息,不做进一步处理。
(2) 相反地,如果信息中记录的sentinel运行ID和接收信息的sentinel运行ID不相同,那说明这条信息监视同一个服务器的其它sentinel发来的,接收信息的sentinel将根据信息中的参数,对相应主服务器的实例结构进行更新。 -
sentinel更新自己的sentinels字典
sentinel为主服务器创建实例结构中的sentinels字典,保存了sentinel本身,还监视这个主服务器的其他sentinel的资料。当一个sentinel接收到其他sentinels发来的信息时,接收的sentinel会从信息中分析并提取出两方面参数:
(1)与sentinel有关的参数,包括sentinel的ip、port、runid、配置纪元。
(2)与主服务器有关的参数, 包括监视主服务器的ip、port、runid、配置纪元。
假设分别有三个sentinel: 127.0.0.1:26379、127.0.0.1:26380、127.0.0.1:26381。三个sentinel正在监视主服务器127.0.0.1:6379, 那么当127.0.0.1:26379这个sentinel接收到以下消息时:
(1) 第一条信息发送者为自己,信息忽略。
(2) 第二条信息发送者为26381, sentinel会根据信息提取出内容,对sentinels字典中26381对应的实例结构进行更新。
(3) 第三条信息发送者为23680,同样更新字典中的23680对应的实例结构。
每个sentinel都有自己的一个sentinels字典, 对于26379的sentinel它的sentinels字典信息保存了26380和26381两个sentinel信息。其它sentinel也一样。 -
sentinel创建连向其他sentinel的命令连接
当sentinel通过频道信息发现一个新的sentinel时,不仅更新sentinels字典,还会创建一个连向sentinel命令连接,而新的sentinel也会创建连向这个sentinel的命令连接,最终监视同一个主服务器的多个sentinel将形成相互连接的网络。 -
Sentinel和master,slave,Sentinel自动发现机制
虽然sentinel集群中各个sentinel都互相连接彼此来检查对方的可用性以及互相发送消息。但是你不用在任何一个sentinel配置任何其它的sentinel的节点。因为sentinel利用了master的发布/订阅机制去自动发现其它也监控了统一master的sentinel节点。
通过向名为__sentinel__:hello的管道中发送消息来实现。
同样,你也不需要在sentinel中配置某个master的所有slave的地址,sentinel会通过询问master来得到这些slave的地址的。
每个sentinel通过向每个master和slave的发布/订阅频道__sentinel__:hello每秒发送一次消息,来宣布它的存在。
每个sentinel也订阅了每个master和slave的频道__sentinel__:hello的内容,来发现未知的sentinel,当检测到了新的sentinel,则将其加入到自身维护的master监控列表中。
每个sentinel发送的消息中也包含了其当前维护的最新的master配置。如果某个sentinel发现
自己的配置版本低于接收到的配置版本,则会用新的配置更新自己的master配置。
在为一个master添加一个新的sentinel前,sentinel总是检查是否已经有sentinel与新的sentinel的进程号或者是地址是一样的。如果是那样,这个sentinel将会被删除,而把新的sentinel添加上去。