Nginx是一個 輕量級/高性能的反向代理Web服務器,他實現非常高效的反向代理、負載平衡,他可以處理2-3萬并發連接數,官方監測能支持5萬并發,現在中國使用nginx網站用戶有很多,例如:新浪、網易、 騰訊等。
1)跨平臺、配置簡單、方向代理、高并發連接:處理2-3萬并發連接數,官方監測能支持5萬并發,內存消耗小:開啟10個nginx才占150M內存 ,nginx處理靜態文件好,耗費內存少。
2)Nginx內置的健康檢查功能:如果有一個服務器宕機,會做一個健康檢查,再發送的請求就不會發送到宕機的服務器了。重新將請求提交到其他的節點上。
優點:1)占內存小,可實現高并發連接,處理響應快
2)可實現http服務器、虛擬主機、方向代理、負載均衡
3)Nginx配置簡單,可以不暴露正式的服務器IP地址
缺點:1)動態處理差:nginx處理靜態文件好,耗費內存少,但是處理動態頁面則很雞肋,所以前端一般用nginx作為反向代理抗住壓力。
1)http服務器。Nginx是一個http服務可以獨立提供http服務。可以做網頁靜態服務器。
2)虛擬主機。可以實現在一臺服務器虛擬出多個網站,例如個人網站使用的虛擬機。
3)反向代理,負載均衡。當網站的訪問量達到一定程度后,單臺服務器不能滿足用戶的請求時,需要用多臺服務器集群可以使用nginx做反向代理。并且多臺服務器可以平均分擔負載,不會應為某臺服務器負載高宕機而某臺服務器閑置的情況。
4)nginx中也可以配置安全管理、比如可以使用Nginx搭建API接口網關,對每個接口服務進行攔截。
因為它的事件處理機制:異步非阻塞事件處理機制運用了epoll模型,提供了一個隊列,排隊解決。
server{ # 第一個Server區塊開始,表示一個獨立的虛擬主機站點
? ? listen ? 80; ? ? ??? ??? ? ? ? ? ?# 提供服務的端口,默認80
? ? server_name ?localhost; ? # 提供服務的域名主機名
? ? location / { ? ? ? ? ? ??? ? ? ? ? ?# 第一個location區塊開始
? ? ? ? root ? html; ? ? ? ?? ??? ? # 站點的根目錄,相當于Nginx的安裝目錄
? ? ? ? index ?index.html index.htm; ? ??? ?# 默認的首頁文件,多個用空格分開
? ? } ? ? ? ? ??? ??? ??? ??? ? # 第一個location區塊結果
} ? ? ?
首先,Nginx 在啟動時,會解析配置文件,得到需要監聽的端口與 IP 地址,然后在 Nginx 的 Master 進程里面先初始化好這個監控的Socket(創建 S ocket,設置 addr、reuse 等選項,綁定到指定的 ip 地址端口,再 listen 監聽)。正向代理就是一個人發送一個請求直接就到達了目標的服務器。
反方代理就是請求統一被Nginx接收,nginx反向代理服務器接收到之后,按照一定的規則分發給了后端的業務處理服務器進行處理了。
反向代理服務器可以隱藏源服務器的存在和特征。它充當互聯網云和web服務器之間的中間層。這對于安全方面來說是很好的,特別是當您使用web托管服務時。
①輪詢:Nginx根據請求發送來的順序,依次把請求循環的發給列表中的服務器;
②按權重:提前為每個服務器指定一個權重,Nginx在分配請求時會優先把請求分配給權重較高的服務器(一般選擇給性能較好的服務器賦予較大的權重);
③hash綁定:可以為每個ip地址使用hash綁定,這樣每個訪客訪問的服務器固定,可以解決seeion存儲問題;常見的用法是對用戶的IP或者ID進行這個策略,然后「負載均衡器」就能保證同一個IP來源或者同一個用戶永遠會被送到同一個后端服務器上了,一般用于處理緩存、會話等功能的時候特別好用;
④響應策略:按后端服務器響應時間,響應快的優先分配;也就是說,不管后端服務器負載高不高,也不管配置如何,只要覺得這個服務器在當前時刻能最快的響應用戶的請求,那么就優先把請求轉發給它,這樣的話,對于用戶而言,體驗也最好。那「負載均衡器」是怎么知道哪一臺后端服務在當前時刻響應能力最佳呢?這就需要「負載均衡器」不停的去統計每一臺后端服務器對請求的處理速度了,比如一分鐘統計一次,生成一個后端服務器處理速度的排行榜。然后「負載均衡器」根據這個排行榜去轉發服務;
⑤負載度策略:負載度策略是指當「負載均衡器」往后端轉發流量的時候,會先去評估后端每臺服務器的負載壓力情況,對于壓力比較大的后端服務器轉發的請求就少一些,對于壓力比較小的后端服務器可以多轉發一些請求給它。這種方式就充分的結合了后端服務器的運行狀態,來動態的分配流量了,比輪詢的方式更為科學一些。但是這種方式也帶來了一些弊端,因為需要動態的評估后端服務器的負載壓力,那這個「負載均衡器」除了轉發請求以外,還要做很多額外的工作,比如采集 連接數、請求數、CPU負載指標、IO負載指標等等,通過對這些指標進行計算和對比,判斷出哪一臺后端服務器的負載壓力較大。因此這種方式帶來了效果優勢的同時,也增加了「負載均衡器」的實現難度和維護成本。
1)Nginx是當下最熱的Web容器,網站優化的重要點在于靜態化網站,網站靜態化的關鍵點則是是動靜分離,動靜分離是讓動態網站里的動態網頁根據一定規則把不變的資源和經常變的資源區分開來,動靜資源做好了拆分以后,我們則根據靜態資源的特點將其做緩存操作。
2)讓靜態的資源只走靜態資源服務器,動態的走動態的服務器
3)Nginx的靜態處理能力很強,但是動態處理能力不足,因此,在企業中常用動靜分離技術。
4)對于靜態資源比如圖片,js,css等文件,我們則在反向代理服務器nginx中進行緩存。這樣瀏覽器在請求一個靜態資源時,代理服務器nginx就可以直接處理,無需將請求轉發給后端服務器tomcat。 若用戶請求的動態文件,比如servlet,jsp則轉發給Tomcat服務器處理,從而實現動靜分離。這也是反向代理服務器的一個重要的作用。
CDN ,即內容分發網絡。其目的是,通過在現有的 Internet中 增加一層新的網絡架構,將網站的內容發布到最接近用戶的網絡邊緣,使用戶可就近取得所需的內容,提高用戶訪問網站的速度。一般來說,因為現在 CDN 服務比較大眾,所以基本所有公司都會使用 CDN 服務。
在有多個cpu的情況下,可以設置多個worker,worker進程的數量可以設置到和cpu的核心數一樣多,如果在單個cpu上起多個worker進程,那么操作系統會在多個worker之間進行調度,這種情況會降低系統性能,如果只有一個cpu,那么只啟動一個worker進程就可以了。
漏桶算法思路很簡單,我們把水比作是請求,漏桶比作是系統處理能力極限,水先進入到漏桶里,漏桶里的水按一定速率流出,當流出的速率小于流入的速率時,由于漏桶容量有限,后續進入的水直接溢出(拒絕請求),以此實現限流。
令牌桶算法的原理也比較簡單,我們可以理解成醫院的掛號看病,只有拿到號以后才可以進行診病。
系統會維護一個令牌(token)桶,以一個恒定的速度往桶里放入令牌(token),這時如果有請求進來想要被處理,則需要先從桶里獲取一個令牌(token),當桶里沒有令牌(token)可取時,則該請求將被拒絕服務。令牌桶算法通過控制桶的容量、發放令牌的速率,來達到對請求的限制。
ActiveMQ是一種開源的,實現了JMS1.1規范的,面向消息(MOM)的中間件,為應用程序提供高效的、可擴展的、穩定的和安全的企業級消息通信。
ActiveMQ的作用就是系統之間進行通信。 當然可以使用其他方式進行系統間通信, 如果使用 ActiveMQ的話可以對系統之間的調用進行解耦, 實現系統間的異步通信。 原理就是生產者生產消息, 把消息發送給ActiveMQ。 ActiveMQ接收到消息, 然后查看有多少個消費者, 然后把消息轉發給消費者, 此過程中生產者無需參與。 消費者接收到消息后做相應的處理和生產者沒有任何關系。
消息通信的基本方式有兩種:
1.同步方式
兩個通信應用服務之間必須要進行同步,兩個服務之間必須都是正常運行的。發送程序和接收程序都必須一直處于運行狀態,并且隨時做好相互通信的準備。發送程序首先向接收程序發起一個請求,稱之為發送消息,發送程序緊接著就會堵塞當前自身的進程,不與其他應用進行任何的通信以及交互,等待接收程序的響應,待發送消息得到接收程序的返回消息之后會繼續向下運行,進行下一步的業務處理。
2.異步方式
兩個通信應用之間可以不用同時在線等待,任何一方只需各自處理自己的業務,比如發送方發送消息以后不用登錄接收方的響應,可以接著處理其他的任務。也就是說發送方和接收方都是相互獨立存在的,發送方只管方,接收方只能接收,無須去等待對方的響應。Java 中 JMS 就是典型的異步消息處理機制,JMS 消息有兩種類型:點對點、發布/訂閱。
1)publish(發布)-subscribe(訂閱)(發布-訂閱方式)
發布/訂閱方式用于多接收客戶端的方式.作為發布訂閱的方式,可能存在多個接收客戶端,并且接收端客戶端與發送客戶端存在時間上的依賴。一個接收端只能接收他創建以后發送客戶端發送的信息。作為subscriber ,在接收消息時有兩種方法,destination的receive方法,和實現message listener 接口的onMessage方法。
2)p2p(point-to-point)(點對點)
p2p的過程則理解起來比較簡單。它好比是兩個人打電話,這兩個人是獨享這一條通信鏈路的。一方發送消息,另外一方接收,就這么簡單。在實際應用中因為有多個用戶對使用p2p的鏈路,相互通信的雙方是通過一個類似于隊列的方式來進行交流。和前面pub-sub的區別在于一個topic有一個發送者和多個接收者,而在p2p里一個queue只有一個發送者和一個接收者。
工作模式:Topic是“訂閱-發布”模式,如果當前沒有訂閱者,消息將會被丟棄,如果有多個訂閱者,那么這些訂閱者都會受到消息;Queue是“負載均衡”模式,如果當前沒有消費者,消息不會被丟棄;如果有多個消費者,那么一條消息也只能發送給一個消費者,并且要求消費者ack信息。
有無狀態:Topic無狀態;Queue 數據默認會在mq服務器上以文件的形式存儲,比如activemq一般保存在$AMQ_HOME\data\kr-store\data下面,也可以配置成DB存儲。
傳遞完整性:Topic模式如果沒有訂閱,消息就會被丟棄。Queue消息不會被丟棄。
處理效率:由于消息會隨著訂閱者的數量進行復制,所以處理性能會隨著訂閱者的增加而明顯降低,并且還要結合不同的消息協議自身的性能差異;Queue模式由于一條消息只能被一個消費者消費,所以就算消費者再多,性能也不會有明顯降低,當然不同的消息協議的具體性能也是有差異的。
一般來說我們可以在業務段加一張表,用來存放消息是否執行成功,每次業務事物commit之后,告知服務端,已經處理過該消息,這樣即使你消息重發了,也不會導致重復處理。
為了避免意外宕機以后丟失信息,需要做到重啟后可以恢復消息隊列,消息系統一半都會采用持久化機制。ActiveMQ的消息持久化機制有JDBC,AMQ,KahaDB和LevelDB,無論使用哪種持久化方式,消息的存儲邏輯都是一致的。就是在發送者將消息發送出去后,消息中心首先將消息存儲到本地數據文件、內存數據庫或者遠程數據庫等。再試圖將消息發給接收者,成功則將消息從存儲中刪除,失敗則繼續嘗試嘗試發送。消息中心啟動以后,要先檢查指定的存儲位置是否有未成功發送的消息,如果有,則會先把存儲位置中的消息發出去。
如果一條消息不能被處理,會被退回服務器重新分配,如果只有一個消費者,該消息又會重新被獲取,重新拋異常。如果有多個消費者,往往在一個服務器上不能處理的消息,在另外的服務器上依然不能被處理。消息在重試 6 次后仍不能發送成功的,ActiveMQ 認為這條消息是“有毒”的,將會把消息丟到死信隊列里。
RabbitMQ就是 AMQP 協議的 Erlang 的實現(當然 RabbitMQ 還支持 STOMP2、 MQTT3 等協議 ) AMQP 的模型架構 和 RabbitMQ 的模型架構是一樣的,生產者將消息發送給交換器,交換器和隊列綁定 。RabbitMQ 中的交換器、交換器類型、隊列、綁定、路由鍵等都是遵循的 AMQP 協議中相應的概念。
采用AMQP高級消息隊列協議的一種消息隊列技術,最大的特點就是消費并不需要確保提供方存在,實現了服務之間的高度解耦。
1.在分布式系統下具備異步,削峰,負載均衡等一系列高級功能;
2.擁有持久化的機制,進程消息,隊列中的信息也可以保存下來。
3.實現消費者和生產者之間的解耦。
4.對于高并發場景下,利用消息隊列可以使得同步訪問變為串行訪問達到一定量的限,利于數據庫的操作。
5.可以使用消息隊列達到異步下單的效果,排隊中,后臺進行邏輯下單。
1.服務間異步通信
2.順序消費
3.定時任務
4.請求削峰
Broker:簡單來說就是消息隊列服務器實體
Exchange:消息交換機,它指定消息按什么規則,路由到哪個隊列
Queue:消息隊列載體,每個消息都會被投入到一個或多個隊列
Binding:綁定,它的作用就是把exchange和queue按照路由規則綁定起來
Routing Key: 路由關鍵字,exchange根據這個關鍵字進行消息投遞
VHost:vhost可以理解為虛擬broker ,即mini-RabbitMQ server。其內部均含有獨立的queue、exchange和binding等,但最最重要的是,其擁有獨立的權限系統,可以做到vhost范圍的用戶控制。當然,從RabbitMQ的全局角度,vhost可以作為不同權限隔離的手段(一個典型的例子就是不同的應用可以跑在不同的 vhost 中)。
Producer: 消息生產者,就是投遞消息的程序
Consumer:消息消費者,就是接受消息的程序
Channel:消息通道,在客戶端的每個連接里,可建立多個channel,每個channel代表一個會話任務由Exchange、Queue、RoutingKey三個才能決定一個從Exchange到Queue的唯一的線路。
消息的發送方有個確認模式,具體的流程如下:
1.將信道設置成confirm模式(發送方確認模式),則所有在信道上發布的消息都會被指派一個唯一的ID。
2.一旦消息被投遞到目的隊列后,或者消息被寫入磁盤后(可持久化的消息),信道會發送一個確認給生產者(包含消息唯一 ID)。
3.如果 RabbitMQ發生內部錯誤從而導致消息丟失,會發送一條nack(notacknowledged,未確認)消息。發送方確認模式是異步的,生產者應用程序在等待確認的同時,可以繼續發送消息。當確認消息到達生產者應用程序,生產者應用程序的回調方法就會被觸發來處理確認消息。
消息的接收方消息確認機制,具體的流程如下:
消費者接收每一條消息后都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確認了消息,RabbitMQ才能安全地把消息從隊列中刪除。這里并沒有用到超時機制,RabbitMQ僅通過Consumer的連接中斷來確認是否需要重新發送消息。也就是說,只要連接不中斷,RabbitMQ給了Consumer足夠長的時間來處理消息。保證數據的最終一致性;
如果消費者接收到消息,在確認之前斷開了連接或取消訂閱,RabbitMQ會認為消息沒有被分發,然后重新分發給下一個訂閱的消費者。
在消息生產時,RabbitMQ內部針對每條生產者發送的消息生成一個inner-msg-id,作為去重的依據(消息投遞失敗并重傳),避免重復的消息進入隊列;
在消息消費時,要求消息體中必須要有一個 bizId(對于同一業務全局唯一,如支付ID、訂單ID、帖子ID 等)作為去重的依據,避免同一條消息被重復消費。
消息不丟失需要堆消息進行持久化。
確保持久性消息能從服務器重啟中恢復的方式是,將它們寫入磁盤上的一個持久化日志文件,當發布一條持久性消息到持久交換器上時,Rabbit會在消息提交到日志文件后才發送響應。一旦消費者從持久隊列中消費了一條持久化消息,RabbitMQ會在持久化日志中把這條消息標記為等待垃圾收集。如果持久化消息在被消費之前RabbitMQ重啟,那么Rabbit會自動重建交換器和隊列(以及綁定),并重新發布持久化日志文件中的消息到合適的隊列。
由于TCP連接的創建和銷毀開銷較大,且并發數受系統資源限制,會造成性能瓶頸。RabbitMQ使用信道的方式來傳輸數據。信道是建立在真實的TCP連接內的虛擬連接,且每條TCP連接上的信道數量沒有限制。
若該隊列至少有一個消費者訂閱,消息將以循環(round-robin)的方式發送給消費者。每條消息只會分發給一個訂閱的消費者(前提是消費者能夠正常處理消息并進行確認)。
主要有3種:
1.fanout:如果交換器收到消息,將會廣播到所有綁定的隊列上
2.direct:如果路由鍵完全匹配,消息就被投遞到相應的隊列
3.topic:可以使來自不同源頭的消息能夠到達同一個隊列。 使用topic交換器時,可以使用通配符
1.簡單模式,用的默認交換機,1個生產者,1個消費者,一個消息只能被一個消費者消息
2.工作模,多個消費者監聽同一個隊列,如果任務數據比較多,可以多幾個消費者,可以加快消費的速度
3.訂閱發布模式,引入了交換機的類型fanout,廣播模式 ,每個消費者單獨監聽自己的對列都可以取消費自己隊列的消息。
4.routing,是direct的的交換機類型,指定路由
5.topic,是topic的交換機類型,比路由多了通配符的更加的靈活
完成RabbitMQ消息路由的核心組件是 Exchange。而消息的路由是由Exchange類型 和 Binding 來決定的。Binding 表示建立 Queue 和 Exchange 之間的綁定關系,每一個綁定關系會存在一個 BindingKey。通過這種方式相當于在 Exchange 中建立了一個路由關系表。生產者發送消息的時候,需要聲明一個 RoutingKey(路由鍵),Exchange 拿到RoutingKey 之后,根據 RoutingKey 和路由表里面的 BindingKey 進行匹配,而匹配的規則是通過 Exchange類型來決定的。在 RabbitMQ 中,默認有四種類型的 Exchange:Direct ,Fanout、Topic和Header。
Direct,叫直連,也就是完整匹配方式,需要Routing Key 和 Binding Key 完全一致,相當于點對點的發送。
Topic: 叫主題,這種方式是通過設置通配符來動態匹配,相當于正則。就是用Routing Key 去匹配Binging Key。BingingKey支持兩個通配符。
Fanout:叫廣播,這種方式不需要設置Routing Key,而是把消息廣播給綁定到當前 Exchange 上的所有隊列上。
1)拆分多個queue(消息隊列),每個queue(消息隊列) 一個consumer(消費者),就是多一些queue(消息隊列)而已,這種方式會比較麻煩;
2)一個queue (消息隊列)但是對應一個consumer(消費者),然后這個consumer(消費者)內部用內存隊列做排隊,然后分發給底層不同的worker來處理。
首先,必然導致性能的下降,因為寫磁盤比寫RAM慢的多,message的吞吐量可能有10倍的差距。
其次,message的持久化機制用在RabbitMQ的內置cluster方案時會出現“坑爹”問題。矛盾點在于,若message設置了persistent屬性,但queue未設置durable屬性,那么當該queue的owner node出現異常后,在未重建該queue前,發往該queue 的message將被 blackholed;若 message 設置了 persistent屬性,同時queue也設置了durable屬性,那么當queue的owner node異常且無法重啟的情況下,則該queue無法在其他node上重建,只能等待其owner node重啟后,才能恢復該 queue的使用,而在這段時間內發送給該queue的message將被 blackholed 。
所以,是否要對message進行持久化,需要綜合考慮性能需要,以及可能遇到的問題。若想達到100,000 條/秒以上的消息吞吐量(單RabbitMQ服務器),則要么使用其他的方式來確保message的可靠delivery ,要么使用非常快速的存儲系統以支持全持久化(例如使用SSD)。
另外一種處理原則是:僅對關鍵消息作持久化處理(根據業務重要程度),且應該保證關鍵消息的量不會導致性能瓶頸。
RabbitMQ有三種模式:單機模式、普通集群模式、鏡像集群模式。
單機模式就是Demo級別的,一般就是你本地啟動了玩玩兒的?,沒人生產用單機模式
普通集群模式就是在多臺機器上啟動多個RabbitMQ實例,每個機器啟動一個。你創建的queue,只會放在一個RabbitMQ實例上,但是每個實例都同步queue的元數據。你消費的時候,實際上如果連接到了另外一個實例,那么那個實例會從queue所在實例上拉取數據過來。這方案主要是提高吞吐量的,就是說讓集群中多個節點來服務某個queue的讀寫操作。
鏡像集群模式才是所謂的RabbitMQ的高可用模式。這種模式下,每個RabbitMQ節點都有這個queue的一個完整鏡像,包含queue的全部數據的意思。然后每次你寫消息到queue的時候,都會自動把消息同步到多個實例的queue上。RabbitMQ有很好的管理控制臺,就是在后臺新增一個策略,這個策略是鏡像集群模式的策略,指定的時候是可以要求數據同步到所有節點的,也可以要求同步到指定數量的節點,再次創建queue的時候,應用這個策略,就會自動將數據同步到其他的節點上去了。這樣的好處在于,你任何一個機器宕機了,沒事兒,其它機器(節點)還包含了這個queue的完整數據,別的consumer都可以到其它節點上去消費數據。壞處在于,第一,這個性能開銷也太大了吧,消息需要同步到所有機器上,導致網絡帶寬壓力和消耗很重!RabbitMQ一個queue的數據都是放在一個節點里的,鏡像集群下,也是每個節點都放這個queue的完整數據。
mq是一個消息隊列,其主要目的是為了解決傳統的消息傳輸上管理困難,效率不高的問題。mq有三大優點:解耦,異步,削峰。
解耦: 如果是傳統的消息通訊方式,無論是哪一方都要去維護一份供外部通訊的這個一個接口,而且各方處理消息的能力有限,效率上明顯跟不上,并且這樣子二者之間的耦合度非常高,對于拓展管理方面極不友好,而是要了mq就不一樣,發送方只需要將消息發送給mq就可以了,別的不用考慮,接口什么的由mq去維護,接收方也只需要去mq里消費消息就可以了,就需要其他開銷,一切由mq中間件來做,達到了解耦操作.
異步: 使用mq,還可以達到異步效果,極大地提升了消息傳輸的效率.發送方在發送消息后不需要關心消費方是否能消費完成,還可以繼續發送其他消息.
削峰:如果是傳統的消息通訊,一下子有大量的消息發送給接收方,這樣對于接收方的處理壓力是很大的,而我們剛好可以利用mq達到一個緩沖操作,一旦流量超出了接收方處理范圍,不用擔心,只需要慢慢消費即可,像經典的雙十一,就很容易會使用到mq這么一個優點.
mq缺點:因為增加了中間件,系統復雜度肯定大大提高,增加了很多維護的成本,比如我們要保證消息不丟失(一致性)和消息冪等性問題,還要保證mq的高可用等。
1)異步處理 - 相比于傳統的串行、并行方式,提高了系統吞吐量。
2)應用解耦 - 系統間通過消息通信,不用關心其他系統的處理。
3)流量削鋒 - 可以通過消息隊列長度控制請求量;可以緩解短時間內的高并發請求。
4)日志處理 - 解決大量日志傳輸。
5)消息通訊 - 消息隊列一般都內置了高效的通信機制,因此也可以用在純的消息通訊。比如實現點對點消息隊列,或者聊天室等。
1)系統可用性降低:本來系統運行好好的,現在你非要加入個消息隊列進去,那消息隊列掛了,你的系統不是呵呵了。因此,系統可用性會降低;
2)系統復雜度提高:加入了消息隊列,要多考慮很多方面的問題,比如:一致性問題、如何保證消息不被重復消費、如何保證消息可靠性傳輸等。因此,需要考慮的東西更多,復雜性增大。
3)一致性問題:A系統處理完了直接返回成功了,人都以為你這個請求就成功了;但是問題是,要是BCD三個系統那里,BD兩個系統寫庫成功了,結果C系統寫庫失敗了,咋整?你這數據就不一致了。
所以消息隊列實際是一種非常復雜的架構,你引入它有很多好處,但是也得針對它帶來的壞處做各種額外的技術方案和架構來規避掉。
解耦:以電商應用為例,應用中有訂單系統、庫存系統、物流系統、支付系統。用戶創建訂單后,如果耦合調用庫存系統、物流系統、支付系統,任何一個子系統出了故障,都會造成下單操作異常。使用mq后,訂單系統和其余系統完成解耦,不必擔心其他系統出現故障,當轉變成基于消息隊列的方式后,系統間調用的問題會減少很多,比如物流系統因為發生故障,需要幾分鐘來修復。在這幾分鐘的時間里,物流系統要處理的內存被緩存在消息隊列中,用戶的下單操作可以正常完成。當物流系統恢復后,繼續處理訂單信息即可,中單用戶感受不到物流系統的故障,提升系統的可用性。
異步:有些服務間的調用并不是同步的,而是異步執行,例如,A調用B,B需要花費很長時間執行,此時A需要知道B什么時間可以執行完成,在未使用MQ時,一般會有兩種方法實現,1.A不斷地輪詢查看B是否完成。2、就是A提供一個調用接口,當B執行完成之后,調用A的回調接口,以此實現。
當然MQ的出現很好的解決這個問題,A調用B后,只需要監聽B處理完成消息,當B處理完后,會發送一條消息給MQ,MQ會將此消息轉發給A服務。這樣就省去了A的輪詢或者B對A的回調。A也能夠即使得到異步處理消息。
削峰:比如說,如果訂單系統最多能處理一萬次訂單,這個處理能力應付正常時段的下單時是沒有問題的,正常時段我們下單一秒后就能返回結果。但是在高峰期,如果有兩萬次下單操作系統是處理不了的,只能限制訂單超過一萬后不允許用戶下單。使用MQ做緩沖,我們可以取消這個限制,把一秒內下的訂單分散成一段時間來處理,這時有些用戶可能在下單十幾秒后才能收到下單成功,雖然這樣會影響一定的體驗,但是要比不能下單好的多。
AMQP協議 AMQP即Advanced Message Queuing Protocol,一個提供統一消息服務的應用層標準高級消息隊列協議,是應用層協議的一個開放標準,為面向消息的中間件設計。基于此協議的客戶端與消息中間件可傳遞消息,并不受客戶端/中間件不同產品,不同開發語言等條件的限制。
優點:可靠、通用
MQTT協議 MQTT(Message Queuing Telemetry Transport,消息隊列遙測傳輸)是IBM開發的一個即時通訊協議,有可能成為物聯網的重要組成部分。該協議支持所有平臺,幾乎可以把所有聯網物品和外部連接起來,被用來當做傳感器和致動器(比如通過Twitter讓房屋聯網)的通信協議。
優點:格式簡潔、占用帶寬小、移動端通信、PUSH、嵌入式系統
STOMP協議 STOMP(Streaming Text Orientated Message Protocol)是流文本定向消息協議,是一種為MOM(Message Oriented Middleware,面向消息的中間件)設計的簡單文本協議。STOMP提供一個可互操作的連接格式,允許客戶端與任意STOMP消息代理(Broker)進行交互。
優點:命令模式(非topic/queue模式)
XMPP協議 XMPP(可擴展消息處理現場協議,Extensible Messaging and Presence Protocol)是基于可擴展標記語言(XML)的協議,多用于即時消息(IM)以及在線現場探測。適用于服務器之間的準即時操作。核心是基于XML流傳輸,這個協議可能最終允許因特網用戶向因特網上的其他任何人發送即時消息,即使其操作系統和瀏覽器不同。
優點:通用公開、兼容性強、可擴展、安全性高,但XML編碼格式占用帶寬大
其他基于TCP/IP自定義的協議:有些特殊框架(如:redis、kafka、zeroMq等)根據自身需要未嚴格遵循MQ規范,而是基于TCP\IP自行封裝了一套協議,通過網絡socket接口進行傳輸,實現了MQ的功能。
1)點對點通訊:點對點方式是最為傳統和常見的通訊方式,它支持一對一、一對多、多對多、多對一等多種配置方式,支持樹狀、網狀等多種拓撲結構。
2)多點廣播:MQ適用于不同類型的應用。其中重要的,也是正在發展中的是"多點廣播"應用,即能夠將消息發送到多個目標站點(Destination List)。可以使用一條MQ指令將單一消息發送到多個目標站點,并確保為每一站點可靠地提供信息。MQ不僅提供了多點廣播的功能,而且還擁有智能消息分發功能,在將一條消息發送到同一系統上的多個用戶時,MQ將消息的一個復制版本和該系統上接收者的名單發送到目標MQ系統。目標MQ系統在本地復制這些消息,并將它們發送到名單上的隊列,從而盡可能減少網絡的傳輸量。
3)發布/訂閱(Publish/Subscribe)模式:發布/訂閱功能使消息的分發可以突破目的隊列地理指向的限制,使消息按照特定的主題甚至內容進行分發,用戶或應用程序可以根據主題或內容接收到所需要的消息。發布/訂閱功能使得發送者和接收者之間的耦合關系變得更為松散,發送者不必關心接收者的目的地址,而接收者也不必關心消息的發送地址,而只是根據消息的主題進行消息的收發。在MQ家族產品中,MQ Event Broker是專門用于使用發布/訂閱技術進行數據通訊的產品,它支持基于隊列和直接基于TCP/IP兩種方式的發布和訂閱。
4)集群(Cluster):為了簡化點對點通訊模式中的系統配置,MQ提供 Cluster 的解決方案。集群類似于一個 域(Domain) ,集群內部的隊列管理器之間通訊時,不需要兩兩之間建立消息通道,而是采用 Cluster 通道與其它成員通訊,從而大大簡化了系統配置。此外,集群中的隊列管理器之間能夠自動進行負載均衡,當某一隊列管理器出現故障時,其它隊列管理器可以接管它的工作,從而大大提高系統的高可靠性;
在消息生產時,MQ內部針對每條生產者發送的消息生成一個唯一id,作為去重和冪等的依據(消息投遞失敗并重傳),避免重復的消息進入隊列。
在消息消費時,要求消息體中也要有一全局唯一id作為去重和冪等的依據,避免同一條消息被重復消費。
一般這個時候,只能臨時緊急擴容了,具體操作步驟和思路如下:
1)先修復 consumer 的問題,確保其恢復消費速度,然后將現有 consumer 都停掉;
2)新建一個 topic,partition 是原來的 10 倍,臨時建立好原先 10 倍的 queue 數量;
3)然后寫一個臨時的分發數據的 consumer 程序,這個程序部署上去消費積壓的數據,消費之后不做耗時的處理,直接均勻輪詢寫入臨時建立好的 10 倍數量的queue;
4)接著臨時用 10 倍的機器來部署 consumer,每一批 consumer 消費一個臨時 queue 的數據。這種做法相當于是臨時將 queue 資源和 consumer 資源擴大10倍,以正常的 10 倍速度來消費數據;
5)等快速消費完積壓數據之后,得恢復原先部署的架構,重新用原先的 consumer 機器來消費消息。
綜上,各種對比之后,有如下建議:
一般的業務系統要引入MQ,最早大家都用ActiveMQ,但是現在確實大家用的不多了,沒經過大規模吞吐量場景的驗證,社區也不是很活躍,所以大家還是算了吧,我個人不推薦用這個了;
后來大家開始用RabbitMQ,但是確實erlang語言阻止了大量的Java工程師去深入研究和掌控它,對公司而言,幾乎處于不可控的狀態,但是確實人家是開源的,比較穩定的支持,活躍度也高;
不過現在確實越來越多的公司會去用RocketMQ,確實很不錯,畢竟是阿里出品,但社區可能有突然黃掉的風險(目前 RocketMQ已捐給Apache,但GitHub上的活躍度其實不算高)對自己公司技術實力有絕對自信的,推薦用RocketMQ,否則回去老老實實用RabbitMQ 吧,人家有活躍的開源社區,絕對不會黃。
所以中小型公司,技術實力較為一般,技術挑戰不是特別高,用RabbitMQ是不錯的選擇;大型公司,基礎架構研發實力較強,用 RocketMQ是很好的選擇。如果是大數據領域的實時計算、日志采集等場景,用Kafka是業內標準的,絕對沒問題,社區活躍度很高,絕對不會黃,何況幾乎是全世界這個領域的事實性規范。
這個首先你可以說下你們公司選用的是什么消息中間件,比如用的是RabbitMQ,然后可以初步給一些你對不同MQ中間件技術的選型分析。舉個例子:比如說ActiveMQ是老牌的消息中間件,國內很多公司過去運用的還是非常廣泛的,功能很強大。但是問題在于沒法確認ActiveMQ可以支撐互聯網公司的高并發、高負載以及高吞吐的復雜場景,在國內互聯網公司落地較少。而且使用較多的是一些傳統企業,用ActiveMQ做異步調用和系統解耦。
然后你可以說說RabbitMQ,他的好處在于可以支撐高并發、高吞吐、性能很高,同時有非常完善便捷的后臺管理界面可以使用。另外,他還支持集群化、高可用部署架構、消息高可靠支持,功能較為完善。而且經過調研,國內各大互聯網公司落地大規模RabbitMQ集群支撐自身業務的case較多,國內各種中小型互聯網公司使用RabbitMQ的實踐也比較多。除此之外,RabbitMQ的開源社區很活躍,較高頻率的迭代版本,來修復發現的bug以及進行各種優化,因此綜合考慮過后,公司采取了RabbitMQ。但是RabbitMQ也有一點缺陷,就是他自身是基于erlang語言開發的,所以導致較為難以分析里面的源碼,也較難進行深層次的源碼定制和改造,畢竟需要較為扎實的erlang語言功底才可以。
然后可以聊聊RocketMQ,是阿里開源的,經過阿里的生產環境的超高并發、高吞吐的考驗,性能卓越,同時還支持分布式事務等特殊場景。而且RocketMQ是基于Java語言開發的,適合深入閱讀源碼,有需要可以站在源碼層面解決線上生產問題,包括源碼的二次開發和改造。
另外就是Kafka。Kafka提供的消息中間件的功能明顯較少一些,相對上述幾款MQ中間件要少很多。但是Kafka的優勢在于專為超高吞吐量的實時日志采集、實時數據同步、實時數據計算等場景來設計。因此Kafka在大數據領域中配合實時計算技術(比如Spark Streaming、Storm、Flink)使用的較多。但是在傳統的MQ中間件使用場景中較少采用。