目前随着微服务建设的普及,跨系统数据交互越来越多,跨系统数据一致性问题越来越多著名的。如何有效保证跨系统的数据一致性呢?本文旨在总结沉淀工作中的问题解决经验,梳理解决跨系统数据不一致问题的经验方法。1、为什么会出现跨系统数据一致性问题?说到数据一致性,我们很容易想到数据库中的事务操作。事务的原子性和持久性可以保证在一个事务内,对多条数据进行操作,要么全部成功,要么全部失败。这样,在一个系统内部,我们自然可以使用数据库事务来保证数据的一致性。但是在今天的微服务中,当一个操作涉及到跨多个系统的多个数据库时,没有办法用单一的数据库事务来解决。另一种常见的情况是有业务端和用户端(业务端负责生产数据,用户端负责展示数据)等依赖情况的系统服务,这就需要数据同步到确保跨系统服务的数据一致性。采用什么样的数据同步方式来保证数据应用的及时性非常重要。2、一致性问题难点分析为了更好的描述和理解问题,我们用一个案例来说明:假设有一个订单系统和一个库存系统,在实际业务中订单的创建会伴随着减少库存。两个系统都部署为微服务,它们的应用数据也存储在独立的数据库中,两个系统通过网络进行通信。2.1CAP原理CAP指的是Consistency(一致性)、Availability(可用性)、Partitiontolerance(分区容错)。放弃A(availability)保证CP具体表现在发生通信故障后,应用程序会进入阻塞状态,不断尝试恢复与库存系统的通信,直到所有数据处理完成。这种方案是先保证数据的完整性,但是这种方案的用户体验极差,因为用户会一直处于等待状态,直到所有的操作都完成。CAP本身是互斥的,三者中只能选二。CA、AP、CP都有各自的应用场景,要根据实际情况进行选择。因为CA没有考虑partitiontolerance,所以它的所有操作都需要在同一个进程中完成(也就是我们常说的单体应用);因为AP放弃了数据一致性,适合对数据要求不高但强调用户体验的项目。如博客、新闻资讯等;CP则相反,放弃了可用性,适用于对数据要求高的交易系统,如银行交易、电商订单交易等,即使用户长时间等待,也必须保证数据的完整性和可靠性保证。如果为了用户体验而完全放弃数据一致性,那么在实际项目中应用CAP原则对于互联网应用来说是不可取的。毕竟,数据是应用的基础。那么如何解决呢?保证最终一致性的措施有很多,主要包括:分布式事务和TCC一致性方案。MySQL其实有一个两阶段提交的分布式事务方案(MySQLXA),但是这个方案存在严重的性能问题。例如,一个数据库事务和多个数据库之间的XA事务性能可能存在10倍的差异。另外,在XA事务处理过程中,会长期占用锁资源,所以一开始没有考虑这个方案。这里主要讨论TCC一致性方案。2.2TCC一致性方案TCC是一种数据一致性方案。我们将原来的接口分为三个接口:Try接口用于检查数据和预留业务资源。Confirm接口用于确认实际业务操作和更新业务资源。Cancel接口是指释放Try接口预留的资源。在TCC中,将分布式处理过程分为两个阶段:1.Try是第一阶段,用于尝试和锁定资源;2.如果资源锁定成功,第二阶段开始确认并提交,完成数据操作;3.如果资源锁失败,第二阶段会Cancel回滚数据;TCC实施过程中应注意哪些事项?1)在Try阶段做尽可能多的事情,在Try阶段完成大部分业务逻辑,因为TCC最初的设计是相信Confirm或Cancel一定要成功,所以不要在Try中包含任何业务代码或远程通信第二阶段,只通过最简单的代码释放冻结的资源。2)保证Confirm或Cancel执行成功。如果在Confirm或Cancel执行过程中出现错误,具体应用会不断重试执行操作,尽量确保执行成功。在这个过程中,update语句可能会被执行多次,所以要注意代码的幂等性。3)在confirm或cancel执行失败的极小概率下,多次重试后confirm或cancel都会失败,数据最终会不一致,这就需要开发额外的数据完整性验证程序进行补救或通过人工补录。TCC归根结底是一种理论设计,需要厂商实现相应的框架来支持。Java开源领域比较知名的TCC框架有:ByteTCC、Hmily、Tcc-transaction和Seata。三、有效的数据同步解决方案实际问题描述:我们还是沿用之前的案例场景,需要将数据从订单系统同步到库存系统。解决数据一致性常用的三种数据同步方案:实时同步、定时同步、手动同步。3.1实时同步实时同步可以从数据库和应用处理两个层面来解决。3.1.1在数据库层面,一般采用数据库的数据同步,采用主从方案。当主(main)数据库中的数据发生变化时,这些变化会实时同步到从(slave)数据库中。优点:横向扩展数据库的负载能力。容错、高可用、Failover(故障切换)/高可用数据备份。如何实现主从一致性关于MySQL主从复制,主要同步的是binlog日志,涉及三个线程,一个运行在master节点上(logdump线程),另外两个(I/O线程,SQL线程)运行在从节点上,如下图所示:(1)主节点二进制日志转储线程当从节点连接到主节点时,主节点会创建一个日志转储线程发送binlog的内容.当读取binlog中的操作时,该线程会将binlog锁定在master节点上。当读取完成后,会释放锁,然后再发送给从节点。(2)Slave节点I/O线程在Slave节点上执行startslave命令后,Slave节点会创建一个I/O线程连接Master节点,请求Master库中更新的binlog。I/O线程收到master节点binlogdump进程发送的update后,保存在本地relay-log(中继日志)中。(3)Slave节点SQL线程SQL线程负责读取relaylog中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。3.1.2API调用一个业务数据操作需要调用多个API来实现数据的实时同步。缺点很明显,主要表现在:1)处理时间长,需要串行调用多个API等待响应,用户体验差;2)可能有一定几率出现数据不一致(个别API调用出错,无响应等)。3.2异步和同步3.2.1异步消息队列MessageQueue(MQ),消息队列中间件MQ通过消息的发送和接收分离实现了应用程序的异步和解耦,同时MQ屏蔽了底层复杂的通信协议,并在应用层定义了一套更简单的通信协议。应用MQ的优势:解耦、削峰、数据分布。在业务系统设计中,我们经常会有一个平台系统A,它关联并同步了很多系统(系统B、C、D等)的对接。使用MQ可以很好的解决系统对接和数据同步的问题,同时对接系统的稳定性也可以忽略不计。3.2.2定时同步定时任务在系统中并不少见,其主要用途是在处理数据或定时执行某些操作时使用,例如定时关闭订单或定时备份。常见的定时任务分为两种:1)第一种:定时执行,保证同步,校准数据。例如:每分钟执行一次,每天执行一次。2)第二种:延迟多久执行,即动作发生后,任务会在预定时间后执行多久,如:15分钟后关闭订单支付状态,关闭订单并24小时后放出库存等。4.应用经验总结技术落地还需要解决实际问题。应用场景很重要。不要仅仅为了技术而依赖技术。技术归根结底还是服务于应用场景和产业落地。在软件设计的过程中,没有必要刻意套用一个看起来高大上的解决方案。需要引入时,需要考虑开发、维护的成本,以及相应性能提升的性价比,否则得不偿失。(1)任何架构方案都是不断演进的。任何数据同步本身都没有好坏之分,都有自己适合的应用场景。(2)架构的目的是为了解决业务问题。能够解决当前问题并且易于扩展和维护的架构解决方案就是优秀的架构。随着互联网的高速发展,跨系统数据一致性应用的需求将越来越迫切,跨区域、跨系统场景的真正痛点也将越来越清晰。希望我们对跨系统数据一致性的研究和探索,能给大家一个思路和参考。希望今天的讲解对大家有所帮助,谢谢!
