保卫萝卜苹果手机版
175.4M · 2025-11-14
单机版的redis就是业务系统把他用作缓存使用,从mysql中查询数据然后写入到redis中,后面再查询的时候就会优先查询缓存。因为redis运行在内存中,所以速度很快。若业务体量不大,这样似乎可以满足需求了。但是随着业务体量的扩大,redis中存储的数据越来越多,此时业务对redis的依赖也越来越多。假设有一种情况,redis因为某些原因宕机了,请求都会打到mysql上,导致mysql压力突增。
这时候能想到的做法可能是重启redis,但是因为redis运行在内存,重启后数据就丢失了,虽然可以正常工作,但没有任何数据,请求还是会打到mysql上。
那么你就会想,有没有什么办法能让redis重启后数据仍然存在呢?那就是把数据写到磁盘上。
那数据持久化怎么做呢?一个简单的思路是当每次redis进行写操作时,都把数据再存一份到磁盘上。但是这样做又会导致redis的压力增大,因为要写磁盘!
那如何解决?优化思路是,redis的写内存由主线程来做,写内存完后就返回给客户端,redis用另外一个线程去写磁盘,这样就可以并发操作。
那么换一个角度,我们用redis通常是用来做缓存,是为了把数据库中的数据写到缓存中,减轻查询的压力。那么就算redis中不存在这些数据,找数据库也能拿到,只是速度慢一些。所以就有了用【数据快照】的持久化方法。这种方式的优点是除了在【持久化】的时刻要把数据一次性写入磁盘,其他时间都不需要操作磁盘。
以上两种方法就对应redis的两种持久化方案RDB和AOF。除此之外,还有以下这些特点:
那么有什么办法,既可以缩小文件体积,又可以提升恢复速度呢?我们这里想一下,因为AOF记录是每一次写操作,对于同一个key可能会进行多次操作,那么是否可以只保留最终的结果呢?这就是【AOF rewrite】。我们可以定时rewrite,避免文件持续膨胀,这样在恢复的时候就可以缩短时间了。
那有没有什么办法继续缩小AOF文件呢?那就是redis的【混合持久化】。具体来说,当AOF rewrite时,redis先以RDB格式在AOF文件中写入一个数据块找,再把这期间内产生的每一个写命令加入到AOF文件中。(redis4.0版本以上才支持混合持久化)。
虽然现在已经把持久化的文件优化到最小了,但在恢复数据时依旧需要时间,这期间业务还是会受到影响,怎么办?一个实例宕机,只能用恢复数据来解决,是否可以部署多个redis实例,让这些实例数据保持同步,这样在一个redis宕机时可以在剩下的实例中选一个继续提供服务。【主从复制】
主从复制的形式就是会有一个主节点,以及一个/多个从节点。这样做的优势是:
但这里存在一个问题,就是在主节点宕机时,需要手动把从节点提升为主节点,这个过程要花费时间。虽然比恢复数据要快,但还是要人工介入。那怎么去解决这个问题呢?——就有了接下来的【故障自动切换机制】。
我们在这种模式会引入观察者(哨兵),这个观察者不存储数据,只是会去实时监测节点的健康状态。
但这里还存在一个问题,就是如果哨兵与主节点之间的网络除了问题,这个哨兵可能会误判!这里我们就可以部署多个哨兵,让它们部署在不同的机器上,一起监测主节点的状态,流程如下:
那么确定主节点故障后,由哪个哨兵进行主从切换呢?这里我们采用基于raft算法的领导选举规则:1)每个哨兵问其他哨兵,请求对方为自己投票;2)如果对方已经给别人投了票,就不能给他投票;若还没投票,就投给他;3)当第一个拿到超过半数投票的哨兵,当选为领导者。(分布式系统领域中的共识算法)
那么随着时间推移,业务体量越来越大,此时这个架构模型还能承担这么大的流量吗?以前的做法是,主节点承担写操作,从节点承担读操作,但是当业务流量暴增的时候,主节点还能承受这么大的写流量吗?——这里就考虑到了【分片集群】。
多实例如何组织?
1)每隔节点各自存储一部分数据,所有节点的数据之和才是全量数据。
2)指定一个路由规则,对不同的key把它路由到一个实例上进行读写。
这种思路可以根据所在位置不同分为两类:
1)客户端分片:key的路由规则放在客户端来做,但缺点是客户端需要维护这个路由规则。那如何不在业务代码耦合这些代码呢?就是把路由规则封装成一个模块,当要使用时集成这个模块就可以了。这就是redis Cluster采用的方案。(其中内置了哨兵逻辑,不用再部署哨兵)
2)服务端分片:路由规则不放在客户端来做,而是在客户端和服务端之间引入一个【中间代理层】。这个代理会把你的请求根据路由规则,转发到对应的redis节点上,当集群实例不足以支撑更大的流量请求时可以横向扩容,添加新的redis实例提升性能。这些操作对于客户端来说都是无感知的。
参考:公众号水滴与银弹