前言
自從上次 CAP 2.3 版本發布 以來,已經過去了幾個月的時間,這幾個月比較忙,所以也沒有怎么寫博客,趁着2019年到來之際(現在應該是2019年開始的時候),CAP也發布了2018年的最后一個大版本 2.4,在這個版本中,我們引入了一個新的特性,叫做“版本隔離”。
簡介
可能有些人還不知道 CAP 是什么,老規矩來一個簡介。
CAP 是一個用來解決微服務或者分布式系統中分布式事務問題的一個開源項目解決方案(https://github.com/dotnetcore/CAP)同樣可以用來作為EventBus使用,目前已經2歲了,目前已經應用到了很多的公司和項目中,
想對 CAP 更多了解的同學可以看下我的這篇文章。
在 這里 你可以查看到入門文檔,在 這里 你可以查看CAP背后的設計原理。
下面我們就來看一下這個新的特性。
版本隔離
不知道你們在實際開發的過程中有沒有遇到這種場景。
業務快速迭代,需要向前兼容
由於業務的快速迭代,在各個服務集成的過程中,消息的數據結構並不是固定不變的,有些時候我們為了適應新引入的需求,會添加或者修改一些數據結構。如果你是一套全新的系統這沒有什么問題,但是如果你的系統已經部署到生產環境了並且正在服務客戶,這就會導致新的功能在上線的時候和舊的數據結構發生不兼容,那么這些改變可能會導致出現嚴重的問題,要想解決這個問題,只能把消息隊列和持久化的消息全部清空,然后才能啟動應用程序,這對於生產環境來說顯然是致命的。
多個版本的服務端
有些時候,App的服務端需要提供多套接口,來支持不同版本的App,這些不同版本的App相同的接口和服務端交互的數據結構可能是不一樣的,所以通常情況下服務端提供不用的路由地址來適配不同版本的App調用。隨着容器技術的流行,目前有一種流行的版本隔離方案就是利用容器來提供多套不同環境的服務端,然后網關根據不同的地址來進行路由,我們目前就是這種方案,這種方案的優點是程序不用寫多套路由Action來提供多個地址,方便維護。
不同實例,使用相同的持久化表/集合
之前有同學表示,希望多個不同實例的程序可以公用相同的數據庫,在 2.4 之前的版本,我們可以通過指定不同的表名來隔離不同實例的數據庫表,即在CAP配置的時候通過配置不同的表名前綴來實現。
public void ConfigureServices(IServiceCollection services)
{
services.AddCap(x =>
{
x.UseKafka("");
x.UseMySql(opt =>
{
opt.ConnectionString = "connection string";
opt.TableNamePrefix = "appone"; // 在這里配置不同的實例使用的表名前綴
});
});
}
但是,如果想不同的實例使用相同的數據庫表怎么辦呢?也許我們可以借助這個新特性來實現。
下面我們就來給版本隔離下個定義吧。
什么是版本隔離呢? 版本隔離就是利用版本特性將消息對象按照版本划分,從而來隔離不同版本的業務或實例。
為了增加這個特性,我們做出了以下改變:
- 數據表新增版本號字段
為了實現版本隔離特性,我們在各個需要持久化的數據庫中添加了一個版本號字段,你可以使用下面的腳本來更新你的數據庫表。
**MySQL**
ALTER TABLE `cap.published` ADD Version VARCHAR(20) NULL;
ALTER TABLE `cap.received` ADD Version VARCHAR(20) NULL;
**SQL Server**
ALTER TABLE Cap.[Published] ADD Version VARCHAR(20) NULL;
ALTER TABLE Cap.[Received] ADD Version VARCHAR(20) NULL;
**PostgreSQL**
ALTER TABLE cap.published ADD "Version" VARCHAR(20) NULL;
ALTER TABLE cap.received ADD "Version" VARCHAR(20) NULL;
**MongoDb**
db.CapPublishedMessage.update({},{"$set" : {"Version" : "1"}});
db.CapReceivedMessage.update({},{"$set" : {"Version" : "1"}});
- 新的版本配置項
我們在CAP的配置項中新增了一個版本號屬性用來配置實例的版本,默認情況如果不進行配置那么會使用 v1
來作為默認值
services.AddCap(x =>
{
...
x.Version="" // 設置版本號,默認值 v1
});
- 新的 Dashboard 顯示項
我們在新的Dashboard面消息列表中添加了版本號顯示列,以提供對版本隔離特型的支持,你可以在已發送或者已接收的消息列表中查看到版本號這一列。
利用版本隔離特性
那么我們如何利用版本隔離特性來處理前面提到不同場景的問題呢?
針對不同版本的服務端,有了版本隔離特性,你現在只需要在配置的時候配置版本號字段,CAP 將自動在不同的實例中將消息划分為不同的版本,從而可以確保不同版本的消息不會被錯誤的消費或者發送。
舉例來說,App 的服務端具有不同的 Api 版本,這么不同版本的程序部署在不同的 Docker 容器中提供服務,但是 這些 Api 版本可能具有很多,通常情況下,我們會保留2-3個不同的服務端版本已適配不同的客戶端版本。那么這個時候有同學可能會問,程序做了不同版本的時候,依賴的那些具有狀態的中間件怎么辦呢?所以,這就是 CAP 提供版本隔離特性的價值所在了,眾所周知 CAP 也算是有狀態的了,因為會依賴 MQ 的一些持久化以及數據庫表的持久化,利用 CAP 提供的版本隔離特性你就不必去部署多套的消息隊列了,是不是非常棒? 😃
下面是舉例 Basket 服務,不同版本的配置示例
// Basket v1
services.AddCap(x =>
{
...
x.Version="v1"
});
// Basket v2
services.AddCap(x =>
{
...
x.Version="v2"
});
同樣的,針對上面提到的 “不同實例,使用相同的持久化表/集合” 這個問題怎么利用這個特性來解決呢?
很簡單,我們可以在配置的時候將版本號字段配置為你要想實例名即可。例如我有兩個服務,分別為購物車服務和個人中心服務,他們都使用的相同的數據庫,在這之前 CAP 要求必須分配不同的持久化表來存儲消息(通過配置表明前綴),例如發消息的表需要為類似 cap.basket.published
和 cap.usercenter.published
。現在利用版本隔離特性就可以使用同一張表了,可以這樣配置:
// Basket 服務配置
services.AddCap(x =>
{
...
x.Version="basket-v1" // 設置實例名稱+版本號
});
// UserCenter 服務配置
services.AddCap(x =>
{
...
x.Version="usercenter-v1" // 設置實例名稱+版本號
});
注意:basket-v1
這后面的 -v1
是可選的,如果你的服務端用不到版本這個特性,去掉即可。
總結
CAP經過兩年的發展,GitHub 已經超過了2000 Star, 目前已經是一個成熟的組件了。有同學反映,他們最近有一些大型的微服務項目也開始使用 CAP 了,CAP 在我們系統上線也接近一年了,非常的穩定,沒有出過一次問題,所以大家在做微服務項目的時候,不用再有什么擔心的了,不管是線上成功案例還是文檔示例視頻教程這些都非常完善成熟了。
也感謝大家兩年來的支持,我們很開心能夠幫助到大家
。大家在使用的過程中遇到問題希望也能夠積極的反饋,幫助CAP變得越來越好。😃
如果你覺得本篇文章對您有幫助的話,感謝您的【推薦】。
如果你對 .NET Core 有興趣的話可以關注我,我會定期的在博客分享我的學習心得。
本文地址:http://www.cnblogs.com/savorboard/p/cap-2-4.html
作者博客:Savorboard
本文原創授權為:署名 - 非商業性使用 - 禁止演繹,協議普通文本 | 協議法律文本