25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.zh-cn.md 8.9 KiB

7 년 전
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. # CAP                       [English](https://github.com/dotnetcore/CAP/blob/develop/README.md)
  2. [![Travis branch](https://img.shields.io/travis/dotnetcore/CAP/develop.svg?label=travis-ci)](https://travis-ci.org/dotnetcore/CAP)
  3. [![AppVeyor](https://ci.appveyor.com/api/projects/status/4mpe0tbu7n126vyw?svg=true)](https://ci.appveyor.com/project/yuleyule66/cap)
  4. [![NuGet](https://img.shields.io/nuget/v/DotNetCore.CAP.svg)](https://www.nuget.org/packages/DotNetCore.CAP/)
  5. [![NuGet Preview](https://img.shields.io/nuget/vpre/DotNetCore.CAP.svg?label=nuget-pre)](https://www.nuget.org/packages/DotNetCore.CAP/)
  6. [![Member project of .NET Core Community](https://img.shields.io/badge/member%20project%20of-NCC-9e20c9.svg)](https://github.com/dotnetcore)
  7. [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/dotnetcore/CAP/master/LICENSE.txt)
  8. CAP 是一个基于 .NET Standard 的 C# 库,它是一种处理分布式事务的解决方案,同样具有 EventBus 的功能,它具有轻量级、易使用、高性能等特点。
  9. 你可以在这里[CAP Wiki](https://github.com/dotnetcore/CAP/wiki)看到更多详细资料。
  10. ## 预览(OverView)
  11. 在我们构建 SOA 或者 微服务系统的过程中,我们通常需要使用事件来对各个服务进行集成,在这过程中简单的使用消息队列并不能保证数据的最终一致性,
  12. CAP 采用的是和当前数据库集成的本地消息表的方案来解决在分布式系统互相调用的各个环节可能出现的异常,它能够保证任何情况下事件消息都是不会丢失的。
  13. 你同样可以把 CAP 当做 EventBus 来使用,CAP提供了一种更加简单的方式来实现事件消息的发布和订阅,在订阅以及发布的过程中,你不需要继承或实现任何接口。
  14. 这是CAP集在ASP.NET Core 微服务架构中的一个示意图:
  15. ![cap.png](http://oowr92l0m.bkt.clouddn.com/cap.png)
  16. > CAP 实现了 [eShop 电子书](https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/subscribe-events#designing-atomicity-and-resiliency-when-publishing-to-the-event-bus) 中描述的发件箱模式
  17. ## Getting Started
  18. ### NuGet
  19. 你可以运行以下下命令在你的项目中安装 CAP。
  20. ```
  21. PM> Install-Package DotNetCore.CAP
  22. ```
  23. CAP 支持 Kafka 或者 RabbitMQ 消息队列,你可以选择下面的包进行安装:
  24. ```
  25. PM> Install-Package DotNetCore.CAP.Kafka
  26. PM> Install-Package DotNetCore.CAP.RabbitMQ
  27. ```
  28. CAP 提供了 Sql Server, MySql, PostgreSQL,MongoDB 的扩展作为数据库存储:
  29. ```
  30. // 按需选择安装你正在使用的数据库
  31. PM> Install-Package DotNetCore.CAP.SqlServer
  32. PM> Install-Package DotNetCore.CAP.MySql
  33. PM> Install-Package DotNetCore.CAP.PostgreSql
  34. PM> Install-Package DotNetCore.CAP.MongoDB
  35. ```
  36. ### Configuration
  37. 首先配置CAP到 Startup.cs 文件中,如下:
  38. ```c#
  39. public void ConfigureServices(IServiceCollection services)
  40. {
  41. ......
  42. services.AddDbContext<AppDbContext>();
  43. services.AddCap(x =>
  44. {
  45. //如果你使用的 EF 进行数据操作,你需要添加如下配置:
  46. x.UseEntityFramework<AppDbContext>(); //可选项,你不需要再次配置 x.UseSqlServer 了
  47. //如果你使用的Ado.Net,根据数据库选择进行配置:
  48. x.UseSqlServer("数据库连接字符串");
  49. x.UseMySql("Your ConnectionStrings");
  50. x.UsePostgreSql("Your ConnectionStrings");
  51. //如果你使用的 MongoDB,你可以添加如下配置:
  52. x.UseMongoDB("Your ConnectionStrings"); //注意,仅支持MongoDB 4.0+集群
  53. //如果你使用的 RabbitMQ 或者 Kafka 作为MQ,根据使用选择配置:
  54. x.UseRabbitMQ("localhost");
  55. x.UseKafka("localhost");
  56. });
  57. }
  58. ```
  59. ### 发布
  60. 在 Controller 中注入 `ICapPublisher` 然后使用 `ICapPublisher` 进行消息发送
  61. ```c#
  62. public class PublishController : Controller
  63. {
  64. private readonly ICapPublisher _capBus;
  65. public PublishController(ICapPublisher capPublisher)
  66. {
  67. _capBus = capPublisher;
  68. }
  69. //不使用事务
  70. [Route("~/without/transaction")]
  71. public IActionResult WithoutTransaction()
  72. {
  73. _capBus.Publish("xxx.services.show.time", DateTime.Now);
  74. return Ok();
  75. }
  76. //Ado.Net 中使用事务,自动提交
  77. [Route("~/adonet/transaction")]
  78. public IActionResult AdonetWithTransaction()
  79. {
  80. using (var connection = new MySqlConnection(ConnectionString))
  81. {
  82. using (var transaction = connection.BeginTransaction(_capBus, autoCommit: true))
  83. {
  84. //业务代码
  85. _capBus.Publish("xxx.services.show.time", DateTime.Now);
  86. }
  87. }
  88. return Ok();
  89. }
  90. //EntityFramework 中使用事务,自动提交
  91. [Route("~/ef/transaction")]
  92. public IActionResult EntityFrameworkWithTransaction([FromServices]AppDbContext dbContext)
  93. {
  94. using (var trans = dbContext.Database.BeginTransaction(_capBus, autoCommit: true))
  95. {
  96. //业务代码
  97. _capBus.Publish("xxx.services.show.time", DateTime.Now);
  98. }
  99. return Ok();
  100. }
  101. }
  102. ```
  103. ### 订阅
  104. **Action Method**
  105. 在 Action 上添加 CapSubscribeAttribute 来订阅相关消息。
  106. ```c#
  107. public class PublishController : Controller
  108. {
  109. [CapSubscribe("xxx.services.show.time")]
  110. public void CheckReceivedMessage(DateTime datetime)
  111. {
  112. Console.WriteLine(datetime);
  113. }
  114. }
  115. ```
  116. **Service Method**
  117. 如果你的订阅方法没有位于 Controller 中,则你订阅的类需要继承 `ICapSubscribe`:
  118. ```c#
  119. namespace xxx.Service
  120. {
  121. public interface ISubscriberService
  122. {
  123. public void CheckReceivedMessage(Person person);
  124. }
  125. public class SubscriberService: ISubscriberService, ICapSubscribe
  126. {
  127. [CapSubscribe("xxx.services.show.time")]
  128. public void CheckReceivedMessage(DateTime datetime)
  129. {
  130. }
  131. }
  132. }
  133. ```
  134. 然后在 Startup.cs 中的 `ConfigureServices()` 中注入你的 `ISubscriberService` 类
  135. ```c#
  136. public void ConfigureServices(IServiceCollection services)
  137. {
  138. //注意: 注入的服务需要在 `services.AddCap()` 之前
  139. services.AddTransient<ISubscriberService,SubscriberService>();
  140. services.AddCap(x=>{});
  141. }
  142. ```
  143. #### 订阅者组
  144. 订阅者组的概念类似于 Kafka 中的消费者组,它和消息队列中的广播模式相同,用来处理不同微服务实例之间同时消费相同的消息。
  145. 当CAP启动的时候,她将创建一个默认的消费者组,如果多个相同消费者组的消费者消费同一个Topic消息的时候,只会有一个消费者被执行。
  146. 相反,如果消费者都位于不同的消费者组,则所有的消费者都会被执行。
  147. 相同的实例中,你可以通过下面的方式来指定他们位于不同的消费者组。
  148. ```C#
  149. [CapSubscribe("xxx.services.show.time", Group = "group1" )]
  150. public void ShowTime1(DateTime datetime)
  151. {
  152. }
  153. [CapSubscribe("xxx.services.show.time", Group = "group2")]
  154. public void ShowTime2(DateTime datetime)
  155. {
  156. }
  157. ```
  158. `ShowTime1` and `ShowTime2` are In different groups, they will be called at the same time.
  159. BTW, You can specify the default group name in the configuration :
  160. ```C#
  161. services.AddCap(x =>
  162. {
  163. x.DefaultGroup = "default-group-name";
  164. });
  165. ```
  166. ### Dashboard
  167. CAP 2.1+ 以上版本中提供了仪表盘(Dashboard)功能,你可以很方便的查看发出和接收到的消息。除此之外,你还可以在仪表盘中实时查看发送或者接收到的消息。
  168. 在分布式环境中,仪表盘内置集成了 [Consul](http://consul.io) 作为节点的注册发现,同时实现了网关代理功能,你同样可以方便的查看本节点或者其他节点的数据,它就像你访问本地资源一样。
  169. ```c#
  170. services.AddCap(x =>
  171. {
  172. //...
  173. // 注册 Dashboard
  174. x.UseDashboard();
  175. // 注册节点到 Consul
  176. x.UseDiscovery(d =>
  177. {
  178. d.DiscoveryServerHostName = "localhost";
  179. d.DiscoveryServerPort = 8500;
  180. d.CurrentNodeHostName = "localhost";
  181. d.CurrentNodePort = 5800;
  182. d.NodeId = 1;
  183. d.NodeName = "CAP No.1 Node";
  184. });
  185. });
  186. ```
  187. 仪表盘默认的访问地址是:[http://localhost:xxx/cap](http://localhost:xxx/cap),你可以在`d.MatchPath`配置项中修改`cap`路径后缀为其他的名字。
  188. ![dashboard](http://images2017.cnblogs.com/blog/250417/201710/250417-20171004220827302-189215107.png)
  189. ![received](http://images2017.cnblogs.com/blog/250417/201710/250417-20171004220934115-1107747665.png)
  190. ![subscibers](http://images2017.cnblogs.com/blog/250417/201710/250417-20171004220949193-884674167.png)
  191. ![nodes](http://images2017.cnblogs.com/blog/250417/201710/250417-20171004221001880-1162918362.png)
  192. ## 贡献
  193. 贡献的最简单的方法之一就是是参与讨论和讨论问题(issue)。你也可以通过提交的 Pull Request 代码变更作出贡献。
  194. ### License
  195. MIT