当前位置: 首页 > 科技观察

分布式系统如何同步?把人折磨死!

时间:2023-03-13 16:37:52 科技观察

本文转载自微信公众号“小姐姐的味道”,作者小姐姐养的狗。转载本文请联系味觉小姐公众号。分布式系统通过数据冗余来保证数据安全。编写分布式系统,绕不开的一道坎就是数据同步。同步,这两个字已经折磨死了很多人。它是同步的还是异步的?是推还是拉?谁是主人,谁是奴隶?离线时会发生什么,在线时会发生什么?中心化还是点对点节点?设计师。下面我们就来看看几款主流的存储服务是如何解决数据同步问题的。MySQL是如何做主从同步的?mysql的主服务器称为master,从服务器称为slave。masterserver会在binlog中记录变化,slave会通过独立的线程复制这些记录,然后replay。binlog的格式分为statement、row、mixed三种。statement将修改后的SQL语句写入binlog,对准确性会有一定的影响。row将每条记录的变化写入binlogmixed以上两者的组合。MySQL会判断什么时候用statement,什么时候用row。由于是异步线程去复制,slave容易出现延迟。当master不幸宕机时,会造成数据延迟丢失。为了解决异步复制的问题,MySQL在5.5版本之后引入了半同步复制(semisync)的概念。半同步介于异步和全同步之间。master执行完事务后,并不直接返回,而是等待至少有一个slave写入成功后才返回。由于需要和至少一个slave进行交互,所以相对于异步复制来说,性能上肯定会有很大的损失。当然,全量复制模式是等待所有从节点完成复制,最安全,但效率最低。从概念上讲,只有一个slave的半复制是全复制。5.7之后,mysql实现了组复制(groupreplication)协议。支持单主模式和多主模式,但在同一个组中,不允许同时存在。听起来很神奇,其实是通过paxos协议实现的。Kafka是如何进行副本同步的?由于kafka是一个消息队列,所以不需要考虑随机删除和随机更新的问题,只关注写入的问题。从结构上来说,Kafka的同步单元是非常去中心化的:Kafka有多个topic,每个topic又分为多个partition,根据partition做副本。主分区称为领导者,1-n个副本称为跟随者。生产者发送消息时,需要先找到分区的领导者,然后将数据发送给它。follower只是作为backup存在的,以便在主分区出现问题的时候可以上去。Kafka的主从同步称为ISR(InSyncReplica)机制。什么时候消息发送成功?它还取决于ack的发送级别。0表示异步发送,即使消息发送成功,写入1个leader的主副本,即使发送成功-1,当leader发送并且ISR中的所有副本需要回复ack0和1时,kafka丢失可能消息。在-1的情况下,还需要保证至少有一个followercommit成功,以保证消息安全。如果follower追不上leader,它将被从ISR列表中移除。没错,直接去掉了。当ISR为空时,Kafka分区和单机没有区别,所以Kafka提供了min.insync.replicas参数来指定最小ISR。ISR不满足怎么办?当然kafka是不会丢消息的,因为此时生产者提交失败,消息根本无法进入系统。所有副本都不可用怎么办?这时候,永不可用的副本之间的分区数据复制是通过followerpull,即拉取的方式来获取的。Redis的主从复制redis是内存kv数据库,速度远超其他数据库。理论上,主从同步更容易。但是在大流量、高QPS下,主从复制还是会出问题。redisslave连接上后,会先进行一次全量同步。它会向master发送psync命令,然后master执行bgsave生成一个rdb文件。全同步就是将rdb快照文件复制到slave上。完整副本中间出现的数据怎么办?它必须被缓存。master会开辟一个buffer,然后记录全量复制过程中产生的新数据,全量同步完成后填入增量数据。slave断开连接后,不需要每次都进行全同步。为了配合增量,引入了复制偏移量(offset)、复制积压缓冲区(replicationbacklogbuffer)和运行ID(run_id)三个概念。可以看出它是用来标识slave的,还有它的拷贝位置和buffer。同步之后,你可以随时使用psync进行复制。依旧是异步复制。可见redis的主从复制一致性对内存的依赖很大,水平很弱。但它很快。很多问题都可以很快解决,所以应用场景也不同。ElasticSearch主从复制es是一个基于lucene的搜索引擎,数据节点会包含多个索引。每个索引包含多个分片,每个分片包含多个副本。从上面的描述来看,这些概念和Kafka高度相似,es的复制单元是分片。es的数据还是先写到master上,同时也维护了一个同步的slave列表(InSyncAllocationIds)。当然,黄色和红色状态的副本不在这个列表中。master需要等这些正常的replica都写完了再返回给client,所以一致性级别比较高,因为它的slave节点需要参与读操作,是一个近实时的系统。既然是数据库,还是会有删除和更新的。translog相当于wallog,保证掉电数据安全,与其他rdbms例程一致。Cassandra集群模式cassandra是一个非常有名的CAP理论和实践数据库,更像是一个AP数据库,目前在db-engines.com的排名还是很高的。数据存储是表的概念,一个表可以存储在多台机器上。它的分区是按partitionkey设计的,数据分布非常依赖于hash函数。如果某个节点出现问题怎么办?它需要一致性哈希的支持。卡桑德拉非常有趣。它的复制(replicas)不像其他的主备数据。它更像是多个主数据,同时对外提供服务。当检查点丢失时,不需要进行主备倒换。为什么能达到这个目的?因为cassandra追求的是最终一致性。由于副本的存在,分布式系统不可避免地需要异步或同步复制。那么复制到什么程度才合适呢?Quorum的R+W是一种权衡策略。quorum=(sum_of_replication_factors/2)+1是什么意思?考虑你有5个抽屉,随机往里放W个球,你需要多少R次才能取出一个球。如果里面放1个球,每次都需要打开5次才能做出正确的判断,此时R=5,W=1;当你放2个球的时候,你只需要打开4次就可以了;如果你放入5个球,你只需要读一次。当R+W>N时,属于强一致性;当R+W<=N时,属于最终一致性。有趣的是,cassandra中的集群信息,即元信息,是使用gossip(push-pull-gossip)传递的。MongoDB主从复制mongodb有三种数据冗余方式。一种是master-slave(不推荐),一种是replicaset,还有一种是sharding模式。MongoDB的副本集master-slave是一种标准的自动故障转移实现,无需人工干预。主节点宕机后,会通过选举从副本集中寻找新的主节点,然后引导其他节点连接到主节点上。mongodb的选举算法采用bully。主节点的变化将存储在特定的系统表中。从站将定期拉取这些更改并应用它们。从这个描述也可以看出,mongodb在同步延迟或者单节点故障时,可能会丢失数据。总结分布式是为了解决单机的容量问题,但是引入了一个新的问题,那就是数据同步。数据同步应注重一致性、故障恢复和及时性。主要有两种数据需要同步。元数据信息Realdata对于元数据信息,目前主流的做法可以参考使用raft协议进行数据分发。真正的数据同步时,raft协议的效率还是有些低,所以一般采用异步复制。在这种情况下,异步复制列表成为关键的元数据信息,集群需要维护这些节点的状态。在最坏的情况下,所有异步复制节点都不可用,master将在一个非常不受信任的环境中运行自己。为了增加数据分配的灵活性,这些复制单元大多对分片进行操作,导致元信息爆炸。分布式系统那么多,却没有一个统一的模型。有趣的是,即使是最低效的分布式系统也有大量的追随者。不相信我吗?看看BTC的走势就知道了。作者简介:品味小姐姐(xjjdog),一个不允许程序员走弯路的公众号。专注于基础架构和Linux。十年架构,每天百亿流量,与你探讨高并发世界,给你不一样的滋味。