宣传型电子商务网站,自建网站需要学哪些,网站建设中faqs的意思,山东坤泰建设集团网站一、事务起步
1. 什么是事务
事务这种东西大家都耳熟能详了#xff0c;通常指由一组操作组成的一个工作单元#xff0c;这一整个组合要么全部成功#xff0c;要么全部失败。
2. 本地事务
在计算机系统中#xff0c;更多的是通过关系型数据库来控制事务#xff0c;这是…一、事务起步
1. 什么是事务
事务这种东西大家都耳熟能详了通常指由一组操作组成的一个工作单元这一整个组合要么全部成功要么全部失败。
2. 本地事务
在计算机系统中更多的是通过关系型数据库来控制事务这是利用数据库本身的事务特性来实现的因此叫数据库事务由于应用主要靠关系数据库来控制事务而数据库和应用在同一服务器所以基于关系型数据库的事务又被称为本地事务。
数据库事务具有原子性Atomacity、一致性Consistency、隔离性Isolation和持久性Durability。
3. 分布式事务
随着互联网的快速发展软件系统由原来的单体应用转变为分布式应用。分布式系统会把一个应用系统拆分为可独立部署的多个服务因此需要服务与服务之间远程协作才能完成事务操作这种分布式系统环境下由不同的服务之间通过网络远程协作完成事务称为分布式事务。 以上面图示举例当需要创建订单的时候将会涉及到订单和库存两个操作。那么左图操作两个系统最终需要写入两个数据库我们需要保证分布式事务的一致性这一点应该很容易理解如果我们只创建了订单而没有去减少相应的库存量就会出现超卖的现象。同样的像中间虽然最终只涉及到一个数据库但是同样需要保证一致性右图同理。
二、CAP理论与BASE理论
1. CAP理论
CAP是一致性Consistency、可用性Availability、分区容忍性Partition Tolerance三个词语的缩写我们先简单解释下这三个词语 一致性服务A、B、C三个节点都存储了用户数据要求三个节点在写操作后的读操作可以读取到的数据都是最新的状态可用性可用性即整个系统可以外提供服务分区容忍性分布式系统的节点往往都是分布在不同的机器上进行网络隔离开的这意味着必然会有网络断开的风险这个网络断开的场景我们称为分区容忍性
那么在网络分区出现也就是有多个节点分布在不同的子网中时如何实现一致性呢过程大概如下
写入主数据库后将数据同步到从数据库写入主数据库后在向数据库同步期间要将从数据库锁定待同步完成后再释放锁以免在新数据写入成功后向从数据库查询到旧的数据。
所以如果我们在数据库同步期间锁定从数据库那么可用性就无法保证如果不锁定那么就会有访问向从数据库读取数据可能会读取到旧的数据此时又无法保证一致性。
所以用一句话概括CAP原理就是当网络分区发生时一致性和可用性难以两全。只能选择CP或者AP。
2. BASE理论
2.1 强一致性和最终一致性
CAP理论告诉我们一个分布式系统只能同时满足CAP三项中的两项其中AP在实际应用中较多AP即舍弃一致性保证可用性和分区容忍性但是在实际生产中很多场景也是需要实现一致性的。
比如主数据库向从数据库中同步数据即使不要一致性但是最终也要将数据同步成功来保证数据一致这种一致性和CAP中的一致性不同CAP中的一致性是要求任何时间查询每个节点数据都必须一致它所强调的是一致性但是最终一致性是允许在一段时间内各节点的数据不一致但是经过一段时间每个节点的数据必须一致它所强调的是最终一致性。
2.2 Base理论介绍
BASE 是 Basically Available基本可用、Soft State软状态和Eventually consistent最终一致性三个短语的缩写。BASE理论是对CAP中AP的一个扩展通过牺牲强一致性来获得可用性当出现故障允许部分不可用但要保核心功能可用允许数据在一段时间内是不一致的但是最终要达到一致状态。满足BASE理论的事务我们称之为“柔性事务”。
基本可用分布式系统在出现故障时允许损失部分可用功能保证核心功能可用。如电商网站交易付款出现问题了商品依然可以正常浏览软状态由于不要求强一致性所以BASE允许系统中存在中间状态也叫软状态这个状态不影响系统可用性如订单的“支付中”、“数据同步中”等状态待数据最终一致后状态改为“成功”状态最终一致最终一致是指经过一段时间后所有节点数据都会达成一致。如订单的“支付中”状态最终会变成“支付成功”或者“支付失败“使订单状态与实际交易结果达成一致但需要一定时间的延迟、等待。
三、2PC两阶段提交
2PC即两阶段提交Two-phase Commit, 2PC通过引入协调者Coordinate来协调参与者的行为并最终决定这些参与者是否要真正执行事务。
1. 运行过程
1.1 准备阶段
协调者询问参与者事务是否执行成功参与者发回事务执行结果如下图所示 1.2 提交阶段
如果事务在每个参与者上都执行成功事务协调者发送通知让参与者提交事务否则协调者发送通知让参与者回滚事务。
注意在准备阶段参与者只是执行了事务但是并没有提交只有在提交阶段接收到协调者发来的通知后才进行提交或者回滚。 2. XA方案
2PC的传统方案是在数据库层面实现的如Oracle和MySQL都支持2PC协议为了统一标准和减少行业内不必要的对接成本需要制定标准化的处理模型及接口标准国际开放组织Open Group定义了分布式事务处理模型DTPDistributed Transaction Processing Reference Model。
下面以新用户注册时送积分的案例来说明 执行流程如下
应用程序AP持有用户库和积分库两个数据源应用程序AP通过TM通知用户库RM新增用户同时通知积分库RM为该用户新增积分RM此时并未提交事务此时用户和积分资源锁定TM收到执行回复只要有一方失败则分别向其他RM发起事务回滚回滚完毕资源锁释放TM收到执行回复全部成功此时向所有RM发起提交事务提交完毕资源锁释放。
DTP模型定义如下角色
APApplication Program即应用程序可以理解为使用DTP分布式事务的程序RMResource Program即资源管理器可以理解为事务的参与者一般情况下是指一个数据库实例通过资源管理器对该数据库进行控制资源管理器控制着分支事务TMTransaction Manager事务管理器负责协调和管理事务事务管理器控制着全局事务管理事务生命周期并协调各个RM。全局事务是指分布式事务处理环境中需要操作多个数据库共同完成一个工作这个工作即是一个全局事务。
DTP模型定义TM和RM之间通讯的接口规范叫XA简单理解为数据库提供的2PC接口协议基于数据库的XA协议来实现2PC又称为XA方案。
以上三个交互角色之间的交互方式如下
TM向AP提供应用程序编程接口AP通过TM提交以及回滚事务TM中间件通过XA接口来通知RM数据库事务的开始、结束以及提交、回滚等。
XA方案的缺陷
需要本地数据库支持XA协议资源锁需要等待两个阶段结束才释放性能较差。
3. Seata方案
Seata是由阿里开源的分布式事务框架。传统2PC的问题在Seata中得到了解决通过对本地关系数据库的分支事务的协调来驱动完成全局事务是工作在应用层的中间件。主要优点是性能较好且不长时间占用连接资源以高效且对事务零侵入的方式解决微服务场景下面临的分布式事务问题它目前提供AT模式即2PC及TCC模式的分布式事务解决方案。
3.1 设计思想
Seata的设计目标包括了对业务的无侵入因此从业务无侵入的2PC方案着手在传统的2PC的基础上演进并解决2PC方案面临的问题。
Seata把一个分布式事务理解成一个包含了若干个分支事务的全局事务。全局事务的职责是协调其下管辖的分支事务达成一致要么一起提交要么一起失败回滚。此外通常分支事务本身就是一个关系数据库的本地事务下图是全局事务与分支事务的关系图 与传统的2PC模型相比Seata定义了三个组件来协调分布式事务的管理过程 Transaction CoordinatorTC事务协调器它是独立的中间件需要独立部署运行它维护全局事务的运行状态接收TM指令发起全局事务的提交与回滚负责与RM通信协调各个分支事务的提交或回滚Transaction ManagerTM事务管理器TM需要嵌入应用程序中工作它负责开启一个全局事务并最终向TC发起全局提交或全局回滚的指令Resource ManagerRM控制分支事务负责分支注册、状态汇报并接收事务协调器TC的指令驱动分支本地事务的提交和回滚。
3.2 执行流程
依旧以新用户注册送积分举例Seata的分布式事务过程 具体的执行流程如下
用户服务的 TM 向 TC 申请开启一个全局事务全局事务创建成功并生成一个唯一的XID用户服务的 RM 向TC 注册分支事务该分支事务在用户执行新增用户逻辑并将其纳入 XID 对应全局事务的管辖用户服务执行分支事务向用户表插入一条记录逻辑执行到远程调用积分服务时XID在微服务调用链路的上下文传播。积分服务的RM向TC注册分支事务该分支事务执行增加积分的逻辑并将其纳入 XID 对应的全局事务的管辖积分服务执行分支事务向积分记录表插入一条记录执行完毕返回用户服务用户服务分支事务执行完毕TM向TC发起针对XID的全局提交或回滚决议TC调度XID下管辖的全部分支事务完成提交或回滚请求。
3.3 Seata的优势
架构层次方面传统2PC方案的RM实际上是在数据库层RM本质上就是数据库本身通过XA协议实现而Seata的RM是以jar包的形式作为中间件层部署在应用程序这一侧的。
两阶段提交方面传统2PC无论第二阶段的决是commit还是rollback事务性资源的锁都要保持到Phase2完成才能释放而Seata的做法是在Phase1就将本地事务提交这样就可以省去 Phase2 持锁的时间整体提高效率。
3.4 二阶段回滚
二阶段如果是提交的话就很容易理解因为”业务SQL“在一阶段已经提交至数据库所以Seata框架只需将一阶段保存的快照数据和行锁删掉完成数据清理即可。
二阶段如果是回滚的话Seata就需要回滚一阶段已经执行的”业务SQL“还原业务数据。回滚方式便是用”before image“还原业务数据但在还原前要首先校验脏写对比”数据库当前业务数据“和”after image“如果两份数据完全一致就说明没有脏写可以还原业务数据如果不一致就说明有脏写出现脏写就需要转人工处理。 四、TCC事务补偿
TCC事务补偿是基于2PC实现的业务层事务控制方案TCC这一词是由Try、Confirm和Cancel三个单词的首字母含义如下
Try阶段做业务检查一致性及资源预留隔离此阶段仅为一个初步操作它和后续的Confirm一起才能真正构成一个完整的业务逻辑Confirm阶段是做确认提交Try阶段所有分支事务执行成功后开始执行Confirm。通常情况下采用TCC则认为Confirm阶段是不会出错的。即只要Try成功Confirm一定成功。若Confirm阶段真的出错了需引入重试机制或人工处理Cancel阶段是在业务执行错误需要回滚的状态下执行分支事务的业务取消预留资源释放。通常情况下采用TCC则认为Cancel阶段也是一定会成功的。若Cancel阶段真的出错了需引入重试机制或人工处理。
TM首先发起所有的分支事务的Try操作任何一个分支事务的Try操作执行失败TM将会发起所有分支事务的Cancel操作若try操作全部成功TM将会发起所有的分支事务的Confirm操作其中Conrirm/Cancel操作若执行失败TM会进行那个重试。
我们用一个下单同时减少库存的业务来进行说明 Try 下单业务由订单服务和库存服务协同完成在try阶段订单和库存服务完成检查和预留资源 订单服务检查当前是否满足提交订单的条件比如当前存在未完成的订单不允许提交新订单 库存服务检查是否有充足的资源并锁定资源 Confirm 订单服务和库存服务完成Try后开始执行资源操作 订单服务向订单写一条订单信息 库存服务减去库存。 Cancel 如果订单服务和库存服务有一方出现失败则全部操作取消 订单服务需要删除新增的订单信息。 库存服务将减去的库存再还原。
1. 空回滚
在没有调用TCC资源Try方法的情况下调用了二阶段的Cancel方法Cancel方法需要识别出这是一个空回滚然后直接返回成功。
出现原因是当一个分支事务所在服务宕机或网络异常分支事务调用记录为失败这个时候其实是没有执行Try阶段当故障恢复后分布式事务进行回滚则会调用二阶段的Cancel方法从而形成空回滚。
解决思路的关键是要识别出这个空回滚。思路很简单就是需要知道一阶段是否执行了如果执行了那就是正常回滚如果没执行那就是空回滚。前面已经说过TM在发起全局事务时生成全局事务记录全局事务ID贯穿整个分布式事务调用链。再额外增加一张分支事务记录表表中有全局事务ID贯穿和分支事务ID第一阶段Try方法里会插入一条记录表示一阶段执行了。Cancel接口里读取该记录如果该记录存在则正常回滚如果该记录不存在则是空回滚。
2. 幂等性
TM即事务管理器在发起全局事务时生成全局事务记录全局事务ID贯穿整个分布式事务调用链条用来记录事务上下s文追踪和记录状态由于Confirm和Cancel失败需进行重试因此需要实现为幂等。幂等性是指同一操作无论请求多少次其结果都相同。
所以为了保证TCC二阶段提交重试机不会引发数据不一致要求TCC的二阶段Try、Confirm和Cancel接口保证幂等这样不会重复使用或者释放资源。如果幂等控制没做好很有可能导致数据不一致等严重问题。
3. 悬挂
悬挂就是对于一个分布式事务其二阶段Cancel接口比Try接口先执行。
出现原因是在RPC调用分支事务Try时先注册分支事务再执行RPC调用如果此时RPC调用的网络发生拥堵通常RPC调用是有超时时间的RPC超时以后TM就会通知RM回滚分布式事务可能回滚完成后RPC请求才到达参与者真正执行而一个Try方法预留的业务资源只有该分布式事务才能使用该分布式事务第一阶段预留的业务资源就再也没有人能够处理了对于这种情况我们称之为悬挂即业务资源预留后没法继续处理。
解决思路是如果二阶段执行完成那一阶段就不再继续执行。在执行一阶段事务时判断在该全局事务下”分支事务记录“表中是否已有二阶段事务记录如果有则不执行Try。
五、可靠消息最终一致性
可靠消息最终一致性方案是指当事务发起方执行完成本地事务后并发出一条消息事务参与方消息消费者一定能够接收消息并处理事务成功此方案强调的是只要消息发给事务参与方最终事务要达到一致。
此方案是利用消息中间件完成如下图
事务发起方消息生成方将消息发给消息中间件事务参与方从消息中间件接收消息事务发起方和消息中间件之间事务参与方消息消费方和消息中间件之间都是通过网络通信由于网络通信的不确定性会导致分布式事务问题。 因此可靠消息最终一致性解决方案要解决以下几个问题
1. 方案问题
1.1 本地事务与消息发送的原子性问题
本地事务与消息发送的原子性问题即事务发起方在本地事务执行成功后消息必须发送出去否则就丢弃消息。即实现本地消息和消息发送的原子性要么都成功要么都失败。本地事务与消息发送的原子性问题是实现可靠消息最终一致性方案的关键问题。
先来尝试下这种操作先发送消息再操作数据库
begin transaction:// 1. 发送MQ// 2. 数据库操作
commit transaction;1234
这种情况下无法保证数据库操作与发送消息的一致性因为可能发送消息成功数据库操作失败。
那么现在来看第二种方案先进行数据库操作再发送消息
begin transaction:// 1. 数据库操作// 2. 发送MQ
commit transaction;1234
这种情况下貌似没有问题如果发送MQ消息失败就会抛出异常导致数据库事务回滚。但如果是超时异常数据库回滚但MQ其实已经正常发送了同样会导致不一致。
1.2 事务参与方接收消息的可靠性
事务参与方必须能够从消息队列接收到消息如果接收消息失败可以重复接收消息。
1.3 消息重复消费的问题
由于网络2的存在若某一消费节点超时但是消费成功此时消息中间件会重复投递此消息就导致了消息的重复消费。
要解决消息重复消费的问题就要实现事务参与方的方法幂等性。
2. 解决方案
2.1 本地消息表方案
本地消息方案是通过本地事务保证数据业务操作和消息的一致性然后通过定时任务将消息发送至消息中间件待确认消息发送给消费方成功再将消息删除。
以注册送积分为例来说明
一共有两个微服务交互用户服务和积分服务用户服务负责添加用户积分服务负责添加积分 交互流程如下
2.1.1 用户注册
用户服务在本地事务新增用户增加”积分消息日志“。用户表和消息表通过本地事务保证一致
下边是伪代码
begin transaction;// 1. 新增用户// 2. 存储积分消息日志
commit transaction;1234
这种情况下本地数据库操作与存储积分消息日志处于同一事务中本地数据库操作与记录消息日志操作具备原子性。
2.1.2 定时任务扫描日志
如何保证将消息发送给消息队列呢
经过第一步消息已经写到消息日志表中可以启动独立的线程定时对消息日志表中的消息进行扫描并发送至消息中间件在消息中间件反馈成功后删除该消息日志否则等待定时任务下一周期重试。
2.1.3 消费消息
如何保证消费者一定能消费到消息呢
这里可以使用MQ的ACK即消息确认机制消费者监听MQ如果消费者接受到消息并且业务处理完成后MQ发送ACK即消息确认此时说明消费者正常消费消息完成MQ将不再向消费者推送消息否则消费者会不断重试向消费者来发送消息。
积分服务接收到”增加积分“消息开始增加积分积分增加成功后向消息中间件回应ACK否则消息中间件将重复投递此消息。
由于消息会重复投递积分服务的”增加积分“功能需要实现幂等性。
2.2 RocketMQ事务消息方案
RocketMQ是一个来自阿里巴巴的分布式消息中间件。RocketMQ事务消息设计则主要为了解决Producer端的消息发送与本地事务执行的原子性问题RocketMQ设计中broker与producer端的双向通信能力使得broker天生可以作为一个事务协调者存在而RocketMQ本身提供的存储机制为事务消息提供了持久化能力RocketMQ的高可用机制以及可靠消息设计则为事务消息在系统发生异常时依然能够保证达成事务的最终一致性。
在RocketMQ 4.3 后实现了完整的事务消息实际上其实是对本地消息表的一个封装将本地消息表移动到了MQ内部解决了 Producer 端的消息发送与本地事务执行的原子性问题。 执行流程如下
我们还以注册送积分的例子来描述整个流程。
Producer即MQ发送方本例中是用户服务负责新增用户。MQ订阅方即消息消费方本例中是积分服务负责新增积分。 Producer发送事务消息 ProducerMQ发送方发送事务消息至MQ ServerMQ Server将消息状态标记为 Prepared预备状态注意此时这条消息消费者MQ订阅方是无法消费到的。 本例中Producer发送”增加积分消息“到 MQ Server。 MQ Server回应消息发送成功 MQ Server接收到Producer发送给的消息则回应发送表示MQ已接受到消息。 Producer执行本地事务 Producer端执行业务代码逻辑通过本地数据库事务控制。本例中Producer执行添加用户操作。 消息投递 若Producer本地事务执行成功功则自动向MQServer发送commit消息MQ Server接收到commit消息后将”增加积 分消息“ 状态标记为可消费此时MQ订阅方积分服务即正常消费消息 若Producer 本地事务执行失败则自动向MQServer发送rollback消息MQ Server接收到rollback消息后 将删 除”增加积分消息“ 。 MQ订阅方积分服务消费消息消费成功则向MQ回应ack否则将重复接收消息。这里ack默认自动回应即 程序执行正常则自动回应ack。 事务回查 如果执行Producer端本地事务过程中执行端挂掉或者超时MQ Server将会不停的询问同组的其他 Producer 来获取事务执行状态这个过程叫事务回查。MQ Server会根据事务回查结果来决定是否投递消息。 以上主干流程已由RocketMQ实现对用户侧来说用户需要分别实现本地事务执行以及本地事务回查方法因此 只需关注本地事务的执行状态即可。 RoacketMQ提供RocketMQQLocalTransactionListener接口 public interface RocketMQLocalTransactionListener {/** ‐ 发送prepare消息成功此方法被回调该方法用于执行本地事务 ‐ param msg 回传的消息利用transactionId即可获取到该消息的唯一Id ‐ param arg 调用send方法时传递的参数当send时候若有额外的参数可以传递到send方法中这里能获取到 ‐ return 返回事务状态COMMIT提交 ROLLBACK回滚 UNKNOW回调 */RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg); /** ‐ param msg 通过获取transactionId来判断这条消息的本地事务执行状态 ‐ return 返回事务状态COMMIT提交 ROLLBACK回滚 UNKNOW回调 */ RocketMQLocalTransactionState checkLocalTransaction(Message msg);
}12345678910111213141516发送事务消息以下是RocketMQ提供用于发送事务消息的API TransactionMQProducer producer new TransactionMQProducer(ProducerGroup);
producer.setNamesrvAddr(127.0.0.1:9876);
producer.start();
// 设置TransactionListener实现
producer.setTransactionListener(transactionListener
// 发送事务消息
SendResult sendResult producer.sendMessageInTransaction(msg, null);1234567
六、最大努力通知
1. 最大努力通知介绍
最大努力通知也是一种解决分布式事务的方案下面以一个充值的案例举例 交互流程 账户系统调用充值系统接口 充值系统完成支付处理向账户系统发起充值结果通知若通知失败则充值系统按策略进行重复通知 账户系统接收到充值结果通知修改充值状态。 账户系统未接收到通知会主动调用充值系统的接口查询充值结果。
通过上边的例子我们总结最大努力通知方案的目标
目标发起通知方通过一定的机制最大努力将业务处理结果通知到接收方。
具体包括 有一定的消息重复通知机制 因为接收通知方可能没有接收到通知此时要有一定的机制对消息重复通知 消息校对机制 如果尽最大努力也没有通知到接收方或者接收方消费消息后要再次消费此时可由接收方主动向通知方查询消息来满足需求。 最大努力通知与可靠消息一致性有什么不同 解决方案思想不同 可靠消息一致性发起通知方需要保证将消息发出去并且将消息发到接收通知方消息的可靠性关键由发起通知 方来保证。 最大努力通知发起通知方尽最大的努力将业务处理结果通知为接收通知方但是可能消息接收不到此时需要接收通知方主动调用发起通知方的接口查询业务处理结果通知的可靠性关键在接收通知方。 两者的业务应用场景不同 可靠消息一致性关注的是交易过程的事务一致以异步的方式完成交易。 最大努力通知关注的是交易后的通知事务即将交易结果可靠的通知出去。 技术解决方向不同 可靠消息一致性要解决消息从发出到接收的一致性即消息发出并且被接收到。 最大努力通知无法保证消息从发出到接收的一致性只提供消息接收的可靠性机制。可靠机制是最大努力的将消 息通知给接收方当消息无法被接收方接收时由接收方主动查询消息业务处理结果。
2. 解决方案
通过对最大努力通知的理解采用MQ的ack机制就可以实现最大努力通知。
方案1 本方案是利用MQ的ack机制由MQ向接收通知方发送通知流程如下
发起通知方将通知发给MQ。
使用普通消息机制将通知发给MQ。
注意如果消息没有发出去可由接收通知方主动请求发起通知方查询业务执行结果。后边会讲 接收通知方监听 MQ。 接收通知方接收消息业务处理完成回应ack。 接收通知方若没有回应ack则MQ会重复通知。
MQ会按照间隔1 min、5 min、10 min、30 min、1 h、2 h、5 h、10 h的方式逐步拉大通知间隔如果 MQ 采用rocketMQ在broker中可进行配置直到达到通知要求的时间窗口上限。
5、接收通知方可通过消息校对接口来校对消息的一致性。
方案2
本方案也是利用MQ的ack机制与方案1不同的是应用程序向接收通知方发送通知如下图 交互流程如下 发起通知方将通知发给MQ。 使用可靠消息一致方案中的事务消息保证本地事务与消息的原子性最终将通知先发给MQ。 通知程序监听 MQ接收MQ的消息。 方案1中接收通知方直接监听MQ方案2中由通知程序监听MQ。通知程序若没有回应ack则MQ会重复通知。 通知程序通过互联网接口协议如http、webservice调用接收通知方案接口完成通知。 通知程序调用接收通知方案接口成功就表示通知成功即消费MQ消息成功MQ将不再向通知程序投递通知消 息。 接收通知方可通过消息校对接口来校对消息的一致性。
方案1和方案2的不同点 方案1中接收通知方与MQ接口即接收通知方案监听 MQ此方案主要应用与内部应用之间的通知。 方案2中由通知程序与MQ接口通知程序监听MQ收到MQ的消息后由通知程序通过互联网接口协议调用接收 通知方。此方案主要应用于外部应用之间的通知例如支付宝、微信的支付结果通知。 资料收集于网络。