目录

redis与分布式

redis是一个单机小程序,如果想让它做一些重量级的事,就会涉及到一整套分布式的概念。

https://gitee.com/lienhui68/picStore/raw/master/null/image-20200928235302857.png

持久化

持久化并不仅仅指从内存到数据库,也指异地备份容灾(从杭州复制到北京也较持久化)

  • 基于文件 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移动到了进程的内存空间中,进程自己去维护

      https://gitee.com/lienhui68/picStore/raw/master/null/1937724-20200609154330858-1169956174.png

      提到内存就得提到DMA,DMA是硬件层级的

redis默认开启rdb,默认关闭aof,可以手工开启aof,4.x以前开启aof 重启后只会读取aof

重写

4.x以后,rdb+增量的内容(重写之后追加的日志),又叫混合持久化

https://gitee.com/lienhui68/picStore/raw/master/null/image-20200929001621286.png


持久化要解决的问题 数据丢失,可靠性,容灾

使用redis是为了快,持久化就要涉及到io,会变得慢

redis做缓存,不建议做持久化

如果不持久化,redis重启数据被清空,就会发生缓存穿透,血崩

选择一种最快的持久化方案。

其实还可以不开启aof这种方案,通过网络主从备份

rdb还是需要的,不然主的不持久化,断电重启后从的数据也恢复不了

持久化会丢数据,主从复制是弱一致性的,也会丢失数据

拿redis做数据库是一件比较疯狂的事情,用redis作数据库必然会做持久化和主从

把redis打造成像关系型数据库的样子,需要开启每操作就写,且主从强一致性,这时候redis的性能已经降到和mysql差不多了甚至还不如mysql对外提供的速度。

https://gitee.com/lienhui68/picStore/raw/master/null/image-20200929002642053.png


单机问题和解决方案

只要单机的技术都存在两点问题

  • 单点故障

    挂了容易造成不可用

    解决:全量集群(主从的高可用集群),主从复制,读写分离

    全量:为了解决单点问题,现在是每台都存有相同数据的主从集群方式。

  • 单机压力/性能

    扩容,sharding 分片,每台机器不是全量

    sharding之后每台机器又成了单点,此时对分片再做一个全量的主从复制

集群:全量集群/分片集群,差异是数据的摆放形式。

可用性/可扩展性 avalability, scalibility

https://gitee.com/lienhui68/picStore/raw/master/null/image-20200929003607449.png


主从复制

redis解决HA,主从复制

client写到主节点(主节点写log),主节点同步数据到从节点(从节点写log)

同步数据

https://gitee.com/lienhui68/picStore/raw/master/null/image-20200929004638826.png

强一致性 会造成 不可用(client访问之后,有节点挂了同步不了,阻塞堆积,对外表现不可用),强一致性就会破坏可用性

此时就需要CAP了,既然CP不行,就用AP

可以配置同步,强一致性,比如3个从,收到3个ok才返回客户端

弱一致性

https://gitee.com/lienhui68/picStore/raw/master/null/image-20200929005624887.png

redis主从默认工作在这个级别,redis主异步写给从

用redis做分布式锁靠谱吗?不靠谱,主从是弱一致,单机挂了更危险。

金融级系统 no,

互联网系统 yes,对数据强一致性不高的情况,速度、粘度,跟钱不相关的业务。

zk 倾向于 大数据做分布式协调

etcd 谷歌 go,容器

最终一致性

https://gitee.com/lienhui68/picStore/raw/master/null/image-20200929010017159.png

异步写可能会失败,改成往一个黑盒同步写(注意是同步写),只要一写就立马成功。

redis和黑盒之间是一个强一致性

redis目前没有实现最终一致性,指写数据,哨兵机制有使用raft,从哨兵当中选主(如果主哨兵挂掉了的话或者第一次选举)

zookpeer 和 redis 集群内一致性协议及选举对比
  • 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

https://gitee.com/lienhui68/picStore/raw/master/null/image-20200929013636949.png

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

    https://gitee.com/lienhui68/picStore/raw/master/null/image-20200929013859665.png

    客户端里实现sharding算法(扔进去还能取回来),

    可以自己写也可以引入jar包,总归比较麻烦,同时客户端也要占cpu,占用算力,而且多台算法同步更新变化(加减redis机器),需要在多台同步,全量发布。

  • 代理sharding

    把sharding的算法迁到代理服务器的进程里,不浪费服务端的算力。

    https://gitee.com/lienhui68/picStore/raw/master/null/image-20200929013913274.png

    缺点:代理层服务器要多少台?单点故障?

    也可以解决,负载均衡,高可用

  • 服务端sharding

    sharding算法迁到redis服务器,两次I/O

    https://gitee.com/lienhui68/picStore/raw/master/null/image-20200929014340023.png

    为什么不是模2而是模10?

    虽然算法可以算出在哪里,但是未来扩容会存在问题,因此redis又提出了slot概念 16384,这样以后扩缩容,只要节点数不超过16384,就不需要做整个集群全量的rehash过程。

    假设是分10个槽,物理机两台

    redis除了sharding算法外,还带一个mapping(1,3,5,7,9 模运算后得到的槽位在这几个里面那么数据就从这个物理节点上取),一致性hash

    redis分布式集群实现了paxos,raft,实现了最终一致性

    选举领导者哨兵使用raft算法,状态同步是使用gossip协议通信,由于去中心化和通信机制,Redis Cluster 选择了最终一致性和基本可用。

    参考:浅谈集群版Redis和Gossip协议

    每俩节点之间都维持心跳通信,通过哨兵分布式协调逻辑,通过哨兵那套分布式逻辑代码,各节点之间要先同步完,同步完后各节点都有全局mapping

以上就是redis自己实现的分布式集群。