hello,大家好,今天来到橙子老哥的分享时间,希望大家一起学习,一起进步。
欢迎加入.net意社区,第一时间了解我们的动态,文章第一时间分享至社区
社区官方地址:https://ccnetcore.com
(上千.neter聚集地)
官方微信公众号:搜索 意.Net
添加橙子老哥
微信加入官方微信群:chengzilaoge520
上一篇我们实操了高并发分布式缓存的解决方案, 这篇我们接着分布式的话题,使用c#去实操了一下分布式事务问题的解决方案
相信很多人已经对分布式事务
这种面试八股文很熟悉了,说个七七八八不成问题,网上也有很多教程,但是多偏向于理论,没有实操,今天橙子老哥使用c#,带大家把整个流程落地一遍
希望下次遇到这个问题,能回想到橙子老哥的这篇文章,就是这篇文章的意义了
1、事务-ACID
长话短说,理论知识不能少:一个事务有四个基本特性,也就是我们常说的(ACID)。
- Atomicity(原子性) :事务是一个不可分割的整体,事务内所有操作要么全做成功,要么全失败。
- Consistency(一致性) :务执行前后,数据从一个状态到另一个状态必须是一致的(A向B转账,不能出现A扣了钱,B却没收到)。
- Isolation(隔离性):多个并发事务之间相互隔离,不能互相干扰。
- Durablity(持久性) :事务完成后,对数据库的更改是永久保存的,不能回滚。
以上这些特征相信大家在使用数据库的时候,已经了如指掌了,这里也不再过多赘述。
2、不处理分布式事务
通常的,如果是在单体架构中,为了保持数据的一致性,只需要在批量执行数据库操作的时候,开启事务,在最终完成操作的时候,再提交事务即可
但是如果各各操作是分布在不同的程序/数据库/服务器上,我们还按照原先的方式会怎么样呢?
废话少说,我们直接实操,准备代码:
这里我们模拟一个经典场景,订单服务
和库存服务
,用户创建订单,订单数+1,库存数量-1,像这种场景,我们必须要确保数据的一致性,如果出现了订单加的多了,库存减的少了,那不就产生了超卖的严重生产事故?
//情况1,无分布式事务处理
//订单服务客户端
var orderServiceClient = new OrderServiceClient();
//库存服务客户端
var storeServiceClient = new StoreServiceClient();
//模拟执行10次下单
var i = 10;
while (i>0)
{
try
{
//入口,用户进行创建订单
orderServiceClient.CreateOrder(storeServiceClient);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
//打印数据库订单和库存数量
Console.WriteLine($"当前订单数量:{
OrderServiceClient.Order},库存数量:{
StoreServiceClient.Store}");
i--;
}
}
Console.WriteLine("完成");
class OrderServiceClient
{
public static int Order {
get; private set; } = 10;
private Action? _tran;
//新增订单到数据库(不会真正执行,返回委托,事务预处理,执行委托就是提交事务)
Action AddOrderToDb()
{
return () => Order += 1;
}
//业务代码
public void CreateOrder(StoreServiceClient storeClient)
{
//订单服务开启事务
_tran = AddOrderToDb();
storeClient.UpdateStore();
//订单提交事务
_tran.Invoke();
}
}
//同理
class StoreServiceClient
{
public static int Store {
get; private set; } = 20;
private Action? _tran;
//新增订单
Action DecreaseStoreToDb()
{
return () => Store -= 1;
}
public void UpdateStore()
{
//库存服务开启事务
_tran = DecreaseStoreToDb();
_tran.Invoke();
}
}
在上面的例子中,我们在订单服务,调用了自己的数据库,同时又远程调用了库存服务,双方各自执行事务操作
当没有一方出现错误、网络完美、服务器稳定、内存够用,好像怎么执行也不会有任何问题
CAP:我又来了,分布式中要满足分区容错,一致性和可用性就不能同时抓
上面执行中,很明显有个地方容易出问题,如果在库存服务事务已经提交,返回的时候,网络波动订单服务没有收到结果
,订单报错了,取消事务,库存执行完了,新增库存,导致数据不一致
//业务代码
public void CreateOrder(StoreServiceClient storeClient)
{
//订单服务开启事务
_tran = AddOrderToDb();
storeClient.UpdateStore();
//情况1
throw new Exception("订单服务网络波动,无法收到库存服务的回应,或者收到回应,但是事务没有提交宕机");