redis与分布式
redis是一个单机小程序,如果想让它做一些重量级的事,就会涉及到一整套分布式的概念。
持久化
持久化并不仅仅指从内存到数据库,也指异地备份容灾(从杭州复制到北京也较持久化)
-
基于文件 rdb(redis),image,bak
拍快照(时间点)
持久化,快照行为类似于java里的序列化,数据从内存保存到一个文件里,体积与内存中的大小相近(可以使用压缩,性能会有约20%的损耗),恢复速度快,一次I/O read。
-
基于日志 aof(redis)
-
redis配置
趋向于实时,也会丢数据(丢多少取决于redis怎么配置)。
sync 每操作同步/ 每秒同步 等等
-
交给操作系统,只管写,也就是交给page cache
page cache丢多少? 两个维度, 5s / 10%, 看怎么设置,站内引用: {%post_link 工作/100_计科基础/操作系统/PageCache Page Cache %}
如果内存有100G, 按百分比10%配置,也就是丢丢失10个G
DB使用DIO(Direct IO)跨国内核的page cache,等于把page cache移动到了进程的内存空间中,进程自己去维护
提到内存就得提到DMA,DMA是硬件层级的
-
redis默认开启rdb,默认关闭aof,可以手工开启aof,4.x以前开启aof 重启后只会读取aof
重写
4.x以后,rdb+增量的内容(重写之后追加的日志),又叫混合持久化
持久化要解决的问题 数据丢失,可靠性,容灾
使用redis是为了快,持久化就要涉及到io,会变得慢
redis做缓存,不建议做持久化
如果不持久化,redis重启数据被清空,就会发生缓存穿透,血崩
选择一种最快的持久化方案。
其实还可以不开启aof这种方案,通过网络主从备份
rdb还是需要的,不然主的不持久化,断电重启后从的数据也恢复不了
持久化会丢数据,主从复制是弱一致性的,也会丢失数据
拿redis做数据库是一件比较疯狂的事情,用redis作数据库必然会做持久化和主从
把redis打造成像关系型数据库的样子,需要开启每操作就写,且主从强一致性,这时候redis的性能已经降到和mysql差不多了甚至还不如mysql对外提供的速度。
单机问题和解决方案
只要单机的技术都存在两点问题
-
单点故障
挂了容易造成不可用
解决:全量集群(主从的高可用集群),主从复制,读写分离
全量:为了解决单点问题,现在是每台都存有相同数据的主从集群方式。
-
单机压力/性能
扩容,sharding 分片,每台机器不是全量
sharding之后每台机器又成了单点,此时对分片再做一个全量的主从复制
集群:全量集群/分片集群,差异是数据的摆放形式。
可用性/可扩展性 avalability, scalibility
主从复制
redis解决HA,主从复制
client写到主节点(主节点写log),主节点同步数据到从节点(从节点写log)
同步数据
强一致性 会造成 不可用(client访问之后,有节点挂了同步不了,阻塞堆积,对外表现不可用),强一致性就会破坏可用性
此时就需要CAP了,既然CP不行,就用AP
可以配置同步,强一致性,比如3个从,收到3个ok才返回客户端
弱一致性
redis主从默认工作在这个级别,redis主异步写给从
用redis做分布式锁靠谱吗?不靠谱,主从是弱一致,单机挂了更危险。
金融级系统 no,
互联网系统 yes,对数据强一致性不高的情况,速度、粘度,跟钱不相关的业务。
zk 倾向于 大数据做分布式协调
etcd 谷歌 go,容器
最终一致性
异步写可能会失败,改成往一个黑盒同步写(注意是同步写),只要一写就立马成功。
redis和黑盒之间是一个强一致性
redis目前没有实现最终一致性,指写数据,哨兵机制有使用raft,从哨兵当中选主(如果主哨兵挂掉了的话或者第一次选举)
- zookeeper 使用的是zab协议,类似 raft 的 Strong Leader 模式
- redis 的哨兵在崩溃选举的时候采用的是raft的那一套term。
因为redis 采用的是异步数据副本的节点同步方式,所以在做分布式锁的时候可能会存在 setNx之后,没有同步到从节点,主节点崩溃,而这时客户端又从从节点读取数据,导致同步锁设置失败(写入都是master节点)。当然作者提供了redLock 在时间内 挨个节点设置锁的形式。具体意思及实现可以参考redssion中的。
反观zk不会出现这个问题,因为zk的主节点接受到请求后,会保证各个从节点数据写入完毕后,返回客户端。
ZAB 协议的消息广播过程使用的是一个原子广播协议,类似一个 二阶段提交过程。对于客户端发送的写请求,全部由 Leader 接收,Leader 将请求封装成一个事务 Proposal,将其发送给所有 Follwer ,然后,根据所有 Follwer 的反馈,如果超过半数成功响应,则执行 commit 操作(先提交自己,再发送 commit 给所有 Follwer)。
当超过半数成功回应,则执行 commit ,同时提交自己。同时每个事物都有一个zxid 还有一个消息队列解决异步,同时,针对各个节点的数据不一致性问题还有选举过程。
别的技术有实现最终一致性,比如hdfs
journalnode是一个集群技术,3,5,7,9…台namenode
为啥journalnode是集群就可靠? paxos
paxos
redis是单机小程序,没有考虑分布式协调办公,redis分布式集群有实现分布式协调办公
journalnode比redis多的代码逻辑?
分布式协调逻辑consensus
paxos是一个论文,zk中是zab,journalnode是raft,zab/raft是paxos的实现体
所以paxos论文怎么保证在分布式系统中多节点数据的一致性,还能对外提供可用性?
- 投票选举
- 过半机制
假设有3个节点,1主2从
强一致性,3个节点都ok,会破坏可用性
容忍2台挂掉
只要一台ok就行,对外表现脑裂,不同的客户端在访问不同的节点时拿到的数据不一样
折中一下,容忍1台挂掉
首先要明白,除了客户端访问节点外,节点之间两两是要通信(维持心跳)的,现在出现了分区,一边两台一边1台,根据多数派规则,2台所在的区继续对外提供服务,1台就不提供服务
为什么是2台对外提供服务,1台不提供服务,因为1台更容易对外造成不可用,2台(多数节点)都挂掉的可能性肯定比1台(少数节点)挂掉的可能性小。
容忍一些节点挂掉的情况出现,在整体上对外可用
节点挂了之后再回来,需要同步数据(sync() 不是重量)。
为了防止脑裂,不过半的分区里节点禁止对外提供服务
为什么集群节点数是奇数,3,5,7…
假设是3台,为了防止脑裂,容忍的挂机的数量是1,4台的时候为了防止脑裂,容忍的挂机数量还是1。
4台比3台更容易出现挂机的风险,根据经验得来3,5,7,9奇数台。
Redis分布式集群
以上是单点故障引出的主从复制集群内容,下面分析分片集群
分片集群
三种实现方式,站内引用: {%post_link 工作/500_中间件/缓存/redis/10_redis集群方案 分片集群 %}
-
客户端sharding
客户端里实现sharding算法(扔进去还能取回来),
可以自己写也可以引入jar包,总归比较麻烦,同时客户端也要占cpu,占用算力,而且多台算法同步更新变化(加减redis机器),需要在多台同步,全量发布。
-
代理sharding
把sharding的算法迁到代理服务器的进程里,不浪费服务端的算力。
缺点:代理层服务器要多少台?单点故障?
也可以解决,负载均衡,高可用
-
服务端sharding
sharding算法迁到redis服务器,两次I/O
为什么不是模2而是模10?
虽然算法可以算出在哪里,但是未来扩容会存在问题,因此redis又提出了slot概念 16384,这样以后扩缩容,只要节点数不超过16384,就不需要做整个集群全量的rehash过程。
假设是分10个槽,物理机两台
redis除了sharding算法外,还带一个mapping(1,3,5,7,9 模运算后得到的槽位在这几个里面那么数据就从这个物理节点上取),一致性hash
redis分布式集群实现了paxos,raft,实现了最终一致性
选举领导者哨兵使用raft算法,状态同步是使用gossip协议通信,由于去中心化和通信机制,Redis Cluster 选择了最终一致性和基本可用。
每俩节点之间都维持心跳通信,通过哨兵分布式协调逻辑,通过哨兵那套分布式逻辑代码,各节点之间要先同步完,同步完后各节点都有全局mapping
以上就是redis自己实现的分布式集群。