詳解:同步架構和異步架構的區別及消息隊列

分佈式消息隊列是是大型分佈式系統不可缺乏的中間件,主要解決應用耦合、異步消息、流量削鋒等問題。實現高性能、高可用、可伸縮和最終一致性架構。前端

對於一個架構師來講,在大型系統設計中,會常常須要面對同步和異步等架構問題,搞明白這些問題,能更好地實現程序並行執行,減小等待或無效操做,以及充分利用計算機的性能!數據庫

 

本文將詳細講解:後端

1.同步架構和異步架構的區別服務器

2.異步架構的主要組成部分:消息生產者、消息消費者、分佈式消息隊列微信

3.異步架構的兩種主要模型:點對點模型和發佈訂閱模型。架構

4.消息隊列的好處
併發

5.消息隊列相關產品異步

 

建議用10min通讀,搞懂分佈式消息隊列的核心內容。分佈式

 

1、同步架構和異步架構的區別性能

 

1.同步調用     

 

是指從請求的發起一直到最終的處理完成期間,請求的調用方一直在同步阻塞等待調用的處理完成。

 

如圖,在這個例子中客戶端代碼ClientCode,須要執行發送郵件sendEmail這樣一個操做,它會調用EmailService進行發送,而EmailService會調用SmtpEmailAdapter這樣一個類來進行處理,而這個類會調用遠程的一個服務,經過SMTP和TCP協議把請求發送給它。

 

而遠程服務器收到消息之後會對消息進行一系列的操做,而後將郵件發送出去,再進行返回。Adapter收到返回後,再返回給EmailService,EmailService收到返回後再把返回結果返回給Clientcode。

  

ClientCode在sendEmail發出請求後,就一直都阻塞在這裏,等待最終調用結果的返回,是成功仍是失敗。由於這個過程是阻塞等待的,因此這個過程也就是同步調用。

               

2.異步調用

 

是指在請求發起的處理過程當中,客戶端的代碼已經返回了,它能夠繼續進行本身的後續操做,而不須要等待調用處理完成,這就叫作異步調用。

 

 

異步調用過程,一樣看剛剛發送郵件的例子,用戶Clientcode調用EmailService之後,EmailService會把這個調用請求發送給消息隊列,而後就當即返回了。Clientcode收到返回之後繼續向下處理,不會繼續阻塞等待。實際上消息發送到Queue後,尚未被處理,咱們看到後面的消息消費,其實要比EmailService返回可能還要晚一點,EmailService返回之後消息纔會被消費處理。

 

有一個QueueConsumer消息隊列的消費者,從消息隊列中取出這個消息,再把這個消息發送給SmtpAdapter,也就是調用SmtpAdapter,處理邏輯跟同步調用同樣,SmtpAdapter經過SMTP的通信協議,把消息發送給遠程的一個服務器,進行郵件發送,經過RemoteServer進行處理,處理完了收到返回,再把返回結果通知消息隊列Queue。

 

在這個過程當中,客戶端的調用,也就是應用程序的調用,和業務邏輯真正發送郵件的操做是不一樣步的。

 

2、異步架構的主要組成部分

  

使用異步調用架構的主要手段,就是經過消息隊列構建,以下是它的架構圖。     

 

消息的生產者將消息發送到消息隊列之後,由消息的消費者從消息隊列中獲取消息,而後進行業務邏輯的處理,消息的生產者和消費者是異步處理的,彼此不會等待阻塞,因此叫作異步架構。

 

使用消息隊列構建一個異步調用架構,你須要瞭解以下3種角色。

       

1.消息的生產者

 

是客戶端應用程序代碼的一部分,用來初始化異步調用處理流程。在基於消息隊列的處理中,生產者的職責很是少,它要作的就是建立一個合法的消息,並把這個消息發送到消息隊列中,由應用開發者決定生產者的代碼在哪裏執行,何時發送消息。

 

2.消息隊列

 

消息隊列是消息發送的目的地和發給消費者的一個緩衝。消息隊列實現的方法有好多種,能夠用共享文件夾,也能夠用關係數據庫或者NoSQL系統,固然最主要的仍是使用專門的分佈式消息隊列服務器來實現。

 

3.消息的消費者

 

消息的消費者從消息隊列中接受並處理消息,消息的消費者也是由應用開發者實現的,可是它是一個異步處理的組件。消息的消費者不須要知道生產者存在,它只依賴消息隊列中的消息。消息的消費者一般部署在獨立的服務器上,和消息的生產者徹底隔離,而且能夠經過添加硬件的方式進行伸縮。

 

3、異步架構的兩種主要模型

 

使用消息隊列構建異步的調用架構,你還須要知道兩種模型:點對點模型和發佈訂閱模型。

 

1.點對點模型

  

 

消費者和生產者只須要知道消息隊列的名字,生產者發送消息到消息隊列中,而消息隊列的另外一端是多個消費者競爭消費消息,每一個到達消息隊列的消息只會被路由到一個消費者中去,因此消費者看到的是所有消息的一個子集。咱們看這張圖,消息的生產者有多個,消息的消費者也有多個,多個生產者將消息發送到消息隊列中,而有多個消費者去消息隊列中對消息進行競爭性的消費。每一個消息只會被一個消費者消費,每一個消費者只會消費消息隊列中的一部分消息。

 

2.發佈訂閱模型

 

在發佈訂閱模型中,消息可能被髮送到不止一個消費者,生產者發送消息到一個主題,而不是隊列中。消息被髮布到主題後,就會被克隆給每個訂閱它的消費者,每一個消費者接收一份消息複製到本身的私有隊列。消費者能夠獨立於其餘消費者使用本身訂閱的消息,消費者之間不會競爭消息。經常使用的分佈式消息隊列都支持發佈訂閱模型,也就是說消息的發佈訂閱模型是分佈式消息隊列的一個功能特性。

 

3.兩個模型的應用

 

點對點模型:主要用於一些耗時較長的、邏輯相對獨立的業務。

 

好比說我前面的講到的發送郵件這樣一個操做。由於發送郵件比較耗時,並且應用程序其實也並不太關心郵件發送是否成功,發送郵件的邏輯也相對比較獨立,因此它只須要把郵件消息丟到消息隊列中就能夠返回了,而消費者也不須要關心是哪一個生產者去發送的郵件,它只須要把郵件消息內容取出來之後進行消費,經過遠程服務器將郵件發送出去就能夠了。並且每一個郵件只須要被髮送一次。因此消息只被一個消費者消費就能夠了。

 

發佈訂閱模型:如新用戶註冊這樣一個消息,須要使用按主題發佈的方式。

 

好比新用戶註冊,一個新用戶註冊成功之後,須要給用戶發送一封激活郵件,發送一條歡迎短信,還須要將用戶註冊數據寫入數據庫,甚至須要將新用戶信息發送給關聯企業的系統,好比淘寶新用戶信息發送給支付寶,這樣容許用戶能夠一次註冊就能登陸使用多個關聯產品。一個新用戶註冊,會把註冊消息發送給一個主題,多種消費者能夠訂閱這個主題。好比發送郵件的消費者、發送短信的消費者、將註冊信息寫入數據庫的消費者,跨系統同步消息的消費者等。

 

4、消息隊列的好處

 

 

1.實現異步處理,提高處理性能

 

對一些比較耗時的操做,能夠把處理過程經過消息隊列進行異步處理。這樣作能夠推遲耗時操做的處理,使耗時操做異步化,而沒必要阻塞客戶端的程序,客戶端的程序在獲得處理結果以前就能夠繼續執行,從而提升客戶端程序的處理性能。

 

2.可讓系統得到更好的伸縮性

 

耗時的任務能夠經過分佈式消息隊列,向多臺消費者服務器並行發送消息,而後在不少臺消費者服務器上並行處理消息,也就是說能夠在多臺物理服務器上運行消費者。那麼當負載上升的時候,能夠很容易地添加更多的機器成爲消費者。

如圖中的例子,用戶上傳文件後,經過發佈消息的方式,通知後端的消費者獲取數據、讀取文件,進行異步的文件處理操做。那麼當前端發佈更多文件的時候,或者處理邏輯比較複雜的時候,就能夠經過添加後端的消費者服務器,提供更強大的處理能力。

 

3.能夠平衡流量峯值,削峯填谷

 

使用消息隊列,即使是訪問流量持續的增加,系統依然能夠持續地接收請求。這種狀況下,雖然生產者發佈消息的速度比消費者消費消息的速度快,可是能夠持續的將消息歸入到消息隊列中,用消息隊列做爲消息的緩衝,所以短期內,發佈者不會受到消費處理能力的影響。

從這張圖能夠看到,由於消息的生產者是直接面向用戶請求的,而用戶的請求訪問壓力是不均衡的。如淘寶天天的訪問高峯是在上午10點左右,而新浪微博則可能在某個明星半夜發一條微博後忽然出現訪問高峯。

 

在訪問高峯,用戶的併發訪問數可能超過了系統的處理能力,因此在高峯期就可能會致使系統負載過大,響應速度變慢,更嚴重的可能會致使系統崩潰。這種狀況下,經過消息隊列將用戶請求的消息歸入到消息隊列中,經過消息隊列緩衝消費者處理消息的速度。

 

如圖中所示,消息的生產者它有高峯有低谷,可是到了消費者這裏,只會按照本身的最佳處理能力去消費消息。高峯期它會把消息緩衝在消息隊列中,而在低谷期它也仍是使用本身最大的處理能力去獲取消息,將前面緩衝起來、來不及及時處理的消息處理掉。那麼,經過這種手段能夠實現系統負載消峯填谷,也就是說將訪問的高峯消掉,而將訪問的低谷填平,使系統處在一個最佳的處理狀態之下,不會對系統的負載產生太大的衝擊。

 

4.失敗隔離和自我修復

 

由於發佈者不直接依賴消費者,因此分佈式消息隊列能夠將消費者系統產生的錯誤異常與生產者系統隔離開來,生產者不受消費者失敗的影響。 當在消息消費過程當中出現處理邏輯失敗的時候,這個錯誤只會影響到消費者自身,而不會傳遞給消息的生產者,也就是應用程序能夠按照原來的處理邏輯繼續執行。

 

因此,這也就意味着在任什麼時候候均可以對後端的服務器執行維護和發佈操做。能夠重啓、添加或刪除服務器,而不影響生產者的可用性,這樣簡化了部署和服務器管理的難度。

 

5.可使生產者和消費者的代碼實現解耦合

 

也就是說能夠多個生產者發佈消息,多個消費者處理消息,共同完成完整的業務處理邏輯,可是它們的不須要直接的交互調用,沒有代碼的依賴耦合。在傳統的同步調用中,調用者代碼必需要依賴被調用者的代碼,也就是生產者代碼必需要依賴消費者的處理邏輯代碼,代碼須要直接的耦合,而使用消息隊列,這兩部分的代碼不須要進行任何的耦合。

 

耦合程度越低的代碼越容易維護,也越容易進行擴展。

       

好比新用戶註冊,若是用傳統同步調用的方式,那麼發郵件、發短信、寫數據庫、通知關聯繫統這些代碼會和用戶註冊代碼直接耦合起來,整個代碼看起來就是完成用戶註冊邏輯後,後面必然跟着發郵件、發短信這些代碼。若是要新增一個功能,好比將監控用戶註冊狀況,將註冊信息發送到業務監控系統,就必需要修改前面的代碼,至少增長一行代碼,發送註冊信息到監控系統,咱們知道,任何代碼的修改均可能會引發bug。

 

而使用分佈式消息隊列實現生產者和消費者解耦合之後,用戶註冊之後,不須要調用任何後續處理代碼,只須要將註冊消息發送到分佈式消息隊列就能夠了。若是要增長新功能,只須要寫個新功能的消費者程序,在分佈式消息隊列中,訂閱用戶註冊主題就能夠了,不須要修改原來任何一行代碼。

 

這種解耦的特色對於團隊的工做分工也頗有幫助!從消息生產者的視角看,它只須要構建消息,將消息放入消息隊列中,開發就完成了。而從消費者的開發視角看,它只須要從消息隊列中獲取消息,而後進行邏輯處理。它們彼此之間不進行任何耦合。消息的生產者不關心放入消息隊列中下一步會發生什麼,而消費者也不須要知道消息從哪裏來。這兩部分程序的開發者也能夠不關心彼此的工做進展,他們開發的代碼也不須要集成在一塊兒,只要約定好消息格式,就能夠各自開發了。

 

經常使用的消息隊列產品              

 

目前業界經常使用的消息隊列產品,有這麼幾種:RabbitMQ 、ActiveMQ、RocketMQ 、Kafka

 

  • RabbitMQ 的主要特色是性能好,社區活躍,可是RabbitMQ用Erlang開發,咱們的應用不多用Erlang,因此不便於二次開發和維護。

     

  • ActiveMQ 影響比較普遍,能夠跨平臺,使用Java開發,對Java比較友好。

     

  • RocketMQ 是阿里推出的一個開源產品,也是使用Java開發,性能比較好,可靠性也比較高。

     

  • Kafka 是LinkedIn出品的,專門針對分佈式場景進行了優化,所以分佈式的伸縮性會比較好。

 

目前看來,Kafka由於最初設計時就是針對互聯網的分佈式、高可用應用場景而設計,而且在大數據領域獲得普遍支持,資料文檔更加完善,所以在互聯網企業獲得更多的應用。

 

這裏跟你們分享一個進行技術產品選型的小技巧,供你在進行技術決策的時候參考。當在幾個類似的技術產品中進行選型決策,若是拿不定主意,感受都差很少的時候,一個辦法就是利用搜索引擎搜索一下這些產品的名字,搜索結果最多的產品,表明了這個產品是最熱門,文檔資料最多的、遇到問題有更大機率能夠經過搜索引擎找到答案的,最有發展前景、不會半途而廢沒人維護的。

 

利用這個技巧,咱們看一下消息隊列MQ的產品選型,Kafka在百度中的搜索結果數量是其餘三個MQ產品的搜索結果數量之和,那麼若是你拿不定主意,選擇Kafka至少不會是一個糟糕的選擇。

 


 

 

以上內容摘取自拉勾

《阿里前輩的架構經》  第03講(分佈式消息隊列) 點擊查看更多

主講人:李智慧,前阿里巴巴技術專家

 添加拉勾職場導師微信 lagouandy  ,可領取技術相關100+電子書

相關文章
相關標籤/搜索