Redis进阶二之Redis数据安全性分析--重点笔记

一 Redis性能压测脚本介绍

# 20个线程,100W个请求,测试redis的set指令(写数据)
redis-benchmark -a 123qweasd -t set -n 1000000 -c 20
...
Summary:
throughput summary: 116536.53 requests per second ##平均每秒11W次写操作。
latency summary (msec):
avg min p50 p95 p99 max
0.111 0.032 0.111 0.167 0.215 3.199

⼆、Redis数据持久化机制详解

Redis提供了很多跟数据持久化相关的配置,⼤体上,可以组成以下⼏种策略:
1,⽆持久化:完全关闭数据持久化,不保证数据安全。相当于将Redis完全当做缓存来⽤
2,RDB(RedisDatabase):按照⼀定的时间间隔缓存Redis所有数据快照。
3,AOF(Append Only File):记录Redis收到的每⼀次写操作。这样可以通过操作重演的⽅式恢复Redis的数据,
4,RDB+AOF:同时保存Redis的数据和操作。
 
两种⽅式的优缺点:
RDB
优点:
1、RDB⽂件⾮常紧凑,⾮常适合定期备份数据。
2、RDB快照⾮常适合灾难恢复。
3、RDB备份时性能⾮常快,对主线程的性能⼏乎没有影响。RDB备份时,主线程只需要启动⼀个负责数据备份的⼦线程即可。所有的备份⼯作都由⼦线程完成,这对主线程的IO性能⼏乎没有影响。
4、与AOF相⽐,RDB在进⾏⼤数据量重启时会快很多。
缺点:
1、RDB不能对数据进⾏实时备份,所以,总会有数据丢失的可能。
2、RDB需要fork化⼦线程的数据写⼊情况,在fork的过程中,需要将内存中的数据克隆⼀份。如果数据量太⼤,或者CPU性能不是很好,RDB⽅式就容易造成Redis短暂的服务停
⽤。相⽐之下,AOF也需要进⾏持久化,但频率较低。并且你可以调整⽇志重写的频率。
AOF
优点:
1、AOF持久化更安全。例如Redis默认每秒进⾏⼀次AOF写⼊,这样,即使服务崩溃,最多损失⼀秒的操作。
2、AOF的记录⽅式是在之前基础上每次追加新的操作。因此AOF不会出现记录不完整的情况。即使因为⼀些特殊原因,造成⼀个操作没有记录完整,也可以使⽤redis-check-aof⼯
具轻松恢复。
3、当AOF⽂件太⼤时,Redis会⾃动切换新的⽇志⽂件。这样就可以防⽌单个⽂件太⼤的问题。
4、AOF记录操作的⽅式⾮常简单易懂,你可以很轻松的⾃⾏调整⽇志。⽐如,如果你错误的执⾏了⼀次 FLUSHALL 操作,将数据误删除了。使⽤AOF,你可以简单的将⽇志中最后
⼀条FLUSHALL指令删掉,然后重启数据库,就可以恢复所有数据。
缺点:
1、针对同样的数据集,AOF⽂件通常⽐RDB⽂件更⼤。
2、在写操作频繁的情况下,AOF备份的性能通常⽐RDB更慢。
混合持久化策略
RDB和AOF两种持久化策略各有优劣,所以在使⽤Redis时,是⽀持同时开启两种持久化策略的。在redis.conf配置⽂件中,有⼀个参数可以同时打开RDB和AOF两种持久化策略。
 
这也说明,如果同时开启RDB和AOF两种持久化策略,那么Redis在恢复数据时,其实还是会优先选择从AOF的持久化⽂件开始恢复。因为通常情况下,AOF的数据集⽐RDB更完整。⽽且AOF的持久化
策略现在已经明确包含了RDB和AOF两种格式,所以AOF恢复数据的效率也还是⽐较⾼的。
 
但是要注意,既然服务重启时只找AOF⽂件,那是不是就不需要做RDB备份了呢?通常建议还是增加RDB备份。因为AOF数据通常在不断变化,这样其实不太利于定期做数据备份。所以通常建议保留
RDB⽂件并定期进⾏备份,作为保证数据安全的后⼿。
 

 三 主从复制

 (一)⼯作流程

1》 Slave启动后,向master发送⼀个sync请求。等待建⽴成功后,slave会删除掉⾃⼰的数据⽇志⽂
件,等待主节点同步。
2》master接收到slave的sync请求后,会触发⼀次RDB全量备份,同时收集所有接收到的修改数据
的指令。然后master将RDB和操作指令全量同步给slave。完成第⼀次全量同步。
3》主从关系建⽴后,master会定期向slave发送⼼跳包,确认slave的状态。⼼跳发送的间隔通过参
数repl-ping-replica-period指定。默认10秒。
4》只要slave定期向master回复⼼跳请求,master就会持续将后续收集到的修改数据的指令传递给
slave。同时,master会记录offset,即已经同步给slave的消息偏移量。
5》如果slave短暂不回复master的⼼跳请求,master就会停⽌向slave同步数据。直到slave重新上线
后,master从offset开始,继续向slave同步数据。
 

(二)主从复制的缺点

1》复制延时,信号衰减: 所有写操作都是先在master上操作,然后再同步到slave,所以数据同步
⼀定会有延迟。当系统繁忙,或者slave数量增加时,这个延迟会更加严重。
2》master⾼可⽤问题: 如果master挂了,slave节点是不会⾃动切换master的,只能等待⼈⼯⼲
预,重启master服务,或者调整主从关系,将⼀个slave切换成master,同时将其他slave的主节点调
整为新的master。
后续的哨兵集群,就相当于做这个⼈⼯⼲预的⼯作。当检测到master挂了之后,⾃动从slave中选择
⼀个节点,切换成master。
3》从数据安全性的⻆度,主从复制牺牲了服务⾼可⽤,但是增加了数据安全。
 

四、Redis哨兵集群Sentinel机制

 

image

 

Redis的Sentinel不负责数据读写,主要就是给Redis的Replica主从复制提供⾼可⽤功能。主要作⽤有四个:
主从监控:监控主从Redis运⾏是否正常
消息通知:将故障转移的结果发送给客户端
故障转移:如果master异常,则会进⾏主从切换。将其中⼀个slave切换成为master。
配置中⼼:客户端通过连接哨兵可以获取当前Redis服务的master地址。
(一)发现master服务宕机后,如何切换新的master
当确定master宕机后,Sentinel会主动将⼀个新的slave切换为mater。这个过程是怎么做的呢?通过以下⼀个Sentinel服务的⽇志,可以看到整个过程:

image

 从这个⽇志中,可以看到Sentinel在做故障切换时,是经过了以下⼏个步骤的:

<1> master变成O_DOWN后,Sentinel会在集群中选举产⽣⼀个服务节点作为Leader。Leader将负责向其他Redis节点发送命令,协调整个故障切换过程。在选举过程中,Sentinel是采⽤的Raft算
法,这是⼀种多数派统⼀的机制,其基础思想是对集群中的重⼤决议,只要集群中超过半数的节点投票同意,那么这个决议就会成为整个集群的最终决议。这也是为什么建议Sentinel的quorum设置为
集群超半数的原因。
<2>Sentinel会在剩余健康的Slave节点中选举出⼀个节点作为新的Master。 选举的规则如下:
⾸先检查是否有提前配置的优先节点:各个服务节点的redis.conf中的replica-priority配置最低
的从节点。这个配置的默认值是100。如果⼤家的配置都⼀样,就进⼊下⼀个检查规则。
然后检查复制偏移量offset最⼤的从节点。也就是找同步数据最快的slave节点。因为他的数据是
最全的。如果⼤家的offset还是⼀样的,就进⼊下⼀个规则
最后按照slave的RunID字典顺序最⼩的节点。
<3>切换新的主节点。 Sentinel Leader给新的mater节点执⾏ slave of no one操作,将他提升为master节点。 然后给其他slave发送slave of 指令。让其他slave成为新Master的slave。
<4>如果旧的master恢复了,Sentinel Leader会让旧的master降级为slave,并从新的master上同步数据,恢复⼯作。
<5>最终,各个Redis的配置信息,会输出到Redis服务对应的redis.conf⽂件中,完成配置覆盖。
 

五、Redis集群Cluster机制

(一)Cluster是什么

image

 

Redis Cluster通过对复制集进⾏合理整合后,核⼼是要解决三个问题:
1》 客户端需要频繁切换master的问题。
2》服务端数据量太⼤后,单个复制集难以承担的问题。
3》master节点挂了之后,主动将slave切换成master,保证服务稳定

(二)Slot如何分配

Redis集群中内置16384个槽位。在建⽴集群时,Redis会根据集群节点数量,将这些槽位尽量平均的分配到各个节点上。并且,如果集群中的节点数量发⽣了变化。(增加了节点或者减少了节点)。就需
要触发⼀次reshard,重新分配槽位。⽽槽位中对应的key,也会随着进⾏数据迁移。

(三)如何确定key与slot的对应关系

Redis集群中,对于每⼀个要写⼊的key,都会寻找所属的槽位。计算的⽅式是 CRC16(key) mod16384。
⾸先,这意味着在集群当中,那些批量操作的复合指令(如mset,mhset)⽀持会不太好。如果他们分属不同的槽位,就⽆法保证他们能够在⼀个服务上进⾏原⼦性操作。
127.0.0.1:6381> mset k1 v1 k2 v2 k3 v3
(error) CROSSSLOT Keys in request don't hash to the same slot
这也是对分布式事务的⼀种思考。如果这种批量指令需要分到不同的Redis节点上操作,那么这
个指令的操作原⼦性问题就称为了⼀个分布式事务问题。⽽分布式事务是⼀件⾮常复杂的事
情,不要简单的认为⽤上seata这样的框架就很容易解决。在⼤部分业务场景下,直接拒绝分布
式事务,是⼀种很好的策略。
然后,在Redis中,提供了指令 CLUSTER KEYSLOT 来计算某⼀个key属于哪个Slot
127.0.0.1:6381> CLUSTER KEYSLOT k1
(integer) 12706
另外,Redis在计算hash槽时,会使⽤hashtag。如果key中有⼤括号{},那么只会根据⼤括号中的hash tag来计算槽位。
127.0.0.1:6381> CLUSTER KEYSLOT k1
(integer) 12706
127.0.0.1:6381> CLUSTER KEYSLOT roy{k1}
(integer) 12706
127.0.0.1:6381> CLUSTER KEYSLOT roy:k1
(integer) 12349
-- 使⽤相同的hash tag,能保证这些数据都是保存在同⼀个节点上的。
127.0.0.1:6381> mset user_{1}_name roy user_{1}_id 1 user_{1}_password 123
-> Redirected to slot [9842] located at 192.168.65.214:6382
OK
在⼤型Redis集群中,经常会出现数据倾斜的问题。也就是⼤量的数据被集中存储到了集群中某⼀个热点Redis节点上。从⽽造成这⼀个节点的负载明显⼤于其他节点。这种数据倾斜问题就容易造成集
群的资源浪费。
调整数据倾斜的问题,常⻅的思路就是分两步。第⼀步,调整key的结构,尤其是那些访问频繁的热点key,让数据能够尽量平均的分配到各个slot上。第⼆步,调整slot的分布,将那些数据量多,访问
频繁的热点slot进⾏重新调配,让他们尽量平均的分配到不同的Redis节点上。

(五)Redis集群选举原理

1,gossip协议
Redis集群之间通过gossip协议进⾏频繁的通信,⽤于传递消息和更新节点状态。
主要作⽤有:
节点间发送⼼跳和确认其他节点的存在。
通知其他节点新节点的加⼊或已经下线的节点。
通过反馈机制更新节点的状态,如权重、过期时间等
gossip协议包含多种消息,包括ping,pong,meet,fail等等。
meet:某个节点发送meet给新加⼊的节点,让新节点加⼊集群中,然后新节点就会开始与其他
节点进⾏通信;
ping:每个节点都会频繁给其他节点发送ping,其中包含⾃⼰的状态还有⾃⼰维护的集群元数
据,互相通过 ping交换元数据(类似⾃⼰感知到的集群节点增加和移除,hash slot信息等);
pong: 对ping和meet消息的返回,包含⾃⼰的状态和其他信息,也可以⽤于信息⼴播和更新;
fail: 某个节点判断另⼀个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机
了
gossip集群是去中⼼化的,各个节点彼此之间通过gossip协议互相通信,保证集群内部各个节点最终能够达成统⼀。gossip协议更新元数据并不是同时在集群内部同步,⽽是陆陆续续请求到所有节点
上。因此gossip协议的数据统⼀是有⼀定的延迟的
 
gossip协议最⼤的好处在于,即使集群节点的数量增加,每个节点的负载也不会增加很多,⼏乎是恒定的。因此在Redis集群中,哪怕构建⾮常多的节点,也不会对服务性能造成很⼤的影响。但是
gossip协议的数据同步是有延迟的,如果集群节点太多,数据同步的延迟时间也会增加。这对于Redis是不合适的。因此,通常不建议构建太⼤的Redis集群。
 
需要注意下的是,Redis集群中,每个节点都有⼀个专⻔⽤于节点之间进⾏gossip通信的端⼝,就是⾃⼰提供服务的端⼝+10000.因此,在部署Redis集群时,要注意防⽕墙配置,不要把这个端⼝屏蔽
了。
2、Redis集群选举流程
当slave发现⾃⼰的master变为FAIL状态时,便尝试进⾏Failover,以期成为新的master。由于挂掉
的master 可能会有多个slave,从⽽存在多个slave竞争成为master节点的过程, 其过程如下:
1》slave发现⾃⼰的master变为FAIL
2》将⾃⼰记录的集群currentEpoch加1,并⼴播FAILOVER_AUTH_REQUEST信息(currentEpoch可
以理解为选举周期,通过cluster info指令可以看到)
3》其他节点收到该信息,只有master响应,判断请求者的合法性,并发送
FAILOVER_AUTH_ACK,对每⼀个 epoch只发送⼀次ack
4》尝试failover的slave收集master返回的FAILOVER_AUTH_ACK
5》slave收到超过半数master的ack后变成新Master(这⾥解释了集群为什么⾄少需要三个主节点,
如果只有两 个,当其中⼀个挂了,只剩⼀个主节点是不能选举成功的)
6》slave⼴播Pong消息通知其他集群节点
从节点并不是在主节点⼀进⼊ FAIL 状态就⻢上尝试发起选举,⽽是有⼀定延迟,⼀定的延迟确保我
们等待 FAIL状态在集群中传播,slave如果⽴即尝试选举,其它masters或许尚未意识到FAIL状态,
可能会拒绝投票
延迟计算公式: DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越⼩代表已复制的数据越
新。这种⽅ 式下,持有最新数据的slave将会⾸先发起选举(理论上)。

 

 
posted @ 2026-03-27 10:46  OMGq  阅读(4)  评论(0)    收藏  举报