閾值Java
❶ ZMQ JAVA使用經驗之 ZMQ簡介怎麼解決
ZMQ JAVA使用經驗之 ZMQ簡介怎麼解決:
ZMQ被稱為史上最快消息隊列,它處於會話層之上,應用層之下,使用後台非同步線程完成消息的接受和發送,完美的封裝了Socket API,大大簡化了編程人員的復雜度,被稱為史上最強大的消息中間件。ZMQ是用C語言編寫的,30s內完成消息的傳輸,能夠兼容多個平台,多種語言,可以使用多種方式實現N對N的Socket連接。本文僅以JAVA版本的ZMQ API為例,介紹ZMQ。
ZMQ與傳統的TCP Socket相比,具有以下優點:
1) ZMQ發送和接受的是具有固定長度的二進制對象,ZMQ的消息包最大254個位元組,前6個位元組是協議,然後是數據包。數據包由3個部分組成,第一個位元組是包的長度,第二個位元組是包的一些屬性,最後是包的內容。如果超過255個位元組(有一個位元組表示包屬性),則ZMQ會自動分包傳輸;而對於TCP Socket,是面向位元組流的連接,編程人員需要處理數據塊與數據塊之間的邊界問題,而ZMQ能夠保證每次用戶發送和接受的都是一個完整的數據塊;
2) 傳統的TCP Socket的連接是1對1的,可以認為「1個Socket=1個連接」,每一個線程獨立的維護一個Socket。但是ZMQ摒棄了這種1對1的模式,ZMQ的Socket可以很輕松的實現1對N,N對1和N對N的連接模式,一個ZMQ的Socket可以自動的維護一組連接,用戶無法操作這些連接,用戶只能操作套接字,而不是連接本身,所以說ZMQ的世界裡,連接是私有的。這里大家關心的一點是,一個Socket是如何識別來自多個Socket的連接的,這里以請求響應模式為例介紹ZMQ是如何實現一個Socket連接N個Socket的;
3)ZMQ使用非同步後台線程處理接受和發送請求,這意味著發送完消息,不可以立即釋放資源,消息什麼時候發送用戶是無法控制的,同時,ZMQ自動重連,這意味著用戶可以以任意順序加入到網路中,伺服器也可以隨時加入或者退出網路;
ZMQ之所以能夠在無狀態的網路中實現1對N的連接,關鍵在於信封的機制,信封里保存了應答目標的位置。ZMQ涉及到請求-響應模式的Socket一共有4種類型:
DEALER是一種負載均衡,它會將消息分發給已連接的節點,並使用公平隊列的機制處理接受到的消息。
REQ發送消息時會在消息頂部插入一個空幀,接受時會將空幀移去。其實REQ是建立在DEALER之上的,但REQ只有當消息發送並接受到回應後才能繼續運行。
ROUTER在收到消息時會在頂部添加一個信封,標記消息來源。發送時會通過該信封決定哪個節點可以獲取到該條消息。
REP在收到消息時會將第一個空幀之前的所有信息保存起來,將原始信息傳送給應用程序。在發送消息時,REP會用剛才保存的信息包裹應答消息。REP其實是建立在ROUTER之上的,但和REQ一樣,必須完成接受和發送這兩個動作後才能繼續。
在了解了4種類型的Socket之後,我們就不難理解ZMQ的信封機制了。ZMQ信封機制的核心是Router Socket,它的工作原理如下:
從ROUTER中讀取一條消息時,ZMQ會包上一層信封,上面註明了消息的來源。向ROUTER寫入一條消息時(包含信封),ZMQ會將信封拆開,並將消息遞送給相應的對象。當REQ Socket向ROUTER Socket發送一條請求後,REP會從ROUTER收到一條消息,消息格式如下:
第三幀是REP從應用程序收到的數據,第二幀是空幀,是REQ在發送ROUTER數據之前添加的,用來表示結束,第一幀即信封,是ROUTER添加的,主要用來記錄消息來源;整個數據包處理過程如下:
對於REQ Socket,可以在創建Socket的時候,為該Sock指定標示符,此時的Socket稱為持久Socket,沒有指定標示符的我們稱為瞬時Socket,ROUTER會自動為瞬時Socket生成一個標示符;
這樣REP返回包含信封的數據給ROUTER,ROUTER就可以根據信封上的標示符將該消息發送到對應的REQ上;
ZMQ使用注意事項:
ZMQ是在發送端緩存消息的,可以通過閾值控制消息的溢出;
ZMQ不可以線程之間共享Socket,否則會報org.zeromq.ZMQException: Operation cannot be accomplished in current state錯誤。
ZMQ一個進程只允許有一個Context,new Context(int arg) arg表示後台線程的數量;
ZMQ的Socket類有一個Linger參數,可以通過SetLinger設置,主要用於表示該Socket關閉以後,未發送成功的消息是否還保存,如果設置為-1表示該消息將永久保存(除非宕機,ZMQ是不持久化消息的),如果為0表示所有未發送成功的消息在Socker關閉以後都將立即清除,如果是一個正數,則表示該消息在Socket關閉後多少毫秒內被刪除;這個方法非常有用,尤其在控制發送失敗時,是否重發消息。