前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于分布式系统数据一致性的那些事(二)

关于分布式系统数据一致性的那些事(二)

作者头像
Bruce Li
发布2020-06-15 11:34:14
5160
发布2020-06-15 11:34:14
举报

接上一篇文章(关于分布式系统数据一致性的那些事),继续更新一些关于分布式系统数据一致性方面的知识。

1

之前写过一篇文章(如何不宕机实现数据库迁移),介绍如何用“双写法”实现数据迁移。从根本上讲,这个方法的关键在于,service需要把一条数据同时写入两个数据库并且确保数据一致性。当时,采用的方法是spring的ChainedTransactionManager,但是理论上讲,这种方法并不能完全确保数据一致,有可能出现写第一个数据库commit,写第二个数据库rollback的情况。

基于此,如果我们要保证数据强一致性,则可以采用XA分布式事务(两阶段提交)。两阶段提交除了数据库本身(扮演participant的角色),还增加了一个coordinator的角色(also known as:transaction manager),用以保存各个participants是否提交等状态信息。协调者可以是和应用程序同一个进程(如tomcat),也可以是单独的一个进程或服务(如MSDTC)。回到编码实现层面,java developer可以直接使用spring JTA,其对分布式事务有一个很好的封装。

但是,大家可能也都知道,两阶段提交有一些显著的问题,如性能差和coordinator单点故障。coordinator单点故障这个问题,也许我们可以通过一些高可用的方案来解决,比如后面会提到的共识算法。但是性能差的问题,由于“两阶段”提交的本质,个人认为不容易解决,除非我们采用其它方案,放弃两阶段提交,后面会提到一个典型的例子。

2

接下来,我们看一个典型例子:一个银行转账系统,用户A转100元给用户B。

如果所有用户信息都放在一个数据库的一张表里面,则可以直接利用单机数据库的事务(ACID)来保证这次转账正常work。

但是,对于某些系统,由于用户量太大,我们需要分库分表,把用户信息这张表拆分成几张表来存(用户A和用户B存在于两个不同的数据库),那么,在这种情况下,要完成这一次转账操作并且确保操作的原子性,则需要分布式事务来保证,这就和上面数据库迁移的场景就有些类似了。所以,同样的,一种方案是,采用XA分布式事务。

然而,对于用户量巨大的系统,XA分布式事务一般来说都不是首选的方案,我们常常会考虑其它的方案,以提高系统的性能、高可用性、容错性和用户使用体验等。在《Designing Data-Intensive Application》这本书里面,提到了一种解决这个问题的方案,如下:

这个方案,规避了两阶段提交的使用;但是,不像分布式事务的强一致性保证,它只能保证最终一致性。同时,书中提到了关于最终一致性的一个解释:一致性包括“时效性”和“正确性”两个方面,“正确性”是都必须保证的,最终一致性只是在“时效性”方面会差一点,导致的现象可能是,在某些情况下,用户A账户的钱先扣,用户B账户的后扣。“正确性”如何保证呢?使用唯一requst ID来严格保证一次转账请求只会被执行一次,抑制重复处理,保证整个端到端的幂等性。

其实这类方案的理论原则就是之前提到过的:at least once delivery + idempotent + auto automatic dead letter reprocessing。

3

一般来讲,当数据量达到一定级别时,我们可以采用partition的方式(分库分表等)来避免单机处理能力限制;为了避免单点故障,我们可以采用replication的方式来保证高可用。例如,传统的数据库,一般都有master-slave模式架构,master负责读写数据,slave负责备份,master发生故障时,可以切换到slave,继续提供服务,但是这种切换很多都是手动的,并且slave可能会有丢失一部分master上写入的数据的风险。其实,对于一些大型的数据系统集群,依赖于手动容错切换是不现实的,我们往往需要依赖“能够自动切换”的分布式容错共识算法(consensus algorithm)。

大家可能都知道,一些常见的开源组件,比如:zookeeper,rabbitmq,etcd等,都支持集群部署以保证高可用性(high availability),那么,它们都是怎么实现节点故障容错并保证数据一致性的呢?其实,它们都实现了一种分布式容错共识算法(zab,raft,Viewstamped Replication,paxos等),zookeeper实现的是zab算法,rabbitmq和etcd实现的是raft算法。这些算法的关键点都是基于法定人数(quorum)的投票机制,投票会应用在领导人选举和日志复制(确保某条日志commit)的时候,quorum的现实依据就是少数服从多数原则。

但是,另外一个非常流行的开源组件kafka,采用了不同于quorum的一种机制ISR(in-sync replicas)来达成共识。在容错性方面,如果要容忍2个节点错误,quorum需要5个节点,而Kafka只需要3个节点,基于这种配置,kafka的成本更低,并且吞吐量更高(quorum需要复制日志到5个节点,而kafka只需要3个节点),这也是kafka给出的为什么没有采用quorum的原因。

同样的,也有一些关系型数据库(YugabyteDB)开始采用分布式容错共识算法来实现高可用,see:https://blog.yugabyte.com/how-does-the-raft-consensus-based-replication-protocol-work-in-yugabyte-db/

References

  • https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/boot-features-jta.html
  • http://kafka.apache.org/documentation/#replication
  • https://github.com/huazailmh/ddia
  • https://github.com/huazailmh/raft-zh_cn/blob/master/raft-zh_cn.md
  • https://www.postgresql.org/docs/9.2/warm-standby.html#SYNCHRONOUS-REPLICATION
  • https://blog.yugabyte.com/how-does-consensus-based-replication-work-in-distributed-databases/
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 天马行空布鲁斯 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档