消息隊列,如何降低消息隊列系統中消息的延遲
當項目中引入了消息隊列時,增加了系統的複雜度。需要考慮如何保證消息不會丟失、如何避免消息重複帶來的影響、還需要考慮消息延遲情況,即消費性能的問題。
場景:上游服務器產生訂單數據,並將數據放入消息隊列服務中,但是下游系統消費較慢,造成消息隊列出現大量堆積。下游系統處理消息出現了延遲。
如何來解決這個問題呢?
- 監控消息的延遲
- 減少消息延遲的正確做法
1 如何監控消息延遲
監控消息的延遲有兩種方式:
- 使用消息隊列提供的工具,通過監控消息的堆積來完成監控
- 通過生成監控消息的方式來監控消息的延遲情況
1.1 使用消息隊列提供的工具
1、在 Kafka 中,提供了 ”kafka-consoumer-groups.sh“ 在 bin 目錄下。
通過命令查看消息積累情況
./bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --describe --group test-consumer-group
2、使用工具 JMX
Kafka 通過 JMX 暴露了消息堆積的數據,我在本地啓動了一個 console consumer,然後使用 jconsole 連接 consumer 就可以看到 consumer 的堆積數據了
1.2 通過生成監控消息的方式監控消息的延遲
1、定義一個特殊的信息,
2、啓動一個監控程序將這個消息定時地循環寫入到消息隊列中
3、消息的內容可以是生成消息的時間戳並作爲隊列的消費這消費數據
4、業務處理程序消費到這個數據時可以直接丟棄掉
5、監控程序在消費到這個消息就可以和消息的生成時間做比較
6、如果時間差達到某一個閥值就報警
2 減少消息延遲的正確做法
減少消息的處理演示,可以在消費端和消息隊列自身兩個地方進行優化。
2.1 在消費端提升
- 優化消費代碼提升消費性能
- 增加消費者數量(Kafka不支持)
如果不能添加 consumer ,可以在一個 consumer 中提升消息的並行度,採用多線程來進行處理,以便提高消息消費的吞吐量。
2.2 消息隊列
消息隊列本身在讀取性能優化方面可以考慮
- 消息的存儲
- 零拷貝技術
消息存儲,普通的數據庫來存儲消息,但是受限於數據庫的性能瓶頸,如果使用本地磁盤作爲存儲介質。Page Cache 的存儲就可以提升消息的讀取速度。
零拷貝技術,儘量較少拷貝的次數。
在讀取消息隊列的數據時,其實就是把磁盤中的數據通過網絡發送給消費客戶端,涉及了4次數據拷貝步驟:
- 數據從磁盤拷貝到內核緩衝區;
- 系統調用將內核緩存區的數據拷貝到用戶緩衝區;
- 用戶緩衝區的數據被寫入到 Socket 緩衝區中;
- 操作系統再將 Socket 緩衝區的數據拷貝到網卡的緩衝區中。
操作系統提供了 Sendfile 函數可以減少數據被拷貝的次數。使用了 Sendfile 之後,在內核緩衝區的數據不會被拷貝到用戶緩衝區而是直接被拷貝到 Socket 緩衝區,節省了一次拷貝的過程提升了消息發送的性能。高級語言中對於 Sendfile 函數有封裝,比如說在 Java 裏面的 java.nio.channels.FileChannel 類就提供了 transferTo 方法提供了 Sendfile 的功能。