1. 程式人生 > >SAAS技術交流系列(一)

SAAS技術交流系列(一)

一、  訊息佇列的概念

訊息佇列中介軟體是分散式系統中重要的元件,主要解決應用耦合,非同步訊息,流量削鋒等問題。實現高效能,高可用,可伸縮和最終一致性架構。是大型分散式系統不可缺少的中介軟體。目前在生產環境,使用較多的訊息佇列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ等。

二、 訊息佇列的應用場景

常用的使用場景。非同步處理,應用解耦,流量削鋒和訊息通訊。

1、非同步處理

場景說明: 使用者註冊後,需要發註冊郵件和註冊簡訊。傳統的做法有兩種1.序列的方式;2.並行方式。

(1)序列方式:將註冊資訊寫入資料庫成功後,傳送註冊郵件,再發送註冊簡訊。以上三個任務全部完成後,返回給客戶端。

(2)並行方式:將註冊資訊寫入資料庫成功後,傳送註冊郵件的同時,傳送註冊簡訊。以上三個任務完成後,返回給客戶端。與序列的差別是,並行的方式可以提高處理的時間。

小結:如以上案例描述,傳統的方式系統的效能(併發量,吞吐量,響應時間)會有瓶頸。如何解決這個問題呢?引入訊息佇列,將不是必須的業務邏輯,非同步處理。

2、應用解耦

場景說明:使用者下單後,訂單系統需要通知庫存系統。傳統的做法是,訂單系統呼叫庫存系統的介面

傳統模式的缺點:

1)假如庫存系統無法訪問,則訂單減庫存將失敗,從而導致訂單失敗;

2)訂單系統與庫存系統耦合;

l  訂單系統:使用者下單後,訂單系統完成持久化處理,將訊息寫入訊息佇列,返回使用者訂單下單成功。

l  庫存系統:訂閱下單的訊息,採用拉/推的方式,獲取下單資訊,庫存系統根據下單資訊,進行庫存操作。

l  假如:在下單時庫存系統不能正常使用。也不影響正常下單,因為下單後,訂單系統寫入訊息佇列就不再關心其他的後續操作了。實現訂單系統與庫存系統的應用解耦。

3、流量削峰

流量削鋒也是訊息佇列中的常用場景,一般在秒殺或團搶活動中使用廣泛。

應用場景:秒殺活動,一般會因為流量過大,導致流量暴增,應用掛掉。為解決這個問題,一般需要在應用前端加入訊息佇列。

l  可以控制活動的人數;

l  可以緩解短時間內高流量壓垮應用;

l 使用者的請求,伺服器接收後,首先寫入訊息佇列。假如訊息佇列長度超過最大數量,則直接拋棄使用者請求或跳轉到錯誤頁面;

l  秒殺業務根據訊息佇列中的請求資訊,再做後續處理。

4、日誌處理

日誌處理是指將訊息佇列用在日誌處理中,比如Kafka的應用,解決大量日誌傳輸的問題。

l  日誌採集客戶端,負責日誌資料採集,定時寫受寫入Kafka佇列;

l  Kafka訊息佇列,負責日誌資料的接收,儲存和轉發;

l  日誌處理應用:訂閱並消費kafka佇列中的日誌資料;

新浪kafka日誌處理應用案例:

(1)Kafka:接收使用者日誌的訊息佇列。

(2)Logstash:做日誌解析,統一成JSON輸出給Elasticsearch。

(3)Elasticsearch:實時日誌分析服務的核心技術,一個schemaless,實時的資料儲存服務,通過index組織資料,兼具強大的搜尋和統計功能。

(4)Kibana:基於Elasticsearch的資料視覺化元件,超強的資料視覺化能力是眾多公司選擇ELKstack的重要原因。

5、訊息通訊

訊息通訊是指,訊息佇列一般都內建了高效的通訊機制,因此也可以用在純的訊息通訊。比如實現點對點訊息佇列,或者聊天室等。客戶端A,客戶端B,客戶端N訂閱同一主題,進行訊息釋出和接收。實現類似聊天室效果。

三、 訊息模型

1、P2P模式

P2P模式包含三個角色:訊息佇列(Queue),傳送者(Sender),接收者(Receiver)。每個訊息都被髮送到一個特定的佇列,接收者從佇列中獲取訊息。佇列保留著訊息,直到他們被消費或超時。

P2P的特點:

l  每個訊息只有一個消費者(Consumer)(即一旦被消費,訊息就不再在訊息佇列中)

l  傳送者和接收者之間在時間上沒有依賴性,也就是說當傳送者傳送了訊息之後,不管接收者有沒有正在執行,它不會影響到訊息被髮送到佇列

l  接收者在成功接收訊息之後需向佇列應答成功

如果希望傳送的每個訊息都會被成功處理的話,那麼需要P2P模式。

2、Pub / Sub模式

包含三個角色主題(Topic),釋出者(Publisher),訂閱者(Subscriber) 。多個釋出者將訊息傳送到Topic,系統將這些訊息傳遞給多個訂閱者。

Pub/Sub的特點:

l  每個訊息可以有多個消費者

l  釋出者和訂閱者之間有時間上的依賴性。針對某個主題(Topic)的訂閱者,它必須建立一個訂閱者之後,才能消費釋出者的訊息。

l  為了消費訊息,訂閱者必須保持執行的狀態。

為了緩和這樣嚴格的時間相關性,JMS允許訂閱者建立一個可持久化的訂閱。這樣,即使訂閱者沒有被啟用(執行),它也能接收到釋出者的訊息。

如果希望傳送的訊息可以不被做任何處理、或者只被一個訊息者處理、或者可以被多個消費者處理的話,那麼可以採用Pub/Sub模型。

四、 RabbitMQ訊息佇列

RabbitMQ是流行的開源訊息佇列系統,用erlang語言開發。RabbitMQ是AMQP(高階訊息佇列協議)的標準實現。支援多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支援AJAX,持久化。用於在分散式系統中儲存轉發訊息,在易用性、擴充套件性、高可用性等方面表現不俗。

 

幾個重要概念:

Broker:簡單來說就是訊息佇列伺服器實體。

Exchange:訊息交換機,它指定訊息按什麼規則,路由到哪個佇列。

Queue:訊息佇列載體,每個訊息都會被投入到一個或多個佇列。

Binding:繫結,它的作用就是把exchange和queue按照路由規則繫結起來。

Routing Key:路由關鍵字,exchange根據這個關鍵字進行訊息投遞。

vhost:虛擬主機,一個broker裡可以開設多個vhost,用作不同使用者的許可權分離。

producer:訊息生產者,就是投遞訊息的程式。

consumer:訊息消費者,就是接受訊息的程式。

channel:訊息通道,在客戶端的每個連線裡,可建立多個channel,每個channel代表一個會話任務。

訊息佇列的使用過程,如下:

(1)客戶端連線到訊息佇列伺服器,開啟一個channel。

(2)客戶端宣告一個exchange,並設定相關屬性。

(3)客戶端宣告一個queue,並設定相關屬性。

(4)客戶端使用routing key,在exchange和queue之間建立好繫結關係。

(5)客戶端投遞訊息到exchange。

exchange接收到訊息後,就根據訊息的key和已經設定的binding,進行訊息路由,將訊息投遞到一個或多個佇列裡。

五、 RabbitMQ與Redis作為訊息佇列的區別

1、RabbitMQ

RabbitMQ是實現AMQP(高階訊息佇列協議)的訊息中介軟體的一種,最初起源於金融系統,用於在分散式系統中儲存轉發訊息,在易用性、擴充套件性、高可用性等方面表現不俗。訊息中介軟體主要用於元件之間的解耦,訊息的傳送者無需知道訊息使用者的存在,反之亦然。

2、Redis

Redis是一個Key-Value的NoSQL資料庫,開發維護很活躍,雖然它是一個Key-Value資料庫儲存系統,但它本身支援MQ功能,所以完全可以當做一個輕量級的佇列服務來使用。

3、具體對比

1) 可靠消費

Redis:沒有相應的機制保證訊息的消費,當消費者消費失敗的時候,訊息體丟失,需要手動處理。

RabbitMQ:具有訊息消費確認,即使消費者消費失敗,也會自動使訊息體返回原佇列,同時可全程持久化,保證訊息體被正確消費。

2) 可靠釋出

Reids:不提供,需自行實現。

RabbitMQ:具有釋出確認功能,保證訊息被髮布到伺服器。

3)  高可用

Redis:採用主從模式,讀寫分離,但是故障轉移還沒有非常完善的官方解決方案。

RabbitMQ:叢集採用磁碟、記憶體節點,任意單點故障都不會影響整個佇列的操作。

4)  持久化

Redis:將整個Redis例項持久化到磁碟。

RabbitMQ:佇列,訊息,都可以選擇是否持久化。

5)  消費者負載均衡

Redis:不提供,需自行實現。

RabbitMQ:根據消費者情況,進行訊息的均衡分發。

6) 佇列監控

Redis:不提供,需自行實現。

RabbitMQ:後臺可以監控某個佇列的所有資訊,(記憶體,磁碟,消費者,生產者,速率等)。

7) 流量控制

Redis:不提供,需自行實現。

RabbitMQ:伺服器過載的情況,對生產者速率會進行限制,保證服務可靠性。

8) 出入隊效能

對於RabbitMQ和Redis的入隊和出隊操作,各執行100萬次,每10萬次記錄一次執行時間。測試資料分為128Bytes、512Bytes、1K和10K四個不同大小的資料。

六、小結

      對於那些實時性要求不高,且比較耗時的任務,是佇列的最佳應用場景。比如說在某網站註冊一個賬號,當我的資訊入庫註冊成功後,網站需要傳送一封啟用郵件,啟用賬號,而這個發郵件的操作並不是需要實時響應的,沒有必要卡在那個註冊介面,等待郵件傳送成功,再說傳送郵件本來就是一個耗時的操作(需要呼叫第三方smtp伺服器),此時,選擇訊息佇列去處理。註冊完成,只需要向佇列投遞一個訊息,訊息的內容中包含我要傳送郵件的一些設定,以及傳送時間,重試次數等訊息屬性。這裡的投遞操作(可以是入庫,寫入快取等)是要訊息進入一個實體的佇列。其中應該有一程序(消費者)一直在後臺執行,他不斷的去輪訓佇列中的訊息(按照時間正序,佇列是先進先出),看有沒有達到執行條件的,如果有就取出一條,根據訊息配置,執行任務,如果成功,則銷燬這條訊息,繼續輪訓,如果失敗,則重試,知道達到重試次數。這時使用者已經收到註冊成功的提示,但是已經去做其他事了,郵件也來了,使用者點選郵件,註冊成功。這就是訊息佇列的一個典型應用。
       點贊場景,這個在高併發的情況下,很容易造成資料庫連線數佔滿,到時整個網站響應緩慢,才是就是想到要解決資料庫的壓力問題,一般就是兩種方案,一是提高資料庫本身的能力(如增加連線數,讀寫分離等),但是資料庫總是有極限的,到達了極限無法再提升了,此時就要考慮第二種方案,釋放資料庫的壓力,將壓力轉移到快取裡面。就拿實際的點贊來說吧,使用者的點贊請求到來,可以將點贊請求投遞到訊息佇列裡面,後續的點贊請求可以將訊息合併,即只更新點贊數,不產生新的任務,此時有個程序不斷的輪訓訊息佇列,將點贊訊息消耗,並將值更新到資料庫裡面,這樣就有效的降低了資料庫的壓力,因為在快取層將數個數據庫更新請求合併成一個,大大提高了效率,降低了負載。

    無論哪種訊息佇列都需要依據實際的業務來進行合理的選型,才能實現更好地效果。

七、參考文章

http://blog.csdn.net/shaobingj126/article/details/50585035 大型網站架構之分散式訊息佇列

http://www.cnblogs.com/wanpengcoder/p/5291627.html RabbitMQ訊息佇列(三):釋出 / 訂閱

http://blog.csdn.net/shudaqi2010/article/details/53639628 Redis作為訊息佇列與RabbitMQ的效能對比