CAP介绍:
CAP是一个用来解决微服务或者分布式系统中分布式事务问题的一个开源项目解决方案。可以解决跨服务器的数据一致性问题。一个简单的列子,如:订单系统创建订单后需要通知邮件通知用户下单成功,解决方案有下面几种:
1:创建订单时同步调用邮件发送,邮件发送失败则整个订单创建失败,这样保证了一致性,但性能和可用性有非常大的问题。或者不管邮件发送状态,失败了就算了,这样用户就可能收不到通知邮件了。
2:创建订单时通过消息队列推送一个订单创建成功的事件,另外创建一个服务来监听消费此事件,并执行邮件发送的功能。这种方案存在往消息队列推送数据失败的可能,存在和方案1一样的问题。
3:创建订单时同时往一个叫“订单创建成功”的事件表中插入相关数据,两者在同一事务中。 另外创建一个服务定时查询此表,发现有待处理的数据时,执行邮件发送,成功后把此数据删除或更新为已处理。此方案保证了最终一致性和可用性,但得定时扫描,性能和及时性有问题。
4:创建订单时同时往一个叫“订单创建成功”的事件表中插入相关数据,两者在同一事务中。并且通过消息队列推送此消息,如果推送失败,则定时扫描“订单创建成功”表将失败的数据重新推送。另外创建一个服务来监听消费此事件,这种方案集成了方案1和方案2的优点,即保证了最终一致性,也保证了可用性。
从上面来看最优的方案显示是方案4,我们这次的主角CAP也正是采用了此种方案来实现的,我们这里介绍的方案4还是比较简单的,CAP的实现要更加的严谨、更加强大,我们不需要建过程表,也不需要处理消息队列的问题,底层很多的细节都不需要我们考虑,只管用就好了。CAP数据库存储支持:Sql Server,MySql,PostgreSql,MongoDB。消息队列支持:RabbitMQ,Kafka,Azure Service Bus等。
各多CAP的介绍可以参考官网,详细的CAP理论可以参考其它文章。 官网 CAP - A distributed transaction solution in micro-service base on eventually consistency, also an eventbus with Outbox pattern - CAP ,开源地址:GitHub - dotnetcore/CAP: Distributed transaction solution in micro-service base on eventually consistency, also an eventbus with Outbox pattern ,作者blog Savorboard - 博客园
快速开始
CAP2.6是2019-8-29发布的,目前官网上的文档快速开始已经无法使用,因为里面用了 Savorboard.CAP.InMemoryMessageQueue 组件,该组件还是2.51,不支持最新的CAP2.6版本,应该得过段时间才会修复文档,或者等 Savorboard.CAP.InMemoryMessageQueue组件更新。现在我们就在这开始我们的“快速开始”吧。我们将基于rabbitmq和sqlserver数据库来实现。
1:创建项目
打开VS创建一个名叫CapDemo的webapi项目,版本选择ASP.NET Core 2.2。CAP2.6不支持2.2以下的.net core
2:添加CAP引用
在Nuget中添加 DotNetCore.CAP DotNetCore.CAP.RabbitMQ DotNetCore.CAP.SqlServer 的引用。
3:配置CAP
在Startup.cs的ConfigureServices方法中添加以下代码
services.AddCap(c =>
{
c.UseSqlServer(@"Data Source=.\sql2014;Initial Catalog=Test;User ID=sa;Password=sa"); //使用SqlServer数据库,连接地址请依实际修改
c.UseRabbitMQ( mq =>
{
mq.HostName = "192.168.150.134"; //RabitMq服务器地址,依实际情况修改此地址
mq.Port = 5672;
mq.UserName = "admin"; //RabbitMq账号
mq.Password = "admin"; //RabbitMq密码
});
});
4:发布事件
将 CapDemo.Controllers.ValuesController中的所有方法全部删除。添加引用 using DotNetCore.CAP; ,并添加以下方法
[HttpGet]
public async Task<string> Get([FromServices]ICapPublisher capPublish)
{
await capPublish.PublishAsync<string>("Order.Created", "hello,订单创建成功啦"); //发布Order.Created事件
return "订单创建成功啦";
}
5:订阅事件
在CapDemo.Controllers.ValuesController中添加以下方法:
[NonAction]
[CapSubscribe("Order.Created")] //监听Order.Created事件
public async Task OrderCreatedEventHand(string msg)
{
Console.WriteLine(msg);
6:最后一步:启动测试
在OrderCreatedEventHand方法内打个断点,F5启动项目访问https://localhost:44304/api/values界面。因为此例中第一次访问时可能发布事件比订阅事件要快,导致还没订阅就把事件发布出去了,这样的事件会丢失,所以我们再F5刷新一下界面,可以看到程序就进入到了订阅事件里面。
后记:
添加监控仪表盘监控CAP运行状况:
1:只需要在Startup.cs的AddCap方法中添加配置: c.UseDashboard(); 就万事大吉了,一个功能强大的事件管理界面就出来了,具体如下图:
2: 重新编译并启动项目,进入https://localhost:44304/cap ,从打开的界面里可以看到CAP的各种事件和状态。
数据库变化
我们再看看数据库里面的变化吧,从下图可以看出CAP自动创建了两个表,并且记录了发布的消息,和接收到的消息。这些数据会定时删除。这些都是不需要我们管的。