CAP 7.0 版本發佈通告 - 支持延遲消息,性能炸了?

前言

今天,我們很高興宣佈 CAP 發佈 7.0 版本正式版,我們在這個版本中帶來了大批新特性以及對性能的優化和改進。

自從今年 1月份發佈 6.0 版本以來,已經過去了快1年的時間。在過去的將近1年的時間裏,我們也發佈了幾個次要版本和小版本(6.0.1, 6.1.0, 6.2.0, 6.2.1),在這裏要感謝這些版本的使用者以及向我們報告 Bug 和反饋問題的用戶。

同時,還要感謝一些我們的貢獻者,是他們在幫助 CAP 變得更加完善和易用,以下是我們的所有貢獻者。

好了,廢話不多說,接下來我們具體看一下 7.0 帶來的新變化吧。

總覽

項目地址:https://github.com/dotnetcore/CAP
開源協議:MIT

本次在 CAP 7.0 版本中我們主要帶來了以下新特性:

  • 性能改進
  • 支持發佈延遲消息
  • Dashboard 支持對延遲消息查看和操作
  • 添加支持度量(Metric)的可觀測性指標
  • Dashboard 添加新圖表支持 Metric 實時查看
  • 支持手動 Start/Stop CAP 進程
  • 其他改進
    • 新增 EnableConsumerPrefetch 配置項
    • RabbitMQ 新增 PublishConfirms 配置項
    • 更改框架目標從 netstandard 到 net6
    • 更新 NuGet 到最新版
  • 破壞性改變
    • 過濾器接口方法由同步更改爲異步
    • IConsumerClient 的 event 改爲 delegate

性能改進

這個必須放在第一章。 😃

在 .NET 7 中,官方做了大量對於性能的改進,是迄今爲止最快的 .NET。

在 CAP 7 中,我們也做了大量對性能優化的改進,是迄今爲止最快的 CAP。

在新版本我們內部做了大量對性能的調整,我們建議有條件的用戶(項目框架爲net6+)儘量升級,廢話不多說直接壓測看數據。

我們以使用量最高的 SQL Server + RabbitMQ 組合作爲我們的測試基準。

這裏是測試服務器配置:
實例: AWS EC2(c5.4xlarge, io1卷)
操作系統: Windows Server 2019
CPU:Intel Xeon Platinum 8275CL [email protected]
核心:16 cores
內存:32G
硬盤: SSD IOPS 3000
數據庫:SQL Server 2019
消息隊列:RabbitMQ 3.11.3
壓力測試工具: Apache AB : 2.4.54-win64

壓測命令:ab.exe -c 16 -n 50000 http://localhost:5000/xxx

壓測數據:

await _cap.PublishAsync("topic", new {
    Id = Guid.NewGuid(),
    Name = "Hello World"
});

測試結果(TPS):

發佈線程數 .NET6 + CAP6 .NET7 + CAP7 CPU使用率
1個線程 746/s 1257/s 7%
4個線程 2288/s 3124/s 15%
8個線程 4732/s 6847/s 30%

下圖藍色爲 CAP 7 , 綠色爲 CAP 6.2版本。

說實話,看到這個數據我都被震驚了,我只能說4個字:“性能爆炸”。
爲了大家有個概念,給大家個參考,一個不寫任何代碼的空接口大概是 9500/s,而 CAP 每次調用操作了 2 次數據庫及 1 次 MQ,還能到 6847/s。以後再有人說性能先看看你的數據庫和硬盤吧。

可能有人會說可能是 .NET 7 平臺的性能提升的影響,所以這裏也有一個 CAP 7 在 .net6 和 .net7 的對比:

發佈線程 .NET6 + CAP7 .NET7 + CAP7
1個線程 1196 1257
4個線程 3079 3124
8個線程 6733 6847

支持發佈延遲消息

一直以來,我們都有用戶反饋希望我們對延遲消息的支持,提出這些想法的主要出發點是系統中有相關需求,而他們瞭解到 RabbitMQ 提供了相關插件來做到發送延遲消息,所以很多用戶在自己的項目中也是利用這一點來發送延遲消息。

在過去,我們一直沒有對延遲消息提供支持主要是因爲只有 RabbitMQ 才支持這一特性,而 RabbitMQ 中又需要開啓相關的第三方延遲插件才能實現,而 CAP 的目標是對 Broker 提供上層抽象,所以我們需要提供一致的使用體驗,這樣用戶不需要關心他使用的 Broker 是否能夠發送延遲消息,所以在過去我們一直都沒有支持。

現在,在 CAP 7.0 版本中,我們內置實現了一套輕量級的調度器,從而可以做到直接支持發送延遲消息而不需要關心 Broker 是否支持。新版本的延遲消息做到了不對目前數據結構做調整的情況下實現的,也就是說目前的數據庫表結構不會發生任何變化也不會添加新的表,所以這不會存在任何升級兼容性問題,還是原來的配方和味道。

在 7.0 新版本中,我們的 ICapPublisher 接口新增加了兩個新方法以支持直接發送延遲消息,分別是同步的 PublishDelay 和異步的 PublishDelayAsync,同步只是對異步的包裝,推薦大家使用異步接口。

下面是一個示例用於展示如何使用:

public class PublishController : Controller 
{
	[HttpGet]
	public async Task PublishDelay([FromServices] ICapPublisher _capPubliser) 
	{
		await _capPublisher.PublishDelayAsync(TimeSpan.FromSeconds(100), "topic", DateTime.Now);
    }
}

在內部,延遲消息的狀態爲 Delayed,實際執行發送時間會被會存儲在 ExpiresAt 字段中,內部實現爲 CAP 的進程會每隔一分鐘掃描數據庫中要發送的下一分鐘延遲消息,然後放置到內存中調度。異常場景的處理和規則的實現就不在這裏展開講了,感興趣的朋友可以直接查看代碼。

另外,我們同樣在新版本中更新了我們的 Dashboard 以支持對延遲消息的查看,向下看。

Dashboard 支持對延遲消息查看和操作

在 7.0 中,我們更新了我們的 Dashboard 以支持對新增加延遲消息的查看功能,並且我們對我們的界面做出了一些調整,現在有更大的可視區域。

新版本的Dashboard 在底部增加了查看當前配置使用的 Broker種類或者 Storage 種類。

對於延遲消息,現在你可以在發送菜單的延遲選項卡界面上表格的最後一列看到“預計發送時間”,或者你可以點擊“立即發佈”按鈕來立即觸發消息發佈而無需等待延遲結束。

添加支持度量(Metric)可觀測性指標

我們知道OpenTelemetry主要有三部分組成,分別是Tracing,Mertics,Logging 。過去主要是對 Tracing(跟蹤)和 Logging (日誌)的支持,

其中我們在 2.6 版本中開始提供了Tracing的支持,我們在 SkyAPM.Diagnostics.CAP 包中提供了對 Skywalking 的支持以用於做分佈式跟蹤,並且在過去的 6.0 版本中,我們提供了 DotNetCore.CAP.OpenTelemerty 包對 OpenTelemetry 標準的直接支持。

上述更多的是對 Tracing 跟蹤部分的支持,那麼從 7.0 開始我們將更進一步。

在7.0 版本中,我們進一步提升了對可觀測性的支持,我們添加了對 Metrics 的支持,現在你可以利用官方提供的 dotnet-counters 工具來查看我們對外提供的Metric指標。

使用 dotnet-counters ps 命令列出 CAP 所屬的進程Id,然後使用 monitor 以查看收集的實時數據(每秒刷新一次)。

dotnet-counters ps
dotnet-counters monitor --process-id=25496 --counters=DotNetCore.CAP.EventCounter

CAP 7.0 提供了以下幾個度量指標:

  • 每秒發佈速度
  • 每秒消費速度
  • 每秒調用訂閱者速度
  • 每秒執行訂閱者平均耗時

同時,我們也在我們的Dashboard 中提供了對度量指標的直接觀測,你可以直接以圖表的形式查看更爲直觀,向下看。

Dashboard 支持 Metric 實時查看

在 CAP 7.0 中,我們改進了我們的Dashbaord,新增加了對實時度量(Metric)指標的查看。

同時我們也改進了我們的圖表組件,從 ECharts 切換到了 uPlot,uPlot提供了更小體積的同時,也帶來了更好的性能和渲染速度,還有嗯~ 附和我們的風格… :)

現在,你可以在CAP 中配置上 x.UseDashbaord() 來感受 Metric 的魅力吧。

從上圖可以看到,在 Realtime Metric Graph 中,時間軸會隨着時間實時滾動從而可以清晰的看出發佈和消費每秒的速率,同時我們對消費者執行耗時以“打點”的方式體現到了 Y1 軸上(Y0軸爲速率,Y1軸爲執行耗時)。

值得提醒的是,Y1軸不代表消費執行次數,而是每秒鐘內消費者的執行平均耗時。

支持手動 Start/Stop CAP 進程

在過去,默認情況下 CAP 隨 ASP.NET Core 宿主進程啓動,你無法(很難) 做到控制默認的停止或啓動行爲,只能按下 Ctrl+C 來停止宿主進行同時觸發停止CAP。

現在,你可以通過 IBootstrapper 接口來動態控制 CAP 啓動或停止。例如,在一個 Action 中添加如下兩個方法來控制。

[Route("~/control/start")]
public async Task<IActionResult> Start([FromServices]IBootstrapper bootstrapper)
{
    await bootstrapper.BootstrapAsync();
    return Ok();
}

[Route("~/control/stop")]
public async Task<IActionResult> Stop([FromServices] IBootstrapper bootstrapper)
{
    await bootstrapper.DisposeAsync();
    return Ok();
}

注意:如果你停止了CAP進程,則無法進行發佈或訂閱消息。

通過這個特性,可以延申出來的應用場景有很多,比如在系統在某個時候開始發送/消費消息等。

其他改進

新增 EnableConsumerPrefetch 配置項

在過去,我們默認會在消費端預取一部分消息到內存隊列,然後再分發給調度器執行,這在提高性能的同時也會產生一些問題。

例如,當訂閱方法執行過慢耗時太久時,會導致重試線程拾取到還未執行的的消息。重試線程默認拾取4分鐘前的消息,也就是說如果消費端積壓了超過4分鐘的消息就會被重新拾取到再次執行,會產生重複,雖然我們要求消費者保持冪等,但這不太友好。

在 7.0 版本中,我們改變了這個行爲,現在默認情況只會從消息隊列讀取一條,然後執行訂閱方法,執行完成後纔會讀取下一條來執行。我們新增了 EnableConsumerPrefetch 來使用以前的行爲,默認爲 false,通過設置 EnableConsumerPrefetch = true 來回到過去的行爲。

如果想提高速度,你可以通過設置 ConsumerThreadCount 來並行執行。

RabbitMQ 新增 PublishConfirms 配置項

過去,在 RabbitMQ 發佈端默認啓用了發佈確認,無法進行設置,對於一些要求高性能的場景中會限制發佈速度,所以在新版本中我們提供了配置項來讓用戶可以手動配置。

考慮到大多數場景失敗的概率很小,我們將默認值爲 false,如果你需要考慮極端場景請將其設置爲 true,這會降低吞吐量。

現在你可以通過設置 rabbitmqOption.PublishConfirms = true 來開啓發布確認,你可以在這裏查看更多關於發佈確認的信息。

更改框架目標從 netstandard 到 net6

在CAP 7.0中,我們將所有的包目標框架由 netstandard 2.1 更改到了 net6 , 對於不需要支持 netframework 或者 Xamarin 之類的目標平臺來說,支持 netstandard意義不大,這也是根據官方對庫作者的建議,所以我們遵循最佳實踐。

.NET 7 擁有向下兼容性,並且我們沒有使用到 .NET 7 特有的東西,所以我們只需將net6 作爲目標平臺即可,這樣 net6, net7 都可以使用。

更新NuGet到最新版

這個不用多說了,國際慣例在進行大版本發佈時,都會升級依賴NuGet包到最新版。

值得一提的是,我們 DotNetCore.CAP.SqlServer 的 SqlClient 升級到了最新的版本,你的SQL Server連接字符串可能需要添加 TrustServerCertificate=True
信任一下證書,否則可能會報錯。

破壞性改變

過濾器接口方法由同步更改爲異步

考慮到現在大部分代碼都是異步寫法,所以我們將訂閱過濾器接口提供的三個方法由同步改爲了異步,這個是我們做出的破壞性改變,如果你使用到了過濾器特性,升級後可能需要調整一下你的代碼。

分別是:

  • OnSubscribeExecuting 更改爲 OnSubscribeExecutingAsync
  • OnSubscribeExecuted 更改爲 OnSubscribeExecutedAsync
  • OnSubscribeException 更改爲 OnSubscribeExceptionAsync

IConsumerClient 的 event 改爲 Action/Func

這個對一般用戶沒有影響,主要影響到的是我們的社區第三方 Broker 擴展。

在新版本 IConsumerClient 接口中,OnReceiveMessage 和 OnLog 回調由 event 改爲下面兩種形式,用法不變。因爲 event 不支持異步。

public Func<TransportMessage, object?, Task>? OnMessageCallback { get; set; }

public Action<LogMessageEventArgs>? OnLogCallback { get; set; }

總結

以上,就是本版本我們做出的一些新特性和改動,感謝大家的支持,我們很開心能夠幫助到大家 。

大家在使用的過程中遇到問題希望也能夠積極的反饋,幫助CAP變得越來越好。😃

如果你喜歡這個項目,可以通過下面的連接點擊 Star 給我們支持。

GitHub stars

如果你覺得本篇文章對您有幫助的話,感謝您的【推薦】。


本文地址:http://www.cnblogs.com/savorboard/p/cap-7-0.html
作者博客:Savorboard
本文原創授權爲:署名 - 非商業性使用 - 禁止演繹,協議普通文本 | 協議法律文本

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章