CAP 2.3版本发布,支持 MongoDB
前言
經過2個月的調整及測試,CAP 2.3 版本終于發布了,這個版本最大的特性就是對于 MongoDB 的支持,感謝博客園團隊的keke同學對于 MongoDB 支持所提供的 PR,相信隨著博客園的使用,CAP 會越來越多的幫助到更多的人。
CAP?是一個用來解決微服務或者分布式系統中分布式事務問題的一個開源項目解決方案(https://github.com/dotnetcore/CAP),目前已經將近2歲了,想對 CAP 更多了解的同學可以看下我的這篇文章。
背景故事
在 2.3 版本中,我們對 Api 做了一些調整,為什么做這些調整呢?我就來說一下這中間的過程
相信在用 CAP 的同學們都知道在2.2以及以前的版本中存在一個 Bug 就是在使用事務的情況下消息持久化到數據庫后如果還沒有提交事務,那么這個時候 CAP 就會開始向消息隊列中發送消息,但是有一個問題就是如果接下來事務提交失敗,這個時候其實消息已經被發送出去了,就會導致消費端接收到了消息,對應到 GitHub 的這個?issue。
這個 Bug 要說嚴重也嚴重,要說不嚴重也不嚴重,但是我們總要解決這個問題。怎么解決呢?有些同學可能會說把發送消息改到事務提交完成后不就行了,但是 CAP 是無法獲取到業務端的事務執行結果的,因為在.NET中沒有類似于Spring Transaction這種機制可以很容易的做一些擴展,所以如果想改到事務提交后,那么就必須提供一個 API 讓用戶手動來調用進行發送。這樣看來可以很容易的解決這個問題,但是我覺得這樣對于使用者來說就要多一行代碼,需要增加學習成本以及要多理解框架內部做的一些事情,還有可能會忘記調用或者用錯。
為了讓 CAP 的使用者少寫這一行代碼,我思考了好幾個月,說一下過程吧。
對于數據庫底層驅動的代碼做過了解的同學可能知道,數據庫驅動在底層封裝的特別死,特別是對于事務這塊的處理,類都是 sealed 幾乎沒有辦法進行擴展,我做了一些嘗試都失敗了,最后都想 fork 一個數據庫驅動來修改發布自己的 Nuget 包了,但是這個方案最終被否定了,因為我自己都不愿意用自己編譯的數據庫驅動,最終這條路行不通。
另外一個方案就是對于 Diagnostics 有了解的同學可能想到了,可以利用這個特性來追蹤事務提交的結果,然后在其中做一些處理就行了。但是有個什么問題呢?目前只有 SQL Server 的驅動才支持 Diagnostics,其他的 MySql,PostgreSql 均不支持,怎么辦呢?不可能不去管使用 MySql,PostgreSql 的那些用戶,畢竟我們自己也是使用的 MySql。
我和 Lemon 同學曾分別向 MySql 和 PostgreSql C#數據庫項目提交了對 Diagnostics 特性支持的 PR(MySql PR,?PostgreSql PR),但是由于微軟對于 DiagnosticsSource API 設計的問題,導致社區對于這種 API 的方式比較反感,另外就是指導文檔中的一些原則,微軟在 SQLClient 的驅動中都沒有遵守,所以這兩個 PR 一直沒有進行合并,有興趣的也可以看下這里的討論,這樣等下去也不知道要等到什么時候。
還有一個原因是因為我們需要對接新的MongoDB,MongoDB對于事務的處理在API上有所不同,為了提供一致的用戶接口,所以需要作出一些改變。
以上,我們需要對 API 做出調整,我們不能一直停滯不前。下面我們來看一下2.3版本做出的改變吧。
CAP 2.3 版本中的改變
1、移除了CAP 中間件注冊
現在,你不需要再使用?app.UseCap()?手動添加中間件,我們將自動注冊。
在 2.3 以前的版本中,需要在 Startup 中 Configure 中注冊 CAP,現在我們已經自動的在啟動的時候進行了注冊你不再需要手動注冊。
public void Configure(IApplicationBuilder app){app.UseCap(); //移除了,不需要再手動注冊}2、修改了消息表主鍵類型
為了適配最新的MongoDB以及某些場景下的數據表遷移,我們將消息表的主鍵Id由自增長的int類型改為了由雪花算法生成的long類型,這在一定程度上可以提高消息處理的性能以及邏輯的復雜性。
由 2.2 版本升級上來的同學,我們提供了數據庫遷移腳本,你可以查看這里來獲取數據庫遷移腳本,然后在數據庫執行即可。
https://gist.github.com/yuleyule66/0e5ec7a5046dc58fcf89d51e4820c5cd
3、修改了 Publish Api
我們添加了一個新的?ICapTransaction?接口,用來控制事務的處理,同時這也是為了處理跟蹤不到事務處理接口的情況,同時我們封裝了一系列擴展方法,方便開發者使用,下面我們看一下新的Api
MongoDB:
這里的?connection.StartTransaction?是一個擴展方法,這個擴展方法返回?IClientSessionHandle?接口,它代表的是MongoDB的原生事務對象,我們在做自己業務代碼的時候拿到這個對象即可使用。
命名 StartTransaction 的原因是我們希望遵循MongoDB的命名規范,便于使用者理解
SQLServer:
這里的?connection.BeginTransaction?是一個擴展方法,這個擴展方法返回?IDbTransaction?接口,它代表的是數據庫的原生事務對象,我們在做自己業務代碼的時候使用這個對象傳到Dapper或者Ado.net中即可。
MySql 和 PostgreSql:
這里的?connection.BeginTransaction?是一個擴展方法,這個擴展方法返回?ICapTransaction?接口,接口包裝的有?DbTransaction?屬性,它代表的是數據庫的原生事務對象,我們在做自己業務代碼的時候使用這個對象傳到Dapper或者Ado.net中即可。
4、增加了事務自動提交
有些情況下,為了精簡代碼,我們不想去手動調用?transaction.Commit()?方法希望CAP去幫助你提交事務,那么也是可以做到的,你只需要在?connection.BeginTransaction?的時候傳遞參數?autoCommit?為?true?即可。
需要注意的是,當使用事務自動提交功能時,你需要在你的業務邏輯執行完成之后再發送消息,也就是說?_capBus.Publish?這行代碼需要放到最后執行。實例代碼:
using (var connection = new MySqlConnection("")) { ? ?using (var transaction = connection.BeginTransaction(_capBus, autoCommit: true)){ ? ? ? ?//your business code sample_capBus.Publish("sample.rabbitmq.mysql", DateTime.Now); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } }注意這里的?autoCommit: true,并且取消了transaction.Commit()
5、增加對 MongoDB 的支持
在微服務應用中,有時候我們的某些服務可能為了性能或者是其他原因考慮,使用的不是傳統的關系型數據庫,而且一些非關系型數據庫,比如這其中MongoDB作為代表,使用的人也最多,然后就有需求希望在存儲數據的時候也想保證數據的高一致性。
MongoDB 在 4.0 及以上版本中支持了ACID事務,這個特性使我們有理由對MongoDB提供支持,同時MongoDB的支持也是博客園的Keke同學提供的PR,再次感謝。
有些同學可能想嘗試一下,那么下面就來簡單的說一下,MongoDB 對 ACID事務的支持是需要集群才能使用,所以我們需要首先搭建一個集群,搭建集群的文章我已經寫好了,大家可以參考這篇博客來搭建。
集群搭建完成之后,在 Startup.cs 文件中的?ConfigureServices(IServiceCollection services)?中配置下即可。
public void ConfigureServices(IServiceCollection services) {services.AddSingleton<IMongoClient>(new MongoClient("mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0"));services.AddCap(x =>{x.UseMongoDB("mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0");x.UseRabbitMQ("localhost");x.UseDashboard();}); }使用方法:
注意:MongoDB 不能在事務中創建數據庫和集合,所以如果你集群創建好之后是空的,則你需要單獨先創建數據庫和集合,可以模擬一條記錄插入就會自動創建了。
var mycollection = _client.GetDatabase("test").GetCollection<BsonDocument>("test.collection"); mycollection.InsertOne(new BsonDocument { { "test", "test" } });然后
[]public IActionResult WithoutTransaction(){_capBus.Publish("sample.rabbitmq.mongodb", DateTime.Now); ? ?return Ok(); }[]public IActionResult PublishNotAutoCommit(){ ? ?//NOTE: before your test, your need to create database and collection at firstusing (var session = _client.StartTransaction(_capBus, autoCommit: true)){ ? ? ? ?var collection = _client.GetDatabase("test").GetCollection<BsonDocument>("test.collection");collection.InsertOne(session, new BsonDocument { { "hello", "world" } });_capBus.Publish("sample.rabbitmq.mongodb", DateTime.Now);} ? ?return Ok(); }總結
最近一兩個月明顯感覺到使用 CAP 的人越來越多了,博客園也出現了一些CAP的博客文章,我們很開心能夠幫助到大家
。大家在使用的過程中遇到問題希望也能夠積極的反饋,幫助CAP變得越來越好。:)
相關文章:
CAP帶你輕松玩轉ASP.NETCore消息隊列
分布式事務一致性解決方案
.NetCore Cap 結合 RabbitMQ 實現消息訂閱
.NET Core微服務之開源項目CAP的初步使用
分布式事務,EventBus 解決方案:CAP【中文文檔】
CAP 介紹及使用【視頻】
.NET Core 事件總線,分布式事務解決方案:CAP
原文地址:?https://www.cnblogs.com/savorboard/p/cap-2-3.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結
以上是生活随笔為你收集整理的CAP 2.3版本发布,支持 MongoDB的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .net core实践系列之短信服务-架
- 下一篇: .NETCore 实现容器化Docker