分布式系统咋作同步?虐死人!

原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。mysql

分布式系统,经过数据冗余,来保证数据的安全。要写一个分布式系统,一道绕不过去的坎,那就是数据同步。程序员

同步,这两个字,折磨死了不少人。web

是同步,仍是异步?是push,仍是pull?谁是master,谁是slave?下线会怎样,上线了又会怎样?中心化,or对等节点?redis

这些问题,无一不拷打者分布式系统的设计者。算法

下面,咱们将看一下主流的几个存储服务,是如何解决数据同步问题的。sql

MySQL如何作主从同步?

mysql的主服务器叫作master,从服务器叫作slave。mongodb

主服务器将变动记录在binlog中,slave将经过独立的线程拷贝这些记录,而后重放。数据库

binlog的格式分为statement、row、mixed三种。缓存

  • statement 将变动的sql语句写入到binlog中,在准确性方面会有必定影响
  • row 将每一条记录的变化,写入到binlog中
  • mixed 上面两种的结合。MySQL会判断何时有用statement,何时用row

因为是异步线程去拷贝,slave很容易会出现延迟。当master不幸宕机,将会形成延迟的数据丢失。安全

replicationseminew.png

为了解决异步复制的问题,5.5版本以后,MySQL引入了半同步复制(semi sync)的概念。半同步处于异步和全量同步之间,master执行完事务以后,并不直接返回,而是要等待至少一个slave写入成功才返回。因为须要与至少一个slave进行交互,性能相比较异步复制确定是有很多折损的。

全复制模式固然是要等待全部的slave节点复制完成,这种安全性最高,可是效率也最低。从概念上来说,只有一个slave的半复制就是全复制。

5.7以后,mysql实现了组复制(group replication)协议。它支持单主模式和多主模式,但在同一个group内,不容许同时存在。听起还好像很神奇,其实它仍是经过paxos协议去实现的。

Kafka如何作的副本同步?

kafka因为是一个消息队列,因此不须要考虑随机删除和随机更新的问题,它只关注写入问题便可。从结构上来讲,kafka的同步单元是很是分散的:kafka有多个topic,每一个topic又分为多个partition,副本就是基于partiton去作的。

主分区叫作leader,1-n个副本叫作follower。生产者在发送消息的时候,须要先找到该分区的leader,而后将数据发送给它。follower只是做为一个备份存在,以便在主分区发生问题时可以顶上去。

x.jpg

kafka的主从同步,叫作ISR(In Sync Replica)机制。

那何时消息算是发送成功呢?这还要看ack的发送级别。

  • 0 表示异步发送,消息发送完毕就算是成功了
  • 1 leader主副本写入完成,就算是发送成功了
  • -1 leader发送完成,而且ISR中的副本都须要回复ack

0和1的状况下,kafka都有丢失消息的可能。在-1的状况下,也须要保证至少有一个follower commit成功才能保证消息安全。若是follower都不能追遇上leader,则会被移除出 ISR列表。没错,是直接移除。当ISR为空,则kafka的分区和单机是没有区别的,因此kafka提供了min.insync.replicas参数规定了最小ISR。

  • 当ISR不知足的时候怎么办?kafka固然是不会丢失消息了,由于此时生产者的提交是失败的,消息根本进不了系统里来
  • 当全部副本都不可用怎么办?此时,该partition将永不可用

副本之间的数据复制,是经过follower pull的方式,也就是拉取的方式去获取的。

Redis的主从复制

redis是内存kv数据库,速度上远超其余数据库,理论上主从同步更容易。但在高流量和高QPS下,主从复制依然会发生问题。

redis的slave链接上以后,首先会进行一次全量同步。它会发送psync命令到master,而后master执行bgsave生成一个rdb文件。全量同步就是复制这个rdb快照文件到slave。

那在全量复制中间出现的数据怎么办呢?确定是要缓存起来的。master会开启一个buffer,而后记录全量复制过程当中产生的新数据,在全量同步完成以后再补齐增量数据。

slave断线以后也不须要每次都执行全量同步,为了配合增量,还引入了复制偏移量(offset)、复制积压缓冲区(replication backlog buffer)和运行 ID (run_id)三个概念。能够看出它都是为了标识slave,以及它的复制位置和缓冲区用的。

image-20210802151100440.png

以后的同步,就能够一直使用psync去复制。依然是异步复制。

能够看出redis的主从复制一致性大量依赖内存,级别是很是弱的。可是它快。快能解决不少问题,因此应用场景是不一样的。

ElasticSearch主从复制

es是基于lucene的搜索引擎,数据节点会包含多个索引(index)。每一个索引包含多个分片(shard),每一个分片又包含多个replica(副本)。

从上面的描述来看,这些概念是与kafka高度雷同的,es的复制单元是分片。

es的数据依然是先写master,它一样维护了一个同步中的slave列表(InSyncAllocationIds),处于yellow和red状态的副本固然是不在这个列表中的。

master须要等待全部这些正常的副本写入完成后,才返回给客户端,因此一致性级别是比较高的,由于它的slave节点是要参与读操做的,它是一个近实时系统。

因为它是一个数据库,因此依然会有删除和更新操做。Translog至关于wal日志,保证了断电的数据安全,这和其余rdbms的套路是一致的。

Cassandra集群模式

cassandra是一个很是有名的CAP理论实践数据库,更多的像一个AP数据库,目前在db-engines.com依然有较高的排名。

数据存储是表的概念,一个表能够存储在多台机器上。它的分区,是经过partition key来设计的,数据分布很是依赖于hash函数。若是某个节点出现问题怎么办?那就须要一致性hash的支持。

cassandra很是有意思,它的复制(replicas)并不像其余的主备数据同样,它更像是多份master数据,这些数据都是同时向外提供服务的。当掉一个检点,并不须要主备切换。

image-20210802151730781.png

为何能够作到这种程度呢?由于cassandra追求的是最终一致性。分布式系统因为副本的存在,不可避免的要异步或者同步复制。那到底复制到什么程度才算是合适的呢?QuorumR+W就是一个权衡策略。

quorum = (sum_of_replication_factors / 2) + 1
复制代码

什么意思呢?考虑到你有5个抽屉,而后随机放入W个球,求须要多少次R,才能拿出一个球。假如你向里面放了1个球,你须要打开5次,才能每次都有正确的判断,此时R=五、W=1;当你放了2个球,则你只须要打开4次就能够了;假如你放入了5个球,那就只须要读一次。

当R+W>N的时候,属于强一致性;当R+W<=N的时候,属于最终一致性。

有意思的是,cassandra中的集群信息,即meta信息,使用gossip(push-pull-gossip)进行传递。

MongoDB主从复制

mongodb有三种数据冗余方式。一种是master-slave(不推荐使用),一种是replica set,一种是 sharding模式。

mongodb的副本集主从,就是标准的故障自动转移实现方式,不须要人工介入。master节点当掉以后,会经过选举从副本集中找出新的master节点,而后引导其余节点链接到这个master。

mongodb的选举算法,采用的是bully。

主节点的变动,会存放在特定的系统表中。slave会定时拉取这些变动,并应用。从这种描述中也能够看出,mongodb在同步延迟或者单节点出问题的时候,会有丢失数据的可能。

总结

分布式是为了解决单机的容量问题,但它引入了一个新的问题,那就是数据同步。

数据同步要关注一致性,故障恢复以及时效性。

主要有两种数据须要同步。

  • 元数据信息
  • 真正的数据

对于元数据信息,目前比较主流的作法,能够参考使用raft协议进行数据分发。到了真正的数据同步方面,raft协议的效率仍是有些低的,因此会广泛采用异步复制的方式。

在这种状况下,异步复制列表,就成了关键的元数据信息,集群须要维护这些节点的状态。最坏的状况下,异步复制节点所有不可用,master会本身运行在很是不可信的环境下。

为了增长数据分配的灵活性,这些复制单元多会针对于sharding分片进行操做,由此带来的,就是meta信息的爆炸。

分布式系统这么多,但并无一个可以统一的模式。有意思的是,即便是最低效的分布式系统,也有大批的追随者。不信?看看BTC的走势就知道了。

做者简介:小姐姐味道 (xjjdog),一个不容许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不同的味道。个人我的微信xjjdog0,欢迎添加好友,进一步交流。

相关文章
相关标签/搜索