深入理解訊息中介軟體技術之RabbitMQ服務

民工哥技術之路發表於2018-07-25

什麼叫訊息佇列?

訊息(Message)是指在應用間傳送的資料。訊息可以非常簡單,比如只包含文字字串,也可以更復雜,可能包含嵌入物件。 訊息佇列(Message Queue)是一種應用間的通訊方式,訊息傳送後可以立即返回,由訊息系統來確保訊息的可靠傳遞。訊息釋出者只管把訊息釋出到 MQ 中而不用管誰來取,訊息使用者只管從 MQ 中取訊息而不管是誰釋出的。這樣釋出者和使用者都不用知道對方的存在。

為何用訊息佇列?

訊息佇列是一種應用間的非同步協作機制,那什麼時候需要使用 MQ 呢? 像使用者下單之後、生成訂單、結算,定時給系統註冊使用者推送活動訊息,一些常見的流程類的業務都會用到訊息佇列服務。

深入理解訊息中介軟體技術之RabbitMQ服務

一、RabbitMQ簡介

RabbitMQ是一個訊息的代理器,用於接收和傳送訊息,你可以這樣想,他就是一個郵局,當您把需要寄送的郵件投遞到郵筒之時,你可以確定的是郵遞員先生肯定會把郵件傳送到需要接收郵件的人的手裡,不會送錯的。在這個比喻中,RabbitMQ就是一個郵箱,也可以理解為郵局和郵遞員,他們負責把訊息傳送出去和用於接收資訊。 RabbitMQ和郵局這兩者之間的主要區別是它不會處理紙質郵件,取而代之的是接收、儲存和傳送二進位制資料塊,也就是我們通常所說的訊息。

二 、RabbitMQ基本概念

下圖是RabbitMQ服務的內部結構

深入理解訊息中介軟體技術之RabbitMQ服務

  • 1)Message 訊息,它由訊息頭和訊息體兩部分組成。訊息體是不透明的,但訊息頭是由一些屬性組成的,其中包括:routing-key(路由鍵)、priority(優先權)、delivery-mode(持久儲存)。
  • 2)Publisher 生產者,也是訊息的生產者,它是向交換器釋出訊息的應用程式
  • 3)Exchange 交換器,用來接收生產者傳遞過來的訊息,然後將這些訊息路由至伺服器中的佇列
  • 4)Binding 繫結,用於訊息佇列與交換器之間的溝通。也是訊息路由的規則,相當於一個路由表。
  • 5)Queue 訊息佇列,用來儲存訊息直到傳送給消費者。一個訊息可以進入一個或多個佇列,除消費者取走訊息,否則它一直在訊息佇列裡。
  • 6)Connection 網路連線,如:一個TCP連線
  • 7)Channel 通道,多路複用連線中一個獨立的雙向資料傳輸通道。無論是釋出訊息、訂閱佇列、接收訊息都是通過通道來完成。複用通道是為了降低系統資源的消耗。
  • 8)Consumer 消費者,也就是接收生產者發來的訊息的客戶端應用。
  • 9)Virtual Host 虛擬主機,交換器、訊息佇列相關的物件。一個VHOST其實可以看成一個rabbitmp伺服器,它擁有自己的佇列、交換器、繫結與許可權機制等。Rabbitmq預設vhost是/。

三、RabbitMQ 特點

RabbitMQ 是一個由 Erlang 語言開發的 AMQP 的開源實現。AMQP :Advanced Message Queue,高階訊息佇列協議。它是應用層協議的一個開放標準,為面向訊息的中介軟體設計,基於此協議的客戶端與訊息中介軟體可傳遞訊息,並不受產品、開發語言等條件的限制。

RabbitMQ 最初起源於金融系統,用於在分散式系統中儲存轉發訊息,在易用性、擴充套件性、高可用性等方面表現不俗。具體特點包括:

  • 1)可靠性(Reliability) RabbitMQ 使用一些機制來保證可靠性,如持久化、傳輸確認、釋出確認。

  • 2)靈活的路由(Flexible Routing) 在訊息進入佇列之前,通過 Exchange 來路由訊息的。對於典型的路由功能,RabbitMQ 已經提供了一些內建的 Exchange 來實現。針對更復雜的路由功能,可以將多個 Exchange 繫結在一起,也通過外掛機制實現自己的 Exchange 。

  • 3)訊息叢集(Clustering) 多個 RabbitMQ 伺服器可以組成一個叢集,形成一個邏輯 Broker 。

  • 4)高可用(Highly Available Queues) 佇列可以在叢集中的機器上進行映象,使得在部分節點出問題的情況下佇列仍然可用。

  • 5)多種協議(Multi-protocol) RabbitMQ 支援多種訊息佇列協議,比如 STOMP、MQTT 等等。

  • 6)多語言客戶端(Many Clients) RabbitMQ 幾乎支援所有常用語言,比如 Java、.NET、Ruby 等等。

  • 7)管理介面(Management UI) RabbitMQ 提供了一個易用的使用者介面,使得使用者可以監控和管理訊息 Broker 的許多方面。

  • 8)跟蹤機制(Tracing) 如果訊息異常,RabbitMQ 提供了訊息跟蹤機制,使用者可以找出發生了什麼。

  • 9)外掛機制(Plugin System) RabbitMQ 提供了許多外掛,來從多方面進行擴充套件,也可以編寫自己的外掛。

參考文章 http://www.rabbitmq.com/

四、Rabbitmq的工作過程

  • 1)客戶端連線到訊息佇列伺服器,開啟一個channel
  • 2)客戶端宣告一個exchange、queue,並配置相關屬性
  • 3)客戶端使用routing key,在exchange與queue之間建立好繫結關係
  • 4)客戶端傳遞訊息到交換器
  • 5)交換器接收到訊息後,根據預定的KEY與繫結關係,對訊息進行路由至訊息佇列
    深入理解訊息中介軟體技術之RabbitMQ服務

五、Rabbitmq服務安裝佈署

1)首先需要安裝Erlang環境

https://bintray.com/rabbitmq/rpm/erlang
[root@master ~]# rpm -ivh erlang-20.3.8-1.el7.centos.x86_64.rpm
警告:erlang-20.3.8-1.el7.centos.x86_64.rpm: 頭V4 RSA/SHA1 Signature, 金鑰 ID 6026dfca: NOKEY
準備中...                         ################################# [100%]
正在升級/安裝...
   1:erlang-20.3.8-1.el7.centos   ################################# [100%]
[root@master ~]# erl
Erlang/OTP 20 [erts-9.3.3] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V9.3.3  (abort with ^G)
1> 
複製程式碼

2)下載安裝Rabbitmq

https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.6/rabbitmq-server-3.7.6-1.el7.noarch.rpm
[root@master ~]# ll rabbitmq-server-3.7.6-1.el7.noarch.rpm
-rw-r--r-- 1 root root 9511623 6月  27 14:00 rabbitmq-server-3.7.6-1.el7.noarch.rpm
[root@master ~]# rpm --import https://dl.bintray.com/rabbitmq/Keys/rabbitmq-release-signing-key.asc
[root@master ~]# yum install rabbitmq-server-3.7.6-1.el7.noarch.rpm
[root@master ~]# chkconfig rabbitmq-server on
注意:正在將請求轉發到“systemctl enable rabbitmq-server.service”。
Created symlink from /etc/systemd/system/multi-user.target.wants/rabbitmq-server.service to /usr/lib/systemd/system/rabbitmq-server.service.
[root@master ~]# /sbin/service rabbitmq-server start
Redirecting to /bin/systemctl start rabbitmq-server.service
[root@master ~]# ps -ef|grep rabbitmq
rabbitmq  5609     1 23 14:22 ?        00:00:02 /usr/lib64/erlang/erts-9.3.3/bin/beam.smp -W w -A 64 -MBas ageffcbf -MHas ageffcbf -MBlmbcs 512 -MHlmbcs 512 -MMmcs 30 -P 1048576 -t 5000000 -stbt db -zdbbl 1280000 -K true -- -root /usr/lib64/erlang -progname erl -- -home /var/lib/rabbitmq -- -pa /usr/lib/rabbitmq/lib/rabbitmq_server-3.7.6/ebin -noshell -noinput -s rabbit boot -sname rabbit@master -boot start_sasl -kernel inet_default_connect_options [{nodelay,true}] -sasl errlog_type error -sasl sasl_error_logger false -rabbit lager_log_root "/var/log/rabbitmq" -rabbit lager_default_file "/var/log/rabbitmq/rabbit@master.log" -rabbit lager_upgrade_file "/var/log/rabbitmq/rabbit@master_upgrade.log" -rabbit enabled_plugins_file "/etc/rabbitmq/enabled_plugins" -rabbit plugins_dir "/usr/lib/rabbitmq/plugins:/usr/lib/rabbitmq/lib/rabbitmq_server-3.7.6/plugins" -rabbit plugins_expand_dir "/var/lib/rabbitmq/mnesia/rabbit@master-plugins-expand" -os_mon start_cpu_sup false -os_mon start_disksup false -os_mon start_memsup false -mnesia dir "/var/lib/rabbitmq/mnesia/rabbit@master" -kernel inet_dist_listen_min 25672 -kernel inet_dist_listen_max 25672
rabbitmq  5752     1  0 14:22 ?        00:00:00 /usr/lib64/erlang/erts-9.3.3/bin/epmd -daemon
rabbitmq  5921  5609  0 14:22 ?        00:00:00 erl_child_setup 1024
rabbitmq  5937  5921  0 14:22 ?        00:00:00 inet_gethost 4
rabbitmq  5938  5937  0 14:22 ?        00:00:00 inet_gethost 4
root      5951  5300  0 14:23 pts/0    00:00:00 grep --color=auto rabbitmq
[root@master ~]# netstat -lntup |grep 5672
-bash: netstat: 未找到命令
[root@master ~]# netstat -lntup |grep 5672
tcp        0      0 0.0.0.0:25672           0.0.0.0:*               LISTEN      5609/beam.smp       
tcp6       0      0 :::5672                 :::*                    LISTEN      5609/beam.smp      
複製程式碼

3)檢視狀態資訊

[root@master ~]# rabbitmqctl status
Status of node rabbit@master ...
[{pid,5609},
 {running_applications,
     [{rabbit,"RabbitMQ","3.7.6"},
      {mnesia,"MNESIA  CXC 138 12","4.15.3"},
      {rabbit_common,
          "Modules shared by rabbitmq-server and rabbitmq-erlang-client",
          "3.7.6"},
      {ranch_proxy_protocol,"Ranch Proxy Protocol Transport","1.5.0"},
      {ranch,"Socket acceptor pool for TCP protocols.","1.5.0"},
      {ssl,"Erlang/OTP SSL application","8.2.6"},
      {public_key,"Public key infrastructure","1.5.2"},
      {asn1,"The Erlang ASN1 compiler version 5.0.5","5.0.5"},
      {inets,"INETS  CXC 138 49","6.5.2"},
      {jsx,"a streaming, evented json parsing toolkit","2.8.2"},
      {os_mon,"CPO  CXC 138 46","2.4.4"},
      {xmerl,"XML parser","1.3.16"},
      {crypto,"CRYPTO","4.2.2"},
      {recon,"Diagnostic tools for production use","2.3.2"},
      {lager,"Erlang logging framework","3.5.1"},
      {goldrush,"Erlang event stream processor","0.1.9"},
      {compiler,"ERTS  CXC 138 10","7.1.5"},
      {syntax_tools,"Syntax tools","2.1.4"},
      {syslog,"An RFC 3164 and RFC 5424 compliant logging framework.","3.4.2"},
      {sasl,"SASL  CXC 138 11","3.1.2"},
      {stdlib,"ERTS  CXC 138 10","3.4.5"},
      {kernel,"ERTS  CXC 138 10","5.4.3"}]},
 {os,{unix,linux}},
 {erlang_version,
     "Erlang/OTP 20 [erts-9.3.3] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:64] [hipe] [kernel-poll:true]\n"},
 {memory,
     [{connection_readers,0},
      {connection_writers,0},
      {connection_channels,0},
      {connection_other,0},
      {queue_procs,0},
      {queue_slave_procs,0},
      {plugins,5936},
      {other_proc,20754544},
      {metrics,184432},
      {mgmt_db,0},
      {mnesia,72912},
      {other_ets,1873688},
      {binary,55376},
      {msg_index,28720},
      {code,25082003},
      {atom,1041593},
      {other_system,9173572},
      {allocated_unused,8315896},
      {reserved_unallocated,3670016},
      {strategy,rss},
      {total,[{erlang,58272776},{rss,70258688},{allocated,66588672}]}]},
 {alarms,[]},
 {listeners,[{clustering,25672,"::"},{amqp,5672,"::"}]},
 {vm_memory_calculation_strategy,rss},
 {vm_memory_high_watermark,0.4},
 {vm_memory_limit,3281294131},
 {disk_free_limit,50000000},
 {disk_free,122394349568},
 {file_descriptors,
     [{total_limit,924},{total_used,2},{sockets_limit,829},{sockets_used,0}]},
 {processes,[{limit,1048576},{used,204}]},
 {run_queue,0},
 {uptime,111},
 {kernel,{net_ticktime,60}}]
複製程式碼

六、Rabbitmq CLI介紹

自帶多個命令列工具 1)rabbitmqctl 管理與操作命令

  • 停止節點
  • 訪問節點狀態,有效配置,執行狀況檢查
  • 虛擬主機管理
  • 使用者和許可權管理
  • 政策管理
  • 列出佇列,連線,渠道,交流,消費者
  • 叢集成員管理 更多操作內容請參考:http://www.rabbitmq.com/rabbitmqctl.8.html
[root@master ~]# rabbitmqctl list_bindings    #檢視繫結資訊
Listing bindings for vhost /...
[root@master ~]# rabbitmqctl list_exchanges   #檢視交換器
Listing exchanges for vhost / ...
amq.rabbitmq.trace	topic
amq.match	headers
	direct
amq.headers	headers
amq.direct	direct
amq.rabbitmq.event	topic
amq.topic	topic
amq.fanout	fanout
[root@master ~]# rabbitmqctl list_queues   #檢視佇列
Timeout: 60.0 seconds ...
Listing queues for vhost / ...
複製程式碼

2)rabbitmq-plugins 是一個管理外掛的工具:列表,啟用和禁用它們

[root@master ~]# rabbitmq-plugins --help
Usage:
rabbitmq-plugins [-n <node>] [-l] [-q] <command> [<command options>]

General options:
    -n node
    -q quiet
    -l longnames

Default node is "rabbit@server", where `server` is the local hostname. On a host
named "server.example.com", the node name of the RabbitMQ Erlang node will
usually be rabbit@server (unless RABBITMQ_NODENAME has been set to some
non-default value at broker startup time). The output of hostname -s is usually
the correct suffix to use after the "@" sign. See rabbitmq-server(1) for
details of configuring the RabbitMQ broker.

Quiet output mode is selected with the "-q" flag. Informational messages are
suppressed when quiet mode is in effect.

If RabbitMQ broker uses long node names for erlang distribution, "longnames"
option should be specified.

Some commands accept an optional virtual host parameter for which
to display results. The default value is "/".

Commands:
    disable <plugin>|--all [--offline] [--online]
    enable <plugin>|--all [--offline] [--online]
    help <command>
    list [pattern] [--verbose] [--minimal] [--enabled] [--implicitly-enabled]
    set [<plugin>] [--offline] [--online]

<timeout> - operation timeout in seconds. Default is "infinity".
參考文章:http://www.rabbitmq.com/rabbitmq-plugins.8.html
複製程式碼

3)rabbitmqadmin 它可以執行一些與WEB介面相同的操作,rabbitmqadmin只是一個專門的HTTP客戶端。 安裝管理外掛後,http://{主機名}:15672 /cli/rabbitmqadmin 進行下載

[root@master ~]# wget https://raw.githubusercontent.com/rabbitmq/rabbitmq-management/v3.7.6/bin/rabbitmqadmin
[root@master ~]# cp rabbitmqadmin /usr/local/bin/
[root@master ~]# chmod +x /usr/local/bin/rabbitmqadmin
複製程式碼

七、RabbitMQ叢集

RabbitMQ 是用 erlang 開發的,叢集非常方便,因為 erlang 天生就是一門分散式語言,但其本身並不支援負載均衡。

RabbitMQ 的叢集節點包括:

  • 1)記憶體節點 記憶體節點就是將所有資料放在記憶體,只儲存狀態到記憶體(例外的情況:持久的queue內容將被儲存到 disk)
  • 2)磁碟節點。 磁碟節點將資料放在磁碟,儲存狀態到記憶體和磁碟,記憶體節點雖然不寫入磁碟,但是它執行比磁碟節點要好,叢集中,只需要一個磁碟節點來儲存狀態 就足夠了,如果叢集中只有記憶體節點,那麼不能停止它們,否則所有的狀態,訊息等都會丟失。
    深入理解訊息中介軟體技術之RabbitMQ服務

不過,如前文所述,如果在投遞訊息時,開啟了訊息的持久化,那即使是記憶體節點,資料還是安全的放在磁碟。一個 RabbitMQ 叢集中可以共享 user、vhost、queue、exchange 等,所有的資料和狀態都是必須在所有節點上覆制的,一個例外是那些當前只屬於建立它的節點的訊息佇列,儘管它們可見且可被所有節點讀取。 RabbitMQ 節點可以動態地加入到叢集中,一個節點它可以加入到叢集中,也可以從叢集環叢集進行一個基本的負載均衡。

Rabbit 模式大概分為以下三種:

  • 1)單一模式
  • 2)普通模式
  • 3)映象模式

深入理解訊息中介軟體技術之RabbitMQ服務
**單一模式:**最簡單的情況,非叢集模式。

**普通模式:**預設的叢集模式。 對於 Queue 來說,訊息實體只存在於其中一個節點,A、B 兩個節點僅有相同的後設資料,即佇列結構。當訊息進入 A 節點的 Queue 中後,consumer 從 B 節點拉取時,RabbitMQ 會臨時在 A、B 間進行訊息傳輸,把 A 中的訊息實體取出並經過 B 傳送給 consumer. 所以 consumer 應儘量連線每一個節點,從中取訊息。即對於同一個邏輯佇列,要在多個節點建立物理 Queue。否則無論 consumer 連 A 或 B,出口總在 A,會產生瓶頸。該模式存在一個問題就是當 A 節點故障後,B 節點無法取到 A 節點中還未消費的訊息實體。如果做了訊息持久化,那麼得等 A 節點恢復,然後才可被消費。

映象模式: 把需要的佇列做成映象佇列,存在於多個節點,屬於 RabbitMQ 的 HA 方案。 該模式解決了上述問題,其實質和普通模式不同之處在於,訊息實體會主動在映象節點間同步,而不是在 consumer 取資料時臨時拉取。該模式帶來的副作用也很明顯,除了降低系統效能外,如果映象佇列數量過多,加之大量的訊息進入,叢集內部的網路頻寬將會被這種同步通訊大大消耗掉,所,在對可靠性要求較高的場合中適用。

深入理解訊息中介軟體技術之RabbitMQ服務

相關文章