微服务下,简单实现数据变更通知

一、场景设计

在微服务开发中,微服务之间的数据同步是一个比较麻烦的问题。

先设计一个简单的应用场景,当然不一定合理,将就一下。

基础数据微服务,员工资料需要同步到其他微服务,当员工信息的任何变更,其他微服务可能会使用到,例如联系方式、部门等信息的变更。

销售管理微服务,销售一般都要核算部门的绩效,当员工的部门信息改变,这个绩效也会随之改变,销售微服务中,从基础数据微服务中,选择部分员工作为销售员,那么权限管理也解决了,这里不一一说明。当这部分人的数据发生update或者delete的时候,绩效和权限必然受影响,例如员工晋升了,要及时调整角色等。

其实这个例子非常简单,因为一般这种情况不涉及到数据一致性,就是说,员工信息的变更与业务的发生没有实时的关系,也就是说,不会参与到事务中来。

升级一下场景,为了计算实时的考核成绩,在技术数据中接收到不同微服务的人员信息,然后根据不同岗位计算不同的绩效成绩,那么,这样就可能涉及到业务的数据一致性,万一业务数据回滚了呢?

二、解决这个场景涉及到的技术

1、RabbitMQ,作为消息通知的中间件

2、Redis,作为缓存员工业绩的缓存

3、Aop技术,同一管控事务以及提供分布式事务的方法,参考文章:在微服务中,利用webapi实现分布式事务_kaka9的博客-CSDN博客_webapi 微服务

4、IOC,自己写的IOCHelper,其启动方式通过基类来引导,虽然有些限制,但是在框架内是没有什么问题了,在net461,net5,netstandard2中通过。

好像没有其他了

三、解决方法

我们这里说的是涉及事务的场景。

首先,业务层对象必须共享一个内存缓存,我们当且称为Session,注意这个Session是根据当前登录用户共享的内存空间,不同用户不是互通的,参考文章:.net中利用线程锁实现缓存自动超时_kaka9的博客-CSDN博客

利用AOP技术,例如定义方法

[Transaction]

public RValue Confirm(SaleHdr hdr)

{

        //此处忽略代码一万行,反正是看不懂的

        return "提示信息";                                //第一种返回情况,事务将回滚

        return new Exception("异常信息");        //第二种返回情况,事务将回滚

        return hdr;                                             //第三种返回情况,事务将提交

}

简单说明一下,RValue<>是一个自动构建类,根据不同的传入参数构建不同的类状态,里边带了一个success属性,表示此方法执行是否成功,若不成功,则会保存Message或者Exception对象,并记录错误日志,就是把message和exception写入日志,这个东东很简单的,参考nullable<>就可以了。

当方法完成后,

var r = Confirm(hdr);

if(r)

{

        Publish(r.Value);        //好吧,这里是通过MQ发布同步数据

}

接下来就是最关键的地方

定义的这个Publish方法,内置检查当前执行方法是否在事务当中。

当AOP开始的时候,我们在Session中定义Session["TransactionKey"]=Guid.Empty.ToString();

AOP完成时候,就移除掉这个TransactionKey,这样,不管在业务层或者是数据层,都非常简单的利用这个标记来实现事务共享了,也就是说,在发布同步信息的时候,先检查是否在事务中,如果没有,直接发布,如果在事务中,那么把要发布的数据缓存到Session中,然后等事务提交成功后,在调用一个方法同步出去即可。

四、总结

说白了,这个思路非常简单,无需要监视数据库的数据变更这么麻烦,而且Publish是业务层基类的方法,使用起来也简单,程序员也无需了解MQ的具体情况,至于发布和订阅规则,在基类中定义好就可以了,建议把订阅方法打上一个标签,这里不涉及规则,不同的思路不同实现,例如

public class BillItem

{

        public THdr hdr{get;set;}

        public List dtls {get;set;}

}

[MQConsume("订阅的参数,一般和Exchange有关")]

public RValue ConsumeSale(BillItem saleItem)

{

        //处理订阅消息

        return saleItem.hdr;

}

这整个系统中,大量使用标注,有些地方是参考java的实现方式,觉得挺方便的,例如

[autowire]

IDALSaleHdr dalhdr;        //系统自动注入数据层实体

这里使用的IOC没有使用autofac,觉得没必要,自己写了一个IOCHelper就觉得了,主要是同时注入考虑依赖的问题,这个工具类无需做任何前期配置,自动扫描程序集来匹配。还是自己整的顺手,哈哈。

你可能感兴趣的:(分布式,微服务,c#,分布式,rabbitmq,redis)