RABBITMQ集羣及HA、LBnode
1、Rabbitmq簡介python
RabbitMQ是一個開源的AMQP實現,服務器端用Erlang語言編寫,支持多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用於在分佈式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。c++
AMQP,即Advanced message Queuing Protocol,高級消息隊列協議,是應用層協議的一個開放標準,爲面向消息的中間件設計。消息中間件主要用於組件之間的解耦,消息的發送者無需知道消息使用者的存在,反之亦然。web
AMQP的主要特徵是面向消息、隊列、路由(包括點對點和發佈/訂閱)、可靠性、安全。正則表達式
rabbitmq是使用erlang開發的,集羣很是方便,且天生就支持併發分佈式,但自身並不支持負載均衡. 常規的博客介紹都是說rabbitmq有幾種部署模式,其中最經常使用的也就兩種:json
1,單一模式: 就是不作ha...vim
2,鏡像模式模式: active/active模式的ha,當master掛掉了,按照策略選擇某個slave(其實就是最早加入集羣的那個slave)來擔當master的角色。緩存
1. Rabbitmq系統架構安全
RabbitMQ Server: 也叫broker server,是一種傳輸服務,負責維護一條從Producer到consumer的路線,保證數據可以按照指定的方式進行傳輸。服務器
Producer,數據的發送方。
Consumer,數據的接收方。
Exchanges 接收消息,轉發消息到綁定的隊列。主要使用3種類型:direct, topic, fanout。
Queue RabbitMQ內部存儲消息的對象。相同屬性的queue能夠重複定義,但只有第一次定義的有效。
Bindings 綁定Exchanges和Queue之間的路由。
Connection: 就是一個TCP的鏈接。Producer和consumer都是經過TCP鏈接到RabbitMQ Server的。
Channel:虛擬鏈接。它創建在上述的TCP鏈接中。數據流動都是在Channel中進行的。也就是說,通常狀況是程序起始創建TCP鏈接,第二步就是創建這個Channel。
2、 Rabbitmq安裝
1. 安裝 erlang 虛擬機
###安裝 erlang 虛擬機,Rabbitmq 基於 erlang 語言開發,因此須要安裝 erlang 虛擬機。
wget http://www.erlang.org/download/otp_src_R15B01. tar .gz
tar -xvf otp_src_R15B01.tar .gz
cdotp_src_R15B01
yum install make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel unixODBC unixODBC-devel
./configure --prefix=/usr/local/erlang --enable-hipe --enable-threads --enable-smp-support --enable-kernel-poll
make &make install
2. 安裝 rabbitmq
wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.5.6/rabbitmq-server-generic-unix-3.5.6. tar .gz
tar -xvf rabbitmq-server-generic-unix-3.2.1. tar .gz
mv rabbitmq_server-3.2.1 /usr/local/rabbitmq
cd /usr/local/rabbitmq/
rm LICENSE* -rf
# sbin/rabbitmqctl #<--提示沒找到 erlang 虛擬機
sbin/rabbitmqctl: line 29: exec: erl: not found
##創建軟鏈接,解決 erlang 虛擬機路徑問題
ln -s /usr/local/erlang/bin/erl /usr/local/bin/
mkdir /data/rabbitmq/data /data/rabbitmq/log -p #<--創建存放數據日誌目錄
# vim /usr/local/rabbitmq/etc/rabbitmq/rabbitmq-env .conf
RABBITMQ_NODE_IP_ADDRESS=10.168.185.96
RABBITMQ_MNESIA_BASE=/data/rabbitmq/data
RABBITMQ_LOG_BASE=/data/rabbitmq/log
# vim /usr/local/rabbitmq/etc/rabbitmq/rabbitmq #<--設置日誌級別
[
{rabbit, [{log_levels, [{connection, error}]}]}
].
啓動 rabbitmq
/usr/local/rabbitmq/sbin/rabbitmq-server –detached& 啓後默認端口是: rabbitmq 的 默認端口是 5672.
中止程序:
/usr/local/rabbitmq/sbin/rabbitmqctl stop #若單機有多個實例,則在 rabbitmqctl 後加–n 指定名稱
3. RABBITMQ頁面(web)管理
啓用 rabbitmq web 管理插件:
/usr/local/rabbitmq/sbin/rabbitmq-plugins enable rabbitmq_management
關閉 rabbitmq 管理插件:
/usr/local/rabbitmq/sbin/rabbitmq-plugins disable rabbitmq_management
列出全部插件:
/usr/local/rabbitmq/sbin/rabbitmq-plugins list
4. Rabbitmq建立用戶
若是是集羣的話,只要在一臺主機設置便可,其它會自動同步。
#rabbitmqctl add_user admin 123456 –admin爲新建的用戶,123456爲密碼
#rabbitmqctl set_user_tags admin administrator –將用戶設置爲管理員角色
#rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
–在 / 虛擬主機裏設置iom用戶配置權限,寫權限,讀權限。.*是正則表達式裏用法。rabbitmq的權限是根據不一樣的虛擬主機(virtual hosts)配置的,同用戶在不一樣的虛擬主機(virtual hosts)裏可能不同。
5. Rabbitmq安全特性
(1)publish消息確認機制
若是採用標準的 AMQP 協議,則惟一可以保證消息不會丟失的方式是利用事務機制 — 令 channel 處於 transactional 模式、向其 publish 消息、執行 commit 動做。在這種方式下,事務機制會帶來大量的多餘開銷,並會致使吞吐量降低 250% 。爲了補救事務帶來的問題,引入了 confirmation 機制(即 Publisher Confirm)。
confirm 機制是在channel上使用 confirm.select方法,處於 transactional 模式的 channel 不能再被設置成 confirm 模式,反之亦然。
在 channel 被設置成 confirm 模式以後,全部被 publish 的後續消息都將被 confirm(即 ack) 或者被 nack 一次。可是沒有對消息被 confirm 的快慢作任何保證,而且同一條消息不會既被 confirm 又被 nack 。
RabbitMQ 將在下面的狀況中對消息進行 confirm :
RabbitMQ發現當前消息沒法被路由到指定的 queues 中;
非持久屬性的消息到達了其所應該到達的全部 queue 中(和鏡像 queue 中);
持久消息到達了其所應該到達的全部 queue 中(和鏡像 queue 中),並被持久化到了磁盤(被 fsync);
持久消息從其所在的全部 queue 中被 consume 了(若是必要則會被 acknowledge)。
(2)consumer消息確認機制
爲了保證數據不被丟失,RabbitMQ支持消息確認機制,即acknowledgments。
若是沒啓動消息確認機制,RabbitMQ在consumer收到消息後就會把消息刪除。
啓用消息確認後,consumer在處理數據後應經過回調函數顯示發送ack, RabbitMQ收到ack後纔會刪掉數據。若是consumer一段時間內不回饋,RabbitMQ會將該消息從新分配給另一個綁定在該隊列上的consumer。另外一種狀況是consumer斷開鏈接,可是獲取到的消息沒有回饋,則RabbitMQ一樣從新分配。
注意:若是consumer 沒調用basic.qos 方法設置prefetch_count=1,那即便該consumer有未ack的messages,RabbitMQ仍會繼續發messages給它。
(3)消息持久化
消息確認機制確保了consumer退出時消息不會丟失,但若是是RabbitMQ自己因故障退出,消息仍是會丟失。爲了保證在RabbitMQ出現意外狀況時數據仍沒有丟失,須要將queue和message都要持久化。
queue持久化:channel.queue_declare(queue=’hello’, durable=True)
message持久化:channel.basic_publish(exchange=」,
routing_key=」task_queue」,
body=message,
properties=pika.BasicProperties(
delivery_mode = 2,) #消息持久化
)
即便有消息持久化,數據也有可能丟失,由於rabbitmq是先將數據緩存起來,到必定條件才保存到硬盤上,這期間rabbitmq出現意外數據有可能丟失。
網上有測試代表:持久化會對RabbitMQ的性能形成比較大的影響,可能會降低10倍不止。
3、Rabbitmq集羣
1. RABBITMQ集羣基本概念
一個RABBITMQ集 羣中能夠共享user,virtualhosts,queues(開啓Highly Available Queues),exchanges等。但message只會在建立的節點上傳輸。當message進入A節點的queue中後,consumer從B節點拉取時,RabbitMQ會臨時在A、B間進行消息傳輸,把A中的消息實體取出並通過B發送給consumer。因此consumer應儘可能鏈接每個節點,從中取消息。
RABBITMQ的集羣節點包括內存節點、磁盤節點。內存節點的元數據僅放在內存中,性能比磁盤節點會有所提高。不過,若是在投遞message時,打開了message的持久化,那麼內存節點的性能只能體如今資源管理上,好比增長或刪除隊列(queue),虛擬主機(vrtual hosts),交換機(exchange)等,發送和接受message速度同磁盤節點同樣。一個集羣至少要有一個磁盤節點。
2. RABBITMQ搭建集羣
(1) 部署網絡環境:
有三臺機器(mq-cluster1,2,3) rabbitmq的執行用戶爲rabbitmq,所屬組rabbitmq。直接將如下內容其加到/etc/hosts文件中
其中mq-cluster1爲master,其他的爲slave
我是以mq-cluster1爲master的,因此須要將其內容覆蓋到mq-cluster2和mq-cluster3中
殺掉rabbitmq2和rabbitmq3的rabbitmq進程:
#ps –ef|grep rab|awk ‘{print $2}’|xargs kill -9。–用service rabbitmq-servier stop停止會有遺留進程。
scp 同步完成後,啓動mq_cluster2和mq_cluster3的rabbitmq服務
(3) 設置ha模式
rabbitmqctl set_policy [-p <vhostpath>] [--priority <priority>] [--apply-to <apply-to>] <name> <pattern> <definition>
name 策略名稱
pattern 正則表達式,用來匹配資源,符合的就會應用設置的策略
definition 是json格式設置的策略。
apply-to 表示策略應用到什麼類型的地方,通常有queues,exchange和all,默認是all
priority 是個整數優先級
其中ha-mode有三種模式:
all: 同步至全部的.
exactly: 同步最多N個機器. 當現有集羣機器數小於N時,同步全部,大於等於N時則不進行同步. N須要額外經過ha-params來指定.
nodes: 只同步至符合指定名稱的nodes. N須要額外經過ha-params來指定.# 這裏設置的是同步所有的queue, 能夠按需本身選擇指定的queue
rabbitmqctl set_policy ha-all '.*' '{"ha-mode":"all"}'
(4) cluster2,3加入集羣
在mq-cluster2和mq-cluster3中分別執行:
rabbitmqctl stop_app
rabbitmqctl join_cluster rabbit@mq-cluster1
rabbitmqctl start_app
加入以後, 能夠經過rabbitmqctl cluster_status來查看cluster狀態.
ps:默認加入是一disc模式加入,能夠執行rabbitmqctl change_cluster_node_type <ram|disc>進行模式的修改
(5) 更改節點屬性
#rabbitmqctl stop_app –中止rabbitmq服務
#rabbitmqctl change_cluster_node_type disc/ram –更改節點爲磁盤或內存節點
#rabbitmqctl start_app –開啓rabbitmq服務
在rabbitmq 2.中使用:
#rabbitmqctl stop_app
#rabbitmqctl force_cluster rabbit@mq-cluster1 #不加本身的node_name,是ram模式
#rabbitmqctl force_cluster rabbit@mq-cluster1 rabbit@mq-cluster2 #加本身的node_name 是disk模式
3. RABBITMQ退出集羣
假設要把rabbitmq2退出集羣
在rabbitmq2上執行
#rabbitmqctl stop_app
#rabbitmqctl reset
#rabbitmqctl start_app
在集羣主節點上執行
# rabbitmqctl forget_cluster_node rabbit@mq-cluster2
4. RABBITMQ集羣重啓
集羣重啓時,最後一個掛掉的節點應該第一個重啓,若是因特殊緣由(好比同時斷電),而不知道哪一個節點最後一個掛掉。可用如下方法重啓:
先在一個節點上執行
#rabbitmqctl force_boot
#service rabbitmq-server –detached&
在其餘節點上執行
#service rabbitmq-server –detached&
查看cluster狀態是否正常(要在全部節點上查詢)。
#rabbitmqctl cluster_status
若是有節點沒加入集羣,能夠先退出集羣,而後再從新加入集羣。
上述方法不適合內存節點重啓,內存節點重啓的時候是會去磁盤節點同步數據,若是磁盤節點沒起來,內存節點一直失敗。
5. 注意事項
§ cookie在全部節點上必須徹底同樣,同步時必定要注意。
§ erlang是經過主機名來鏈接服務,必須保證各個主機名之間能夠ping通。能夠經過編輯/etc/hosts來手工添加主機名和IP對應關係。若是主機名ping不通,rabbitmq服務啓動會失敗。
§ 若是queue是非持久化queue,則若是建立queue的那個節點失敗,發送方和接收方能夠建立一樣的queue繼續運做。但若是是持久化queue,則只能等建立queue的那個節點恢復後才能繼續服務。
§ 在集羣元數據有變更的時候須要有disk node在線,可是在節點加入或退出的時候全部的disk node必須所有在線。若是沒有正確退出disk node,集羣會認爲這個節點當掉了,在這個節點恢復以前不要加入其它節點。
4、Rabbitmq HA
1. 鏡像隊列概念
鏡像隊列能夠同步queue和message,當主queue掛掉,從queue中會有一個變爲主queue來接替工做。
鏡像隊列是基於普通的集羣模式的,因此你仍是得先配置普通集羣,而後才能設置鏡像隊列。
鏡像隊列設置後,會分一個主節點和多個從節點,若是主節點宕機,從節點會有一個選爲主節點,原先的主節點起來後會變爲從節點。
queue和message雖然會存在全部鏡像隊列中,但客戶端讀取時不論物理面鏈接的主節點仍是從節點,都是從主節點讀取數據,而後主節點再將queue和message的狀態同步給從節點,所以多個客戶端鏈接不一樣的鏡像隊列不會產生同一message被屢次接受的狀況。
2. 配置鏡像隊列
沿用3.2的環境,如今咱們把名爲「hello」的隊列設置爲同步給全部節點
#rabbitmqctl set_policy ha-all ‘hello’ ‘{「ha-mode」:」all」}’
ha-all 是同步模式,指同步給全部節點,還有另外兩種模式ha-exactly表示在指定個數的節點上進行鏡像,節點的個數由ha-params指定,ha-nodes表示在指定的節點上進行鏡像,節點名稱經過ha-params指定;
hello 是同步的隊列名,能夠用正則表達式匹配;
{「ha-mode」:」all」} 表示同步給全部,同步模式的不一樣,此參數也不一樣。
執行上面命令後,能夠在web管理界面查看queue 頁面,裏面hello隊列的node節點後會出現+2標籤,表示有2個從節點,而主節點則是當前顯示的node(xf7021是測試用的名字,按4-2應該爲rabbitmq(1-3))。
測試的python代碼,依次發送消息到三個rabbitmq-server中,
能夠隨機的操做去關閉任意一個mq-cluster上的rabbitmq-server服務, 再經過rabbitmqctl list_queues來查看消息的數量. 能夠看到,儘管master掛了,消息依然可以發送成功,且當掛掉的機器(master或者slave)從新起起來以後,消息會立刻同步過去.
4. 搭建haproxy
安裝和初始配置haproxy此處從略.
在配置好的/etc/haproxy/haproxy.cfg尾端加上如下內容
接着啓動haproxy
haproxy -f /etc/haproxy/haproxy.cfg -D
將以前的測試代碼中的
mq_servers = ['10.22.129.57', '10.22.129.58', '10.22.129.59']
改爲
mq_servers = ['10.22.129.53', '10.22.129.53', '10.22.129.53']
執行測試代碼,發現三個消息均發送成功,而後即便手動關閉其中一臺mq,消息依然發送成功,經過rabbitctl list_queues也依然能夠看到消息是成功收到3條的.
至此,能夠看到rabbitmq-server成功的解除了single-point狀態。