怎么给网站做301,网站做代码图像显示不出来,网上购物哪个平台能买到正品,广州网站建设功能前言对于分布式事务#xff0c;常用的解决方案根据一致性的程度可以进行如下划分#xff1a;强一致性(2PC、3PC)#xff1a;数据库层面的实现#xff0c;通过锁定资源#xff0c;牺牲可用性#xff0c;保证数据的强一致性#xff0c;效率相对比较低。弱一致性(TCC)… 前言对于分布式事务常用的解决方案根据一致性的程度可以进行如下划分强一致性(2PC、3PC)数据库层面的实现通过锁定资源牺牲可用性保证数据的强一致性效率相对比较低。弱一致性(TCC)业务层面的实现通过预留或锁定部分资源最后通过确认或取消操作完成事务的处理。比如A向B转款500元A账号会冻结500元其他操作正常B接收转款时也不能直接入账而是将500元放到预留空间只有经过确认之后A才正式扣钱B才正式入账如果取消把A的500块解冻B也不会入账。最终一致性(本地消息表)不管经过多少个服务节点最终数据一致就行。比如下单成功之后需要库存服务扣减库存如果库存扣减失败不管是重试还是最后人工处理最后确保订单和库存数据能对上就行为保证用户体验及时通过中间状态的形式反馈给用户比如常见的出票中、数据处理中等。对于强一致性和弱一致性的解决方案一般针对数据一致性和时效性要求特别高的业务场景通常会牺牲暂时的可用性来满足一致性的要求由于为保证一致性会锁定资源在高并发的业务场景不是最佳选择所以很多系统在业务需求允许的情况下基本上都会采用最终一致性方案。正文1.1 最终一致性简述顾名思义就是保证数据最后的一致性就行了。如果中间节点发生失败系统为了减少代价一般不会自动回滚而是通过重试机制和人工参与的方式对失败数据进行处理从而保证系统高并发场景下高可用的数据一致性需求。1.2 解决方案目前用得最多的方案是结合本地消息表进行实现再加上后台任务、消息队列中间件就可以更好的实现分布式事务的处理。解决方案流程本地消息表就是在对应业务数据库中增加的一张消息表这张表存储业务产生的消息通过本地事务保证业务数据和消息数据的一致性。在消息表中通过一个状态来标识业务是否执行成功如果失败后台任务就进行重试。1.2.2 CAP框架简介CAP 是一个EventBus(事件总线)同时也是一个在微服务或者SOA系统中解决分布式事务问题的一个框架基于CAP理论思想进行封装的。采用模块化设计具有高度的可扩展性可靠并且易于更改。对于分布式事务的处理CAP 框架采用的是“异步确保”这种方案即本地消息表。官方支持的数据存储方式有SQL Server、MySQL、PostgreSql、MongoDB、In-Memory(内存)由于是开源项目社区大佬也提供了其他数据存储支持如Oracle、SQLite、SmartSql等。在分布式系统各节点需要进行消息传输CAP框架提供以下几种方式RabbitMQ、Kafka、Redis Streams(Redis 5.0支持)、Azure Service Bus、Amazon SQS、In-Memory Queue使用方式都差不多。CAP的架构图如下架构图上图简要说明有两个微服务服务A和服务B服务A中通过本地事务的方式将事件消息和业务逻辑进行事务保存(事件消息保存在本地消息表中)保证业务逻辑和消息的一致性和可靠性关于消息的处理和保存CAP已经封装在内部CAP内部定时调度任务将消息发布到消息队列中服务B订阅到消息将其保存到服务B的本地消息表中CAP已经封装好只需按照说明使用即可如果业务处理失败服务B中集成的CAP会根据配置的定时任务策略进行重试直到处理成功为止主要的理论就说那么多更多详细内容请进下方传送门官网https://cap.dotnetcore.xyz/githubhttps://github.com/dotnetcore/CAP/blob/master/README.zh-cn.md接下来就到撸码时刻CAP由于封装比较好所以使用起来比较简单。1.3 撸码实践以下的业务场景是为了案例演示目的是体现CAP的实践所以业务逻辑都只是模拟切勿当真。1.3.1 环境准备演示中要用到RabbitMQ为了安装方便这里使用Docker的方式直接通过镜像运行简单快速方便。关于Docker的实践后续会专门出系列文章。这里就先总结一下Docker的安装和RabbitMQ在Docker中的运行步骤采用的主机环境是我之前买的阿里云服务器(CentOS 7)演示用的数据库是SqlServer。Docker安装1、移除移动旧版本sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine
2、安装需要的依赖包sudo yum install -y yum-utils
3、设置镜像仓库sudo yum-config-manager \--add-repo \https://download.docker.com/linux/centos/docker-ce.repo
4、更新Yum软件包索引sudo yum makecache fast # 提高安装速度
5、开始安装Dockersudo yum install docker-ce docker-ce-cli containerd.io
6、启动Dockersudo systemctl start docker
7、测试Dockersudo docker run hello-world # 运行Hello-world
安装成功RabbitMQ在Docker中安装和运行1、一行命令直接指定镜像运行如果本地找不到镜像会去远程仓储里去找。docker run -d --hostname my-rabbit --name cap-rabbit -p 8888:15672 -p 5672:5672 -p 5671:5671 -p 1883:1883 rabbitmq:3-management
这里先不细说命令了后续聊Docker的时候好好说说。命令需要注意的是主机端口和容器端口的映射。2、运行成功后就可以访问啦默认用户名和密码guest/guest这里访问的地址端口是8888那是在启动容器的时候将主机端口8888和容器端口15672进行了映射。这就是选择Dokcer安装的原因超级快如果用传统的方式还得安装语言环境还得配置最后才能安装Docker通过镜像的方式直接运行即可。如果小伙伴新增用户之后不能访问或者程序连接报错可以排查是否有权限访问如下注如果小伙伴用的是云服务器需要配置安全组允许端口访问另外如果程序和RabbitMq所在的主机不是同一台机器主机防火墙也需要放开对应的端口。1.3.2 开始撸码项目准备这里模拟两个服务一个是订单服务一个是库存服务两都用到EF(Code First)如果小伙伴对EF入门还不熟跟我一起学.NetCore之EF Core 实战入门一看就会这篇文章超详细肯定能帮到你所以接下来就上几张关键的图就行啦。项目结构OrderDbContext:Startup中注册服务库存服务的代码和这个类似。通过迁移并更新到数据库时会生成如下数据库和表集成CAP这里因为用的是RabbitMQ、SqlServer所以需要引入以下几个包如果用其他消息队列或数据库可以引入对应的包。因为订单服务是在Respository层使用CAP所以对应的包就在这层引用库存服务是直接在Controller那层引用这里就不重复截图啦。订单服务和库存服务都是在各自项目的Startup文件中注册CAP相关服务并配置相关信息如下图集成完毕之后启动项目(不需要手动自己迁移)在各自业务数据库中就自动生成两个消息表用于后续消息的存储如下编写业务代码订单服务在订单生成成功之后向库存服务发送消息业务逻辑如下图中用到的_capPublisher是通过构造函数注入的。订单服务其他层的代码就不用截图了就是简单调用源码地址在文末。库存服务直接订阅就行演示案例中是直接在StockController中进行订阅如下// 标记为不实Action
[NonAction]
// 订阅消息参数和发布时指定的参数一致
[CapSubscribe(Order.Create.Success)]
public void UpdateStock(OrderEntity order)
{//throw new Exception(扣减库存异常了~~~);// 为了测试库存里面没有数据的话先模拟一条数据bool bHaveData _stockDbContext.Stock.Any();if(!bHaveData){StockEntity stock new StockEntity{Id Guid.NewGuid(),ProductNo Product001,StockCount 100,UpdateDate DateTime.Now};_stockDbContext.Stock.Add(stock);_stockDbContext.SaveChanges();}// 模拟扣减库存using var trans _stockDbContext.Database.BeginTransaction(_capPublisher, autoCommit: false);try{// 根据产品编号找到产品var product _stockDbContext.Stock.Where(s s.ProductNo order.ProductNo).FirstOrDefault();// 扣减库存之后保存product.StockCount product.StockCount - order.Count;_stockDbContext.Update(product);_stockDbContext.SaveChanges();// 可以继续向下发布流程比如库存扣减成功下一步到物流服务进行相关处理可以继续发布消息// _capPublisher.Publish();trans.Commit();Console.WriteLine(order.OrderNo);}catch (Exception ex){trans.Rollback();}
}
可以看到订阅很简单直接标上[CapSubscribe(Order.Create.Success)]这个Attribute就行了如果消息状态为失败后续CAP的定时任务会根据定时策略调用此方法。1.3.3 运行看效果正常流程下单成功扣减库存成功将订单服务(端口5000)和库存服务(端口6000)都启动起来。订单服务中增加了OrderController里面有一个GenerateOrder的接口直接调用即可这里使用Postman工具进行测试如下库存服务就会订阅到信息如下业务流程完成之后订单和库存数据整体一致了回过头来看看消息表看看里面有什么消息如下异常流程模拟下单成功扣减库存失败在扣减服务逻辑方法中手动抛出异常代码如下然后启动项目重新测试再下一个订单试试操作后先来看看消息表如下注CAP在默认情况下发送和消费消息的过程中失败会立即重试 3 次在 3 次以后将进入重试轮询重试将在发送和消费消息失败的 4分钟后 开始这是为了避免设置消息状态延迟导致可能出现的问题后续就会每隔1分钟之后重试一次默认的最高重试次数为50次当达到50次时就不会重试了。现在知道问题了优化代码重新启动即把抛异常的代码注释掉看看会不会自动处理如下如上图稍等一会消息就自动处理了业务数据符合预期保证一致性。这个是CAP内部定时读取消息表根据状态不断重试业务逻辑直到成功为止。CAP的全自动是不是感觉比较便捷写最少的代码解决了最难搞的分布式事务。修改默认的配置在实际业务场景中默认配置可能不太实用可以在注册服务时进行默认配置更改如下配置修改之后的测试这里就不截图了留给小伙伴们动手试试吧。案例代码地址https://gitee.com/CodeZoe/microservies-demo/tree/main/CapDemo总结关于分布式事务的实操把最常用的最终一致性方案简单分享了一下小伙伴可以根据自己的业务场景赶紧动手试试吧其他方案会在后续的文章中加上主要还是以实用为主已经不咋用的就没必要再说啦。文章中提及到Docker和RabbitMQ我已经在着手准备这块的文章了关注“Code综艺圈”和我一起学习吧