专栏首页天马行空布鲁斯关于分布式系统数据一致性的那些事(二)

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

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

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/

本文分享自微信公众号 - 天马行空布鲁斯(gh_2feda5c053bd),作者:huazailmh

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-06-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • liquibase和flyway中分布式锁实现的区别?

    大家可能都知道,锁的存在本质上是为了解决共享资源互斥访问的问题,为了解决这个问题,在单机系统中(一个进程),很多开发语言都提供了锁的特性,比如说java的syn...

    Bruce Li
  • 空谈分布式系统设计之幂等性

    在之前的文章,有多次提到转账系统这个案例,由于这个案例太典型了,很多大学教授数据库事务的时候就是用的这个案例。

    Bruce Li
  • 如何不宕机实现数据库迁移

    由于业务的扩展或者其他原因,常常会有迁移系统数据库的场景,对于有大量用户7*24小时不间断使用的系统,如何不宕机实现数据库迁移,这是个很有挑战的话题。

    Bruce Li
  • 搜索(3)

    mathor
  • 巨杉数据库宣布获得1000万美元B轮融资,DCM领投

    <数据猿导读> 在当前的资本寒冬之下,国内领先的新一代分布式数据库厂商SequoiaDB巨杉数据库宣布获得世界顶级投资机构DCM领投的B轮融资1000万美元,A...

    数据猿
  • 数据库PostrageSQL-查看锁

    监控数据库活动的另外一个有用的工具是pg_locks系统表。这样就允许数据库管理员查看在锁管理器里面未解决的锁的信息。例如,这个功能可以被用于:

    cwl_java
  • 图数据库调研

    更好,更快速的查询和分析:图数据库为查询相关数据(无论大小)提供了卓越的性能。 图模型提供了固有的索引数据结构,因此它不需要为给定条件的查询加载或接触不相关的数...

    宗文
  • 腾讯云优惠券和优惠促销活动整理2019

    随着互联网巨头进入云计算市场,国内的云服务器商家也开始新一轮洗牌。其中具有代表性的国内商家有阿里云、腾讯云、华为云等商家。这些商家搅和云市场均采用亏本式促销活动...

    Miracler
  • 这效果碉堡了!Bitmap粒子“爆炸”效果

    内容来源:作者 | 张风捷特烈,链接 | https://www.jianshu.com/p/12184d861646

    IT大咖说
  • Android粒子篇之Bitmap像素级操作

    张风捷特烈

扫码关注云+社区

领取腾讯云代金券