線上業務需要一款擁有超低延遲(us),支援多消費者,並且能夠處理海量的訊息積壓的訊息佇列。
kafka是我們日常生活中比較常見的訊息佇列,非常適合做訊息的離線處理。但是在一些實時性要求比較高的場景下,訊息自帶的延遲是不可忍受的,測試發現一條訊息**大概需要200ms的耗時,實際情況可能有所出入,但肯定是毫秒級別的。kafka從設計上就是傾向於面向大眾,滿足大部分需求。當然滿足這些要求的成本就是通過犧牲了效能。所以說kafka適合做離線處理。而不是做一些非常實時的應用。
zeromq就是針對實時應用的一款訊息佇列,提供了各個拓撲結構的鏈結方式,效能不錯,但不足的是當訊息積壓有可能會寫滿記憶體。
市面上目前的訊息佇列都與我們的設計目標不符。
要想擁有微秒級別的延遲,
不能走網路,資料必須放本地。
使用inotify等待新資料的產生。
不適用get_line, fgets等庫函式,減少資料拷貝,自己實現拆包邏輯。
讀取的buffer_size不能設定的過小,由於下游消費通常存在一定的耗時,我們盡量一次多讀取一些,否則系統呼叫read的成本很高。
當訊息產生積壓的情況,我們採用water_mark機制來自動調節每次資料讀取的最大位元組。
#include #include #include #define event_size (sizeof(struct inotify_event))
#define buf_len (10 * (event_size + filename_max + 1))
int wartermark = 1024 * 1024;
int max_buffer_size = wartermark * 6;
char *line_ = new char[10240]; // 每行緩衝區
char *buffer_ = new char[max_buffer_size]; // 檔案緩衝區
char *buffer2_ = new char[buf_len]; // inotify事件緩衝區
// 註冊監聽檔案變化
int ifd_ = inotify_init();
if (ifd_ < 0)
inotify_add_watch(ifd_, path_.c_str(), in_modify | in_create | in_delete);
// 開啟檔案
int fd_ = open(path_.c_str(), o_rdonly);
if (fd_ < 0)
// 讀取檔案
register long int buffer_size = wartermark;
register char *cs;
register int i = 0;
cs = line_;
bool ok_ = true;
while (ok_)
//remove last \n
*(--cs) = '\0';
cb_(line_);
if (!ok_) break;
cs = line_;
}if (!ok_) break;
if (read_ == wartermark) else
i = 0;
}read(ifd_, buffer2_, buf_len);
}
消費者只需要將自己業務入口註冊為cb_,就可以實現消費。
實際測試發現從訊息生產到cb_入口訊息延遲大概在100個us以內。以上**雖然實現起來很簡單,但是正是由於其簡單才保證了超高的效能。
Kafka高效能讀寫原理
kafka是高吞吐低延遲的高併發 高效能的訊息中介軟體,在大資料領域有極為廣泛的運用。配置良好的kafka集群甚至可以做到每秒幾十萬 上百萬的超高併發寫入。那麼kafka到底是如何做到這麼高的吞吐量和效能的呢?首先kafka每次接收到資料都會往磁碟上去寫,如下圖所示。那麼在這裡我們不禁有乙個疑問了,...
kafka原理解析之 高效能內幕
1.partition的持久化佇列結構 資料按先後順序依次追加在檔案末尾,讀寫操作分開,如下圖所示。這種結構有如下優勢 注 使用6個7200rpm sata介面 raid 5的磁碟陣列在jbod配置下的順序寫入的效能約為600mb 秒,但隨機寫入的效能僅約為100k 秒,相差6000倍以上。2.利用...
高效能 爬蟲原理
socket 原理 本質上就是乙個socket服務端,乙個客戶端.客戶端在連線服務端的時候只是封裝了http協議頭以及訪問的位址 阻塞 import socket 阻塞 請求 非阻塞 http用的就是這種 請求方式,請求只管發出去,而阻塞的方式還等請求連線成功再發訊息。mport socket ip...