当前位置: 首页 > news >正文

重庆建设工程招标造价信息网站网站建设项目如何敏捷

重庆建设工程招标造价信息网站,网站建设项目如何敏捷,音乐网站如何做,免费推广网站排名随着业务的快速发展、业务复杂度越来越高#xff0c;传统单体应用逐渐暴露出了一些问题#xff0c;例如开发效率低、可维护性差、架构扩展性差、部署不灵活、健壮性差等等。而微服务架构是将单个服务拆分成一系列小服务#xff0c;且这些小服务都拥有独立的进程#xff0c;…随着业务的快速发展、业务复杂度越来越高传统单体应用逐渐暴露出了一些问题例如开发效率低、可维护性差、架构扩展性差、部署不灵活、健壮性差等等。而微服务架构是将单个服务拆分成一系列小服务且这些小服务都拥有独立的进程彼此独立很好地解决了传统单体应用的上述问题但是在微服务架构下如何保证事务的一致性呢 1、事务的介绍 1.1 事务 1.1.1 事务的产生 数据库中的数据是共享资源因此数据库系统通常要支持多个用户的或不同应用程序的访问并且各个访问进程都是独立执行的这样就有可能出现并发存取数据的现象这里有点类似Java开发中的多线程安全问题解决共享变量安全存取问题如果不采取一定措施会出现数据异常的情况。列举一个简单的经典案例比如用户用银行卡的钱还京东白条银行卡扣款成功了但是白条因为网络或者系统问题没有还款成功就会出大问题这时候我们就需要使用事务。 1.1.2 事务的概念 事务是数据库操作的最小工作单元是作为单个逻辑工作单元执行的一系列操作这些操作作为一个整体一起向系统提交要么都执行、要么都不执行事务是一组不可再分割的操作集合工作逻辑单元。例如在关系数据库中一个事务可以是一条SQL语句一组SQL语句或整个程序。 1.1.3 事务的特性 事务的四大特征主要是原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability这四大特征大家或多或少都听说过这里我做下简单介绍。 1原子性Atomicity事务内的操作要么全部成功要么全部失败不会在中间的某个环节结束。假如所有的操作都成功了那么事务是成功的只要其中任何一个操作失败那么事务会进行回滚回滚到操作最初的状态。 begin transaction; update activity_acount set money money-100 where name ‘小明’ update activity_acount set money money100 where name ‘小红’ commit transaction 2一致性Consistency事务的执行使数据从一个状态转换为另一个状态但是对于整个数据的完整性保持稳定。换一种说法是数据按照预期生效数据的状态是预期的状态。比如数据库在一个事务执行之前和执行之后都必须处于一致性状态如果事务执行失败那么需要自动回滚到原始状态也就是事务一旦提交其他事务查看到的结果一致事务一旦回滚其他事务也只能看到回滚前的状态。 举个通俗一点的例子小明给小红转账100元转账前和转账后数据是正确的状态这叫一致性如果小红没有收到100元或者收到金额少于100元这就出现数据错误就没有达到一致性。 3隔离性Isolation在并发环境中不同事务同事修改相同的数据时一个未完成的事务不会影响另外一个未完成的事务。 例如当多个用户并发访问数据库时比如操作同一张表时数据库为每一个用户开启的事务不能被其他事务的操作所干扰多个并发事务之间要相互隔离。 4持久性Durability事务一旦提交其修改的数据将永远保存到数据库中改变是永久性即使接下来数据库发生故障也不应对其有任何影响。 通俗一点例子A卡里有2000块钱当A从卡里取出500在不考虑外界因素干扰的情况下那么A的卡里只能剩1500。不存在取了500块钱后卡里一会剩1400一会剩1500一会剩1600的情况。 1.1.4 Mysql隔离级别 如果不考虑事务隔离性产生问题脏读、不可重复读和幻读。 Mysql隔离级别分为4种Read Uncommitted读取未提交的、Read Committed读取提交的、Repeatable Red可重复读、Serializaable串行化 1Read Uncommitted是隔离级别最低的一种事务级别。在这种隔离级别下一个事务会读到另一个事务更新后但未提交的数据如果另一个事务回滚那么当前事务读到的数据就是脏数据这就是脏读Dirty Read。 2在Read Committed隔离级别下一个事务可能会遇到不可重复读Non Repeatable Read的问题。不可重复读是指在一个事务内多次读同一数据在这个事务还没有结束时如果另一个事务恰好修改了这个数据那么在第一个事务中两次读取的数据就可能不一致。 3在Repeatable Read隔离级别下一个事务可能会遇到幻读Phantom Read的问题。幻读是指在一个事务中第一次查询某条记录发现没有但是当试图更新这条不存在的记录时竟然能成功并且再次读取同一条记录它就神奇地出现了就好象发生了幻觉一样。 4Serializable是最严格的隔离级别。在Serializable隔离级别下所有事务按照次序依次执行因此脏读、不可重复读、幻读都不会出现。虽然Serializable隔离级别下的事务具有最高的安全性但是由于事务是串行执行所以效率会大大下降应用程序的性能会急剧降低。如果没有特别重要的情景一般都不会使用Serializable隔离级别。 如果没有指定隔离级别数据库就会使用默认的隔离级别。在MySQL中如果使用InnoDB默认的隔离级别是Repeatable Read。 1.1.5 启动事务 在说明启动事务之前首先大家先想一下事务的传播行为事务传播行为用于解决两个被事务管理的方法互相调用问题。实际开发中将事务在service控制如以下方法调用存在传播行为如果serviceB也会产生一个代理对象同时也会进行事务管理执行serviceA和serviceB分别开启事务上边的serviceA中funA方法内容不处于一个事务中了。 class serviceA{ //此方法进行事务控制 funA(){ //在此方法中操作多个dao的操作处于一个事务中 userDao.insertUser(); orderDao.insertOrder(); //如果在这里调用另一个service的方法此时存在事务传播 serviceB.funB(); } } class serviceB{ funB(){ } } 解决方案就是在启动类上添加注解 EnableTransactionManagement在执行事务的方法上面使用 Transactionalisolation Isolation.DEFAULTpropagation Propagation.REQUIRED设置隔离界别与事务传播。默认就是REQUIRED。 Spring的声明式事务为事务传播定义了几个级别默认传播级别就是REQUIRED它的意思是如果当前没有事务就创建一个新事务如果当前有事务就加入到当前事务中执行。其余的还有 1.SUPPORTS表示如果有事务就加入到当前事务如果没有那也不开启事务执行。这种传播级别可用于查询方法因为SELECT语句既可以在事务内执行也可以不需要事务 2.MANDATORY表示必须要存在当前事务并加入执行否则将抛出异常。这种传播级别可用于核心更新逻辑比如用户余额变更它总是被其他事务方法调用不能直接由非事务方法调用 3.REQUIRES_NEW表示不管当前有没有事务都必须开启一个新的事务执行。如果当前已经有事务那么当前事务会挂起等新事务完成后再恢复执行 4.NOT_SUPPORTED表示不支持事务如果当前有事务那么当前事务会挂起等这个方法执行完成后再恢复执行 5.NEVER和NOT_SUPPORTED相比它不但不支持事务而且在监测到当前有事务时会抛出异常拒绝执行 6.NESTED表示如果当前有事务则开启一个嵌套级别事务如果当前没有事务则开启一个新事务。 1.2 本地事务 1.2.1 本地事务定义 定义在单体应用中我们执行多个业务操作使用的是同一个连接操作同一个数据库操作不同表一旦有异常我们可以整体回滚。 其实在介绍事务的定义中也介绍了一部分本地事务。本地事务通过ACID保证数据的强一致性在我们实际开发过程中我们或多或少都使用了本地事务。例如MySQL事务处理使用begin开始事务、rollback回滚事务、commit确认事务。事务提交后通过redo log记录变更通过undo log 在失败时进行回滚保证事务原子性。在我们日常使用Java语言开发时都接触过SpringSpring使用Transactional注解就可以实现事务功能前面我们也介绍过了。事实上Spring封装了这些细节在生成相关的Bean的时候在需要注入相关的带有Transactional注解的Bean时候用代理去注入在代理中开启提交/回滚事务。 1.2.2 本地事务的缺点 随着业务的高速发展面对海量数据例如上千万甚至上亿的数据查询一次所花费的时间会变长甚至会造成数据库的单点压力。因此我们就要考虑分库与分表方案了。分库与分表的目的在于减小数据库的单库单表负担提高查询性能缩短查询时间。这里我们先来看下单库拆分的场景。事实上分表策略可以归纳为垂直拆分和水平拆分。垂直拆分把表的字段进行拆分即一张字段比较多的表拆分为多张表这样使得行数据变小。一方面可以减少客户端程序和数据库之间的网络传输的字节数因为生产环境共享同一个网络带宽随着并发查询的增多有可能造成带宽瓶颈从而造成阻塞。另一方面一个数据块能存放更多的数据在查询时就会减少 I/O 次数。水平拆分把表的行进行拆分。因为表的行数超过几百万行时就会变慢这时可以把一张的表的数据拆成多张表来存放。水平拆分有许多策略例如取模分表时间维度分表等。这种场景下虽然我们根据特定规则分表了我们仍然可以使用本地事务。 但是库内分表仅仅是解决了单表数据过大的问题但并没有把单表的数据分散到不同的物理机上因此并不能减轻 MySQL 服务器的压力仍然存在同一个物理机上的资源竞争和瓶颈包括 CPU、内存、磁盘 IO、网络带宽等。对于分库拆分的场景它把一张表的数据划分到不同的数据库多个数据库的表结构一样。此时如果我们根据一定规则将我们需要使用事务的数据路由到相同的库中可以通过本地事务保证其强一致性。但是对于按照业务和功能划分的垂直拆分它将把业务数据分别放到不同的数据库中。这里拆分后的系统就会遇到数据的一致性问题因为我们需要通过事务保证的数据分散在不同的数据库中而每个数据库只能保证自己的数据可以满足 ACID 保证强一致性但是在分布式系统中它们可能部署在不同的服务器上只能通过网络进行通信因此无法准确的知道其他数据库中的事务执行情况。 此外不仅仅在跨库调用存在本地事务无法解决的问题随着微服务的落地中每个服务都有自己的数据库并且数据库是相互独立且透明的。那如果服务 A 需要获取服务 B 的数据就存在跨服务调用如果遇到服务宕机或者网络连接异常、同步调用超时等场景就会导致数据的不一致这个也是一种分布式场景下需要考虑数据一致性问题。 当业务量级扩大之后的分库以及微服务落地之后的业务服务化都会产生分布式数据不一致的问题。既然本地事务无法满足需求因此就需要分布式事务。 2、分布式事务定义 分布式事务定义我们可以简单地理解它就是为了保证不同数据库的数据一致性的事务解决方案。这里我们有必要先来了解下 CAP 原则和 BASE 理论。CAP 原则是 Consistency一致性、Availablity可用性和 Partition-tolerance分区容错性的缩写它是分布式系统中的平衡理论。在分布式系统中一致性要求所有节点每次读操作都能保证获取到最新数据可用性要求无论任何故障产生后都能保证服务仍然可用分区容错性要求被分区的节点可以正常对外提供服务。事实上任何系统只可同时满足其中二个无法三者兼顾。对于分布式系统而言分区容错性是一个最基本的要求。那么如果选择了一致性和分区容错性放弃可用性那么网络问题会导致系统不可用。如果选择可用性和分区容错性放弃一致性不同的节点之间的数据不能及时同步数据而导致数据的不一致。 此时BASE 理论针对一致性和可用性提出了一个方案BASE 是 Basically Available基本可用、Soft-state软状态和 Eventually Consistent最终一致性的缩写它是最终一致性的理论支撑。简单地理解在分布式系统中允许损失部分可用性并且不同节点进行数据同步的过程存在延时但是在经过一段时间的修复后最终能够达到数据的最终一致性。BASE 强调的是数据的最终一致性。相比于 ACID 而言BASE 通过允许损失部分一致性来获得可用性。 现在比较常用的分布式事务解决方案包括强一致性的两阶段提交协议三阶段提交协议以及最终一致性的可靠事件模式、补偿模式TCC 模式。 3、分布式事务-强一致性解决方案 3.1 二阶段提交协议 在分布式系统中每个数据库只能保证自己的数据可以满足 ACID 保证强一致性但是它们可能部署在不同的服务器上只能通过网络进行通信因此无法准确的知道其他数据库中的事务执行情况。因此为了解决多个节点之间的协调问题就需要引入一个协调者负责控制所有节点的操作结果要么全部成功要么全部失败。其中XA 协议是一个分布式事务协议它有两个角色事务管理者和资源管理者。这里我们可以把事务管理者理解为协调者而资源管理者理解为参与者。 XA 协议通过二阶段提交协议保证强一致性。 二阶段提交协议顾名思义它具有两个阶段第一阶段准备第二阶段提交。这里事务管理者协调者主要负责控制所有节点的操作结果包括准备流程和提交流程。第一阶段事务管理者协调者向资源管理者参与者发起准备指令询问资源管理者参与者预提交是否成功。如果资源管理者参与者可以完成就会执行操作并不提交最后给出自己响应结果是预提交成功还是预提交失败。第二阶段如果全部资源管理者参与者都回复预提交成功资源管理者参与者正式提交命令。如果其中有一个资源管理者参与者回复预提交失败则事务管理者协调者向所有的资源管理者参与者发起回滚命令。举个案例现在我们有一个事务管理者协调者三个资源管理者参与者那么这个事务中我们需要保证这三个参与者在事务过程中的数据的强一致性。首先事务管理者协调者发起准备指令预判它们是否已经预提交成功了如果全部回复预提交成功那么事务管理者协调者正式发起提交命令执行数据的变更。 注意的是虽然二阶段提交协议为保证强一致性提出了一套解决方案但是仍然存在一些问题。其一事务管理者协调者主要负责控制所有节点的操作结果包括准备流程和提交流程但是整个流程是同步的所以事务管理者协调者必须等待每一个资源管理者参与者返回操作结果后才能进行下一步操作。这样就非常容易造成同步阻塞问题。其二单点故障也是需要认真考虑的问题。事务管理者协调者和资源管理者参与者都可能出现宕机如果资源管理者参与者出现故障则无法响应而一直等待事务管理者协调者出现故障则事务流程就失去了控制者换句话说就是整个流程会一直阻塞甚至极端的情况下一部分资源管理者参与者数据执行提交一部分没有执行提交也会出现数据不一致性。此时读者会提出疑问这些问题应该都是小概率情况一般是不会产生的是的但是对于分布式事务场景我们不仅仅需要考虑正常逻辑流程还需要关注小概率的异常场景如果我们对异常场景缺乏处理方案可能就会出现数据的不一致性那么后期靠人工干预处理会是一个成本非常大的任务此外对于交易的核心链路也许就不是数据问题而是更加严重的资损问题。 3.2 三阶段提交协议 二阶段提交协议诸多问题因此三阶段提交协议就要登上舞台了。三阶段提交协议是二阶段提交协议的改良版本它与二阶段提交协议不同之处在于引入了超时机制解决同步阻塞问题此外加入了预备阶段尽可能提早发现无法执行的资源管理者参与者并且终止事务如果全部资源管理者参与者都可以完成才发起第二阶段的准备和第三阶段的提交。否则其中任何一个资源管理者参与者回复执行失败或者超时等待那么就终止事务。总结一下三阶段提交协议包括第一阶段预备第二阶段准备第二阶段提交。 这里可能大家有点蒙我再详细讲解一下三阶段提交的整体流程。 3PC主要是为了解决两阶段提交协议的单点故障问题和缩小参与者阻塞范围。 引入参与节点的超时机制之外3PC把2PC的准备阶段分成事务询问该阶段不会阻塞和事务预提交,则三个阶段分别为CanCommit、PreCommit、DoCommit。 1第一阶段CanCommit 阶段 类似于2PC的准备第一阶段。协调者向参与者发送commit请求参与者如果可以提交就返回Yes响应否则返回No响应。 1.事务询问 协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。 2.响应反馈 参与者接到CanCommit请求之后正常情况下 如果其自身认为可以顺利执行事务则返回Yes响应并进入预备状态。 否则反馈No。 2第二阶段PreCommit 阶段 协调者根据参与者的反应情况来决定是否可以记性事务的PreCommit操作。根据响应情况有以下两种可能 如果响应Yes则 1.发送预提交请求 协调者向参与者发送PreCommit请求并进入Prepared阶段。 2.事务预提交 参与者接收到PreCommit请求后会执行事务操作并将undo和redo信息记录到事务日志中。 3.响应反馈 如果参与者成功的执行了事务操作则返回ACK响应同时开始等待最终指令。 假如有任何一个参与者向协调者发送了No响应或者等待超时之后协调者都没有接到参与者的响应那么就执行事务的中断。则有 1.发送中断请求 协调者向所有参与者发送abort请求。 2.中断事务 参与者收到来自协调者的abort请求之后或超时之后仍未收到协调者的请求执行事务的中断。 3第三阶段doCommit 阶段 该阶段进行真正的事务提交也可以分为执行提交和中断事务两种情况。 如果执行成功则有如下操作 1.发送提交请求 协调者接收到参与者发送的ACK响应那么它将从预提交状态进入到提交状态。 并向所有参与者发送doCommit请求。 2.事务提交 参与者接收到doCommit请求之后执行正式的事务提交。 并在完成事务提交之后释放所有事务资源。 3.响应反馈 事务提交完之后向协调者发送ACK响应。 4.完成事务 协调者接收到所有参与者的ACK响应之后完成事务。 协调者没有接收到参与者发送的ACK响应可能是接受者发送的不是ACK响应也可能响应超时那么就会执行中断事务注意这是没有收到二段段最后的ACK这里要理解清楚。则有如下操作 1.发送中断请求 协调者向所有参与者发送abort请求 2.事务回滚 参与者接收到abort请求之后利用其在阶段二记录的undo信息来执行事务的回滚操作 并在完成回滚之后释放所有的事务资源。 3.反馈结果 参与者完成事务回滚之后向协调者发送ACK消息 4.中断事务 协调者接收到参与者反馈的ACK消息之后执行事务的中断。 最关键的在doCommit阶段如果参与者无法及时接收到来自协调者的doCommit或者rebort请求时1、协调者出现问题2、协调者和参与者出现网络故障会在等待超时之后会继续进行事务的提交。其实这个应该是基于概率来决定的当进入第三阶段时说明参与者在第二阶段已经收到了PreCommit请求那么协调者产生PreCommit请求的前提条件是他在第二阶段开始之前收到所有参与者的CanCommit响应都是Yes。一旦参与者收到了PreCommit意味他知道大家其实都同意修改了所以一句话概括就是当进入第三阶段时由于网络超时等原因虽然参与者没有收到commit或者abort响应但是它有理由相信成功提交的几率很大 三阶段提交协议很好的解决了二阶段提交协议带来的问题是一个非常有参考意义的解决方案。但是极小概率的场景下可能会出现数据的不一致性。因为三阶段提交协议引入了超时机制一旦参与者无法及时收到来自协调者的信息之后他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。但是这种机制也会导致数据一致性问题因为由于网络原因协调者发送的abort响应没有及时被参与者接收到那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。 4、分布式事务-最终一致性解决方案 4.1 TCC模式 二阶段提交协议和三阶段提交协议很好的解决了分布式事务的问题但是在极端情况下仍然存在数据的不一致性此外它对系统的开销会比较大引入事务管理者协调者后比较容易出现单点瓶颈以及在业务规模不断变大的情况下系统可伸缩性也会存在问题。注意的是它是同步操作因此引入事务后直到全局事务结束才能释放资源性能可能是一个很大的问题。因此在高并发场景下很少使用。因此需要另外一种解决方案TCC 模式。注意的是很多读者把二阶段提交等同于二阶段提交协议这个是一个误区事实上TCC 模式也是一种二阶段提交。 TCC 模式将一个任务拆分三个操作Try、Confirm、Cancel。假如我们有一个 func() 方法那么在 TCC 模式中它就变成了 tryFunc()、confirmFunc()、cancelFunc() 三个方法。 在 TCC 模式中主业务服务负责发起流程而从业务服务提供 TCC 模式的 Try、Confirm、Cancel 三个操作。其中还有一个事务管理器的角色负责控制事务的一致性。例如我们现在有三个业务服务交易服务库存服务支付服务。用户选商品下订单紧接着选择支付方式进行付款然后这笔请求交易服务会先调用库存服务扣库存然后交易服务再调用支付服务进行相关的支付操作然后支付服务会请求第三方支付平台创建交易并扣款这里交易服务就是主业务服务而库存服务和支付服务是从业务服务。 我们再来梳理下TCC 模式的流程。第一阶段主业务服务调用全部的从业务服务的 Try 操作并且事务管理器记录操作日志。第二阶段当全部从业务服务都成功时再执行 Confirm 操作否则会执行 Cancel 逆操作进行回滚。 注意我们要特别注意操作的幂等性。幂等机制的核心是保证资源唯一性例如重复提交或服务端的多次重试只会产生一份结果。支付场景、退款场景涉及金钱的交易不能出现多次扣款等问题。事实上查询接口用于获取资源因为它只是查询数据而不会影响到资源的变化因此不管调用多少次接口资源都不会改变所以是它是幂等的。而新增接口是非幂等的因为调用接口多次它都将会产生资源的变化。因此我们需要在出现重复提交时进行幂等处理。 那么如何保证幂等机制呢事实上我们有很多实现方案。其中一种方案就是常见的创建唯一索引。在数据库中针对我们需要约束的资源字段创建唯一索引可以防止插入重复的数据。但是遇到分库分表的情况是唯一索引也就不那么好使了此时我们可以先查询一次数据库然后判断是否约束的资源字段存在重复没有的重复时再进行插入操作。注意的是为了避免并发场景我们可以通过锁机制例如悲观锁与乐观锁保证数据的唯一性。这里分布式锁是一种经常使用的方案它通常情况下是一种悲观锁的实现。但是很多人经常把悲观锁、乐观锁、分布式锁当作幂等机制的解决方案这个是不正确的。除此之外我们还可以引入状态机通过状态机进行状态的约束以及状态跳转确保同一个业务的流程化执行从而实现数据幂等。 4.2 补偿模式 我们提到了重试机制。事实上它也是一种最终一致性的解决方案我们需要通过最大努力不断重试保证数据库的操作最终一定可以保证数据一致性如果最终多次重试失败可以根据相关日志并主动通知开发人员进行手工介入。注意的是被调用方需要保证其幂等性。重试机制可以是同步机制例如主业务服务调用超时或者非异常的调用失败需要及时重新发起业务调用。重试机制可以大致分为固定次数的重试策略与固定时间的重试策略。除此之外我们还可以借助消息队列和定时任务机制。消息队列的重试机制即消息消费失败则进行重新投递这样就可以避免消息没有被消费而被丢弃例如 JMQ 可以默认允许每条消息最多重试 多少 次每次重试的间隔时间可以进行设置。定时任务的重试机制我们可以创建一张任务执行表并增加一个“重试次数”字段。这种设计方案中我们可以在定时调用时获取这个任务是否是执行失败的状态并且没有超过重试次数如果是则进行失败重试。但是当出现执行失败的状态并且超过重试次数时就说明这个任务永久失败了需要开发人员进行手工介入与排查问题。 除了重试机制之外也可以在每次更新的时候进行修复。例如对于社交互动的点赞数、收藏数、评论数等计数场景也许因为网络抖动或者相关服务不可用导致某段时间内的数据不一致我们就可以在每次更新的时候进行修复保证系统经过一段较短的时间的自我恢复和修正数据最终达到一致。需要注意的是使用这种解决方案的情况下如果某条数据出现不一致性但是又没有再次更新修复那么其永远都会是异常数据。 定时校对也是一种非常重要的解决手段它采取周期性的进行校验操作来保证。关于定时任务框架的选型上业内比较常用的有单机场景下的 Quartz以及分布式场景下 Elastic-Job、XXL-JOB、SchedulerX 等分布式定时任务中间件咱公司有分布式调用平台 https://schedule.jd.com/ 。关于定时校对可以分为两种场景一种是未完成的定时重试例如我们利用定时任务扫描还未完成的调用任务并通过补偿机制来修复实现数据最终达到一致。另一种是定时核对它需要主业务服务提供相关查询接口给从业务服务核对查询用于恢复丢失的业务数据。现在我们来试想一下电商场景的退款业务。在这个退款业务中会存在一个退款基础服务和自动化退款服务。此时自动化退款服务在退款基础服务的基础上实现退款能力的增强实现基于多规则的自动化退款并且通过消息队列接收到退款基础服务推送的退款快照信息。但是由于退款基础服务发送消息丢失或者消息队列在多次失败重试后的主动丢弃都很有可能造成数据的不一致性。因此我们通过定时从退款基础服务查询核对恢复丢失的业务数据就显得特别重要了。 4.3 可靠事件模式 在分布式系统中消息队列在服务端的架构中的地位非常重要主要解决异步处理、系统解耦、流量削峰等问题。多个系统之间如果使用同步通信则很容易造成阻塞同时会将这些系统耦合在一起因此引入消息队列后一方面解决了同步通信机制造成的阻塞另一方面通过消息队列实现了业务解耦。 可靠事件模式通过引入可靠的消息队列只要保证当前的可靠事件投递并且消息队列确保事件传递至少一次那么订阅这个事件的消费者保证事件能够在自己的业务内被消费即可。这里是否只要引入了消息队列就可以解决问题了呢事实上只是引入消息队列并不能保证其最终的一致性因为分布式部署环境下都是基于网络进行通信而网络通信过程中上下游可能因为各种原因而导致消息丢失。 其一主业务服务发送消息时可能因为消息队列无法使用而发生失败。对于这种情况我们可以让主业务服务生产者发送消息再进行业务调用来确保。一般的做法是主业务服务将要发送的消息持久化到本地数据库设置标志状态为“待发送”状态然后把消息发送给消息队列消息队列先向主业务服务生产者返回消息队列的响应结果然后主业务服务判断响应结果执行之后的业务处理。如果响应失败则放弃之后的业务处理设置本地的持久化消息标志状态为“失败”状态。否则执行后续的业务处理设置本地的持久化消息标志状态为“已发送”状态。 此外消息队列接收消息后也可能从业务服务消费者宕机而无法消费。JMQ有ACK机制如果消费失败会重试如果成功会从消息队列中删除此条消息。那么消息队列如果一直重试失败而无法投递会在一定次数之后主动丢弃当然我们也可以设置为一直重试这种方式不推荐。我们需要如何解决呢我们在上个步骤中主业务服务已经将要发送的消息持久化到本地数据库。因此从业务服务消费成功后它也会向消息队列发送一个通知消息此时它是一个消息的生产者。主业务服务消费者接收到消息后最终把本地的持久化消息标志状态为“完成”状态。这就是使用“正反向消息机制”确保了消息队列可靠事件投递。当然补偿机制也是必不可少的。定时任务会从数据库扫描在一定时间内未完成的消息并重新投递。大家也可能会说消费成功之后可以用RPC调用主业务服务首先这样主业务服务要额外提供一个RPC的接口另外也会对从业务服务造成业务的复杂度和耗时影响。这里要注意从业务服务要保证幂等性。 了解了“可靠事件模式”的方法论后现在我们来看一个真实的案例来加深理解。首先当用户发起退款后自动化退款服务会收到一个退款的事件消息此时如果这笔退款符合自动化退款策略的话自动化退款服务会先写入本地数据库持久化这笔退款快照紧接着发送一条执行退款的消息投递到给消息队列消息队列接受到消息后返回响应成功结果那么自动化退款服务就可以执行后续的业务逻辑。与此同时消息队列异步地把消息投递给退款基础服务然后退款基础服务执行自己业务相关的逻辑执行失败与否由退款基础服务自我保证如果执行成功则发送一条执行退款成功消息投递到给消息队列。最后定时任务会从数据库扫描在一定时间内未完成的消息并重新投递。这里需要注意的是自动化退款服务持久化的退款快照可以理解为需要确保投递成功的消息由“正反向消息机制”和“定时任务”确保其成功投递。此外真正的退款出账逻辑在退款基础服务来保证因此它要保证幂等性。当出现执行失败的状态并且超过重试次数时就说明这个任务永久失败了需要开发人员进行手工介入与排查问题。 总结一下引入了消息队列并不能保证可靠事件投递换句话说由于网络等各种原因而导致消息丢失不能保证其最终的一致性因此我们需要通过“正反向消息机制”确保了消息队列可靠事件投递并且使用补偿机制尽可能在一定时间内未完成的消息并重新投递。 5、总结 Google Chubby的作者Mike Burrows说过 there is only one consensus protocol, and that’s Paxos” – all other approaches are just broken versions of Paxos. 意思是世上只有一种一致性算法那就是Paxos所有其他一致性算法都是Paxos算法的不完整版。上面都是以Paxos算法理论为基础具象化的方案。Google 的 Chubby、MegaStore、Spanner 等系统ZooKeeper 的 ZAB 协议还有更加容易理解的 Raft 协议都有Paxos算法的影子感兴趣的可以去看Paxos算法详细说明这里就不再赘述了。
http://www.hkea.cn/news/14391226/

相关文章:

  • 建个什么网站好呢互联网整合营销推广
  • 干果坚果网站建设中山网站制作服务
  • 有专业做线切割配件的网站吗在windows在wordpress
  • 汕尾网站建设免费自动交易软件app
  • 个人网站模板 免费lnmp.org wordpress
  • 网站建设网络公司哈尔滨龙彩做网站多少钱
  • 陕西省建设工程协会网站大鹏外贸网站建设
  • 电商商城网站建设方案国内贸易平台
  • 展馆设计说明范文seo won jin
  • 大庆免费网站建设金华金义东轨道建设网站
  • 焦作网站开发广东省东莞市
  • 安陆建设局网站wordpress使用多说头像
  • 网站开发不懂英语买购网中国10大品牌网
  • .net 网站 iis 配置小米发布会直播入口
  • 网站服务器是什么意思上海市人才服务中心网首页
  • 网站维护一般需要多久时间网站开发能封装成app吗
  • 做城市网站的标语做网站公司怎么赚钱吗
  • 网站的页面动态需要哪些方法做南宁微信公众号开发
  • 网站建设项目需求书公司网站的建设流程
  • 承德网站建设案例做app网站的软件
  • 世界最受欢迎的免费架站平台html个人主页代码编写
  • 深圳网站seo推广西安网站建设 招聘
  • ppt做视频的模板下载网站h5彩票网站怎么做
  • 昆山规划与建设局网站关键词优化排名有哪些牛霸天的软件1
  • 发布文章后马上更新网站主页房地产设计管理的思路
  • 做网站怎么开后台网站建设功能最全的软件
  • 在哪网站可以做农信社模拟试卷国际营销信息系统
  • 网站源码官网华为商城网站建设
  • ai怎么做自己的网站弘泽建设集团网站
  • 黄埔商城网站建设discuz可以做门户网站吗