分布式系统(二)


总结一下各种分布式系统对于分布式理论的应用

正前

从一些几个方面来介绍

  1. 主从同步
  2. 分片
  3. 协调中心

主从同步

主从同步的作用主要是保证高可用,将一份数据复制多份到多个节点,分为主节点、从节点或者leader和follower,其中的的问题主要是主从同步延迟导致的数据不一致问题。
其中主从同步和分片一般来说都是结合的,有些中间件是将二者合并的,有些是分离的

  • redis
    • redis是读写分离的,主节点接收读写请求,从节点只接收读请求
    • 数据同步有全量同步和增量同步,(2.8版本之前只有全量同步),全量同步时发送RDB文件进行同步,增量同步是在全量同步的基础上,将新的命令发送过来。
    • 2.8版本后有无磁盘复制模式,使用这种模式,可以通过子进程将直接将RDB文件发送到从服务器。
    • 如果有多个从服务器,全部由主服务器来同步,会造成fork的子进程太多,主服务器的响应应用程序会比较受影响,所以有主-从-从的配置,由已经同步的从服务器来进行分配。
    • 读写分离的问题
      • 延迟与不一致 : 前置: 优化网络,同机房,监控延迟量,通知应用不再从该节点读取数据
      • 数据过期问题 : 主节点会进行惰性删除+定时删除, 从节点不会主动删除,而是主节点来控制,所以可能会出现读取过期数据的问题,升级到3.2后,从节点接收读请求时会判断是否过期。
      • 故障切换 : 没有哨兵的情况下,需要及时修改应用程序来切换
    • redis-cluster的分片会有不同,但是逻辑上上类似
    • 一般来说redis主从同步配合redis-sentinel使用,redis-cluster是二者功能的结合并升级
  • kafka
    • kafka对应的概念是副本,即每个topic的多个分片都会有多个副本(副本数可配置)来保证数据可靠性
    • kafka的副本集为replica,其中有一个leader,来进行读写请求的处理,当leader挂掉之后,由集群controller从ISR中选举出一个新的leader(也可以设置允许从不同步的副本里选举,为脏选举),leader写入消息后,由其他副本进行拉取同步
    • ISR(in-sync replica)即同步中的副本,isr的判断是根据一个参数,即和leader的时间差距,在这个范围内的都认为是同步中的。所以isr是一个动态的集合
    • 因为kafka只对已提交的消息进行有限度的持久化保证,所以需要保证这个已提交,在生产端可以通过重试和acks这个参数来控制,这个参数的意思是,leader写入后,多少个副本都提交后才认为写成功
    • 其中高水位是对于消费者来说,被允许读到的对大消息偏移,同时高水位也是以提交消息和未提交消息的界限
  • zookeeper
    • zk的的主从,是节点级别的,集群节点分为leader,follower,observer,其中leader负责读写请求,follower负责读请求,observer负责分担读请求,不参与选举
    • 对于写请求,都会有leader来处理,leader内部会有一个队列来处理,每个事件都有事务id,leader处理后,会广播给follower进行同步,当半数以上节点同步成功,提交事务
    • 对于读请求,因为可能会有部分节点同步较慢,所以无法保证强一致性,但是会保证最终一致性
  • es
    • es的主从,也是分片层面的,每个分片都有副本分片,对于每个写请求,都要同步给所有副本才成功, 对于读请求,会读取副本分片进行负载均衡
  • mysql
    • mysql的主从同步
    • 过程 : 首先从库连接到主库时会创建一个io线程,泳衣请求主库更新的binlog,并且把收到的binlog写到一个relay log日志文件里,主库会创建一个log dump线程发送binlog,同时从库启动一个sql线程读取relay log日志文件,在从库里回放,实现最终一致性

分片

分片主要为了水平扩展,将数据分片,扩展了读请求的并发量。

  • redis
    • redis分片主要是redis cluster中的hash槽,redis-cluster同时还负责主从同步和主从的选举
    • redis-cluster引用了哈希槽的概念,一般由2^14 = 16384个槽,每个key通过crc16校验后对16383取模来决定放置哪个槽。集群中每个节点负责一部分hash槽。
    • 当增加一个节点后,需要把每个节点的一部分槽和数据迁移到新的节点,每个节点负责的槽为变少了。
    • 当下线一个节点时,需要先把该节点的槽位迁移到其他节点,然后关闭对应节点
    • 集群模式下,redis接收任何命令都是线计算槽为,然后找到对应的节点,如果节点时自身,则处理命令,否则恢复moved重定向错误,通知客户端请求正确的节点
      • 命令行下可以加-c自动重定向
    • 当集群正在发生迁移时,接收到命令后,可能发生槽的一部分数据在原来的节点,一部分在当前节点,这个时候先在自己的本地查找,如果没有找到,发送ask重定向到原来的节点。
  • kafka
    • kafka的分片是用于扩展集群吞吐量的,对于生产者来说,每次写入时,会通过负载均衡(轮训,随机,hash)写入其中一个分片,对于消费者来说,一个分片只能被一个实例所消费。
    • 一个topic的分区尽量会分布到不同的broker中
    • 一个topic的每一条消息,对于一个消费组来说,只能消费一次,放到分片层面,就是一个分片只能被消费组中的一个消费者消费
    • 当消费组订阅的topic数量,topic的分片数量,topic的消费者发生变化时,会触发rebalance,重新分配消费者
  • zookeeper
    • zk没有分片的概念,因为存储的数据都是轻量的
  • es
    • es的分片机制,es在创建索引时就会设置分片数量,
    • 对于读请求,首先到一个协调节点,通过文档id确定分片,然后通过轮训副本分片负载均衡,读取对应的副本分片,然后将结果返回给协调节点
    • 对于写请求, 到达协调节点后,会根据文档id确定分片,然后找到主分片所在的节点进行操作,成功后,通知到协调节点,返回给客户端
  • mysql
    • mysql的分片主要是分库分表,

协调中心

协调中心主要用于主从的选举和监控协调。

  • redis
    • redis的协调中心是redis-sentinel,主要是用于主节点的自动故障转移,因为在单机的主从同步下,主节点出现故障只能自己切换
    • 哨兵也是一个集群,主要通过redis的pub/sub机制,在主库上有一个_sentinel:hello频道,哨兵1发布自己的的ip和端口号,哨兵2和哨兵3订阅,就可以拿到ip端口号然后进行通信,就主库下线的事情进行判断和协商
    • 哨兵向主库发送info信息,主库回复从库列表,接着,哨兵和所有从库建立连接,同时其他哨兵也会进行连接
    • 判断主库下线
      • 主观下线,每个哨兵和主库的连接情况判断
      • 客观下线,哨兵集群对节点的判断。
      • 当有一个哨兵判断主库主观下线后,会让其他哨兵判断,其他哨兵根据自己的连接情况进行判断,当赞成票>=哨兵配置quorum(节点/2)时,标记为客观下线。
    • 当判断主库下线时,需要一个哨兵节点来执行主从切换,设计哨兵的选举
      • 还是raft算法,收到大于节点数量一半的票时,成为领导者。
    • 新主库的选出
      • 过滤掉不健康的从库,(下线或者断线,没有回复ping响应)
      • 优先级高的
      • 复制偏移量最大的
  • kafka
    • kafka的协调中心使用的是zk
    • kafka涉及选举的有两个,
      • 一个是broker的controller,它主要负责集群元数据的记录,broker的管理,主题创建,副本leader选举。controller的选举比较简单,就是多个broker取zk上创建/controller临时节点,第一个创建成功的就是controller,同时没有成功的节点会在这个节点下创建watcher,当对应broker挂了,其他节点就可以收到消息进行新的选举
      • 另一个时副本分片的选举,这个介绍的不多,大部分说的都是由controller来从ISR中进行选举
  • zookeeper
    • zk本身就是作为协调中心存在的,所以这里主要介绍它的选举机制
    • zk使用的是zab协议,zab主要有两个模式,崩溃恢复和广播通知
    • 崩溃恢复
      • 当leader服务器发生网络中断,宕机等异常情况时,zk集群会进入恢复模式,当选举出新的leader,并且已经有半数以上机器和leader的数据同步,退出恢复模式
    • 消息广播
      • 退出恢复模式后,进入消息广播模式,leader接收到读请求后,会讲消息广播出去,follower和observer会进行同步,当超过一般机器ack后,提交消息
      • leader会对其他节点创建一个队列,保证数据同步
    • 选举详情
      • 当进入恢复状态后,每台机器首先会把票投给自己,然后将投票信息发出去,投票信息为(myid,zxid)myid时机器的id,zxid是当前机器最新同步的事务id,当机器收到其他机器的投票信息,会比较投票信息,首先比较zxid,大优先,然后比较myid,也是大优先,如果发现目标机器比自己更适合,就会讲投票信息更改为目标机器再次广播出去,当目标机器发现自己收到票超过半数,就成为leader,将信息同步出去。
      • zk的节点数都是奇数,因为如果超过半数机器挂掉,集群就不可用了,那么偶数机器效果一样,还多部署一台机器,造成浪费。
      • 当follwer挂掉后,只要挂掉的机器没有超过一半,集群就是可用的,leader后面会继续同步数据
      • 当leader挂掉后,集群会停止服务,进行选举
  • es
    • es在7.x之前使用的是bully算法,7.x之后使用raft算法
    • es有两种节点,主节点和数据节点,客户端节点
      • 主节点, 主节点负责创建索引,删除索引,分配分片,用户请求可以发往任何一个节点,并由该节点分发请求,收集结果等操作,而并不需要经过主节点转发
      • 数据节点, 数据节点主要负责数据的存储和相关操作,比如索引数据的创建,修改,删除,搜索,数据节对机器配置要求比较高
      • 客户端节点, 即不做候选节点也不做数据节点的节点,只负责请求的分法,汇总,就是协调节点
      • 协调节点,逻辑上的,任何节点都可以当,当一个节点收到请求后,会把查询语句分法到其他节点,并合并各个节点的查询结果,然后返回给用户
    • es的选举算法是zen directory,不过最新的已经换了,采用集群协调模块代替旧版
    • zen directory的主要流程时, 由master-eligoble节点发起选举,当满足一下条件后发起
      • 当前eligoble节点不是master
      • 连接不到master
      • 超过一定数量的节点认为没有master时
    • 每个eligoble会根据closterStateVersion和节点id排序, 然后选举出一个它认为的master,然后向它发送join请求,目标节点如果已经是master,就将它加入,并发布新的cluster state, 如果目标节点正在竞选,就会把这个join当作一个选票,如果目标节点认为自己选不上,就拒绝这个join请求,
    • 当收到半数以上的票后,就成为master节点。

  目录