rocketmq總結(jié)以及自動化部署策略

RocketMQ總結(jié)

1 rocketmq是什么?

what_is_rocketmq.png

是一個隊列模型的消息中間件,具有高性能、高可靠、高實時、分布式特點。

  • Producer、Consumer、隊列都可以分布式。
  • Producer 向一些隊列輪流發(fā)送消息,隊列集合稱為 Topic,Consumer 如果做廣播消費,則一個 consumer

實例消費這個 Topic 對應(yīng)的所有隊列,如果做集群消費,則多個 Consumer 實例平均消費這個 topic 對應(yīng)的隊列集合。

  • 能夠保證嚴(yán)格的消息順序
  • 提供豐富的消息拉取模式
  • 高效的訂閱者水平擴展能力
  • 實時的消息訂閱機制
  • 億級消息堆積能力
  • 較少的依賴

2 rocketmq網(wǎng)絡(luò)結(jié)構(gòu)

rocketmq網(wǎng)絡(luò)架構(gòu)

RocketMQ 網(wǎng)絡(luò)部署特點

  • Name Server 是一個幾乎無狀態(tài)節(jié)點,可集群部署,節(jié)點之間無任何信息同步。

  • Broker 部署相對復(fù)雜,Broker 分為 Master 與 Slave,一個 Master 可以對應(yīng)多個 Slave,但是一個 Slave 只能對應(yīng)一個 Master,Master 與 Slave 的對應(yīng)關(guān)系通過指定相同的 BrokerName,不同的 BrokerId 來定義,BrokerId為 0 表示 Master,非 0 表示 Slave。Master 也可以部署多個。每個 Broker 與 Name Server 集群中的所有節(jié)點建立長連接,定時注冊 Topic 信息到所有 Name Server。

  • Producer 與 Name Server 集群中的其中一個節(jié)點(隨機選擇)建立長連接,定期從 Name Server 取 Topic 路由信息,并向提供 Topic 服務(wù)的 Master 建立長連接,且定時向 Master 發(fā)送心跳。Producer 完全無狀態(tài),可集群部署。

  • Consumer 與 Name Server 集群中的其中一個節(jié)點(隨機選擇)建立長連接,定期從 Name Server 取 Topic 路由信息,并向提供 Topic 服務(wù)的 Master、Slave 建立長連接,且定時向 Master、Slave 發(fā)送心跳。Consumer既可以從 Master 訂閱消息,也可以從 Slave 訂閱消息,訂閱規(guī)則由 Broker 配置決定。

3 模塊功能特性

3.1 Namesrv

  1. Namesrv用于存儲Topic、Broker關(guān)系信息,功能簡單,穩(wěn)定性高。多個Namesrv之間相互沒有通信,單臺Namesrv宕機不影響其他Namesrv與集群;即使整個Namesrv集群宕機,已經(jīng)正常工作的Producer,Consumer,Broker仍然能正常工作,但新起的Producer, Consumer,Broker就無法工作。

  2. Namesrv壓力不會太大,平時主要開銷是在維持心跳和提供Topic-Broker的關(guān)系數(shù)據(jù)。但有一點需要注意,Broker向Namesr發(fā)心跳時,會帶上當(dāng)前自己所負(fù)責(zé)的所有Topic信息,如果Topic個數(shù)太多(萬級別),會導(dǎo)致一次心跳中,就Topic的數(shù)據(jù)就幾十M,網(wǎng)絡(luò)情況差的話,網(wǎng)絡(luò)傳輸失敗,心跳失敗,導(dǎo)致Namesrv誤認(rèn)為Broker心跳失敗。

3.2 Broker

1)高并發(fā)讀寫服務(wù)

Broker的高并發(fā)讀寫主要是依靠以下兩點:

  • 消息順序?qū)?/strong>,所有Topic數(shù)據(jù)同時只會寫一個文件,一個文件滿1G,再寫新文件,真正的順序?qū)懕P,使得發(fā)消息TPS大幅提高。
  • 消息隨機讀,RocketMQ盡可能讓讀命中系統(tǒng)pagecache,因為操作系統(tǒng)訪問pagecache時,即使只訪問1K的消息,系統(tǒng)也會提前預(yù)讀出更多的數(shù)據(jù),在下次讀時就可能命中pagecache,減少IO操作。

2) 負(fù)載均衡與動態(tài)伸縮

負(fù)載均衡:Broker上存Topic信息,Topic由多個隊列組成,隊列會平均分散在多個Broker上,而Producer的發(fā)送機制保證消息盡量平均分布到所有隊列中,最終效果就是所有消息都平均落在每個Broker上。

動態(tài)伸縮能力(非順序消息):Broker的伸縮性體現(xiàn)在兩個維度:Topic, Broker。

  • Topic維度:假如一個Topic的消息量特別大,但集群水位壓力還是很低,就可以擴大該Topic的隊列數(shù),Topic的隊列數(shù)跟發(fā)送、消費速度成正比。
  • Broker維度:如果集群水位很高了,需要擴容,直接加機器部署B(yǎng)roker就可以。Broker起來后想Namesrv注冊,Producer、Consumer通過Namesrv發(fā)現(xiàn)新Broker,立即跟該Broker直連,收發(fā)消息。

3) 高可用&高可靠

高可用:集群部署時一般都為主備,備機實時從主機同步消息,如果其中一個主機宕機,備機提供消費服務(wù),但不提供寫服務(wù)。

高可靠:所有發(fā)往broker的消息,有同步刷盤和異步刷盤機制;同步刷盤時,消息寫入物理文件才會返回成功,異步刷盤時,只有機器宕機,才會產(chǎn)生消息丟失,broker掛掉可能會發(fā)生,但是機器宕機崩潰是很少發(fā)生的,除非突然斷電

4)Broker與Namesrv的心跳機制
單個Broker跟所有Namesrv保持心跳請求,心跳間隔為30秒,心跳請求中包括當(dāng)前Broker所有的Topic信息。Namesrv會反查Broer的心跳信息,如果某個Broker在2分鐘之內(nèi)都沒有心跳,則認(rèn)為該Broker下線,調(diào)整Topic跟Broker的對應(yīng)關(guān)系。但此時Namesrv不會主動通知Producer、Consumer有Broker宕機。

3.3 消費者

消費者啟動時需要指定Namesrv地址,與其中一個Namesrv建立長連接。消費者每隔30秒從nameserver獲取所有topic的最新隊列情況,這意味著某個broker如果宕機,客戶端最多要30秒才能感知。連接建立后,從namesrv中獲取當(dāng)前消費Topic所涉及的Broker,直連Broker。

Consumer跟Broker是長連接,會每隔30秒發(fā)心跳信息到Broker。Broker端每10秒檢查一次當(dāng)前存活的Consumer,若發(fā)現(xiàn)某個Consumer 2分鐘內(nèi)沒有心跳,就斷開與該Consumer的連接,并且向該消費組的其他實例發(fā)送通知,觸發(fā)該消費者集群的負(fù)載均衡。

消費者端的負(fù)載均衡
先討論消費者的消費模式,消費者有兩種模式消費:集群消費,廣播消費。

  • 廣播消費:每個消費者消費Topic下的所有隊列。
  • 集群消費:一個topic可以由同一個ID下所有消費者分擔(dān)消費。具體例子:假如TopicA有6個隊列,某個消費者ID起了2個消費者實例,那么每個消費者負(fù)責(zé)消費3個隊列。如果再增加一個消費者ID相同消費者實例,即當(dāng)前共有3個消費者同時消費6個隊列,那每個消費者負(fù)責(zé)2個隊列的消費。

消費者端的負(fù)載均衡,就是集群消費模式下,同一個ID的所有消費者實例平均消費該Topic的所有隊列。

3.4 生產(chǎn)者(Producer)

Producer啟動時,也需要指定Namesrv的地址,從Namesrv集群中選一臺建立長連接。如果該Namesrv宕機,會自動連其他Namesrv。直到有可用的Namesrv為止。

生產(chǎn)者每30秒從Namesrv獲取Topic跟Broker的映射關(guān)系,更新到本地內(nèi)存中。再跟Topic涉及的所有Broker建立長連接,每隔30秒發(fā)一次心跳。在Broker端也會每10秒掃描一次當(dāng)前注冊的Producer,如果發(fā)現(xiàn)某個Producer超過2分鐘都沒有發(fā)心跳,則斷開連接。

生產(chǎn)者端的負(fù)載均衡

生產(chǎn)者發(fā)送時,會自動輪詢當(dāng)前所有可發(fā)送的broker,一條消息發(fā)送成功,下次換另外一個broker發(fā)送,以達(dá)到消息平均落到所有的broker上。

這里需要注意一點:假如某個Broker宕機,意味生產(chǎn)者最長需要30秒才能感知到。在這期間會向宕機的Broker發(fā)送消息。當(dāng)一條消息發(fā)送到某個Broker失敗后,會往該broker自動再重發(fā)2次,假如還是發(fā)送失敗,則拋出發(fā)送失敗異常。業(yè)務(wù)捕獲異常,重新發(fā)送即可。客戶端里會自動輪詢另外一個Broker重新發(fā)送,這個對于用戶是透明的。

4 集群說明

  • 單個 Master

    這種方式風(fēng)險較大,一旦Broker重啟或者宕機時,會導(dǎo)致整個服務(wù)不可用,不建議線上環(huán)境使用。

  • 多 Master 模式(2m-noslave)

    brokerClusterName brokerName brokerRole brokerId
    DefaultCluster broker-a ASYNC_MASTER 0
    DefaultCluster broker-b ASYNC_MASTER 0
    說明:一個集群無 Slave,全是 Master,例如 2 個 Master 或者 3 個 Master優(yōu)點:配置簡單,單個Master 宕機或重啟維護對應(yīng)用無影響,在磁盤配置為RAID10 時,即使機器宕機不可恢復(fù)情況下,由與 RAID10磁盤非??煽?,消息也不會丟(異步刷盤丟失少量消息,同步刷盤一條不丟)。性能最高。
    
    缺點:單臺機器宕機期間,這臺機器上未被消費的消息在機器恢復(fù)之前不可訂閱,消息實時性會受到受到影響。
    
    啟動說明:先啟動 NameServer在機器 A,啟動第一個 Master在機器 B,啟動第二個 Master
    
    
  • 多 Master 多 Slave 模式,異步復(fù)制(2m-2s-async)

    brokerClusterName brokerName brokerRole brokerId
    DefaultCluster broker-a ASYNC_MASTER 0
    DefaultCluster broker-a SLAVE 1
    DefaultCluster broker-b ASYNC_MASTER 0
    DefaultCluster broker-b SLAVE 1
    說明:每個 Master 配置一個 Slave,有多對Master-Slave,HA。采用異步復(fù)制方式,主備有短暫消息延遲,毫秒級。
    
    優(yōu)點:即使磁盤損壞,消息丟失的非常少,且消息實時性不會受影響,因為Master 宕機后,消費者仍然可以從 Slave消費,此過程對應(yīng)用透明。不需要人工干預(yù)。性能同多 Master 模式幾乎一樣。
    
    缺點:Master 宕機,磁盤損壞情況,會丟失少量消息。
    
    啟動說明:
      先啟動 NameServer
      在機器 A,啟動第一個 Master
      在機器 B,啟動第二個 Master
      在機器 C,啟動第一個 Slave
      在機器 D,啟動第二個 Slave
    
  • **多 Master 多 Slave 模式,同步雙寫(2m-2s-sync) **

brokerClusterName brokerName brokerRole brokerId
DefaultCluster broker-a SYNC_MASTER 0
DefaultCluster broker-a SLAVE 1
DefaultCluster broker-b SYNC_MASTER 0
DefaultCluster broker-b SLAVE 1
說明:每個 Master 配置一個 Slave,有多對Master-Slave,HA。采用同步雙寫方式,主備都寫成功,向應(yīng)用返回成功。

優(yōu)點:數(shù)據(jù)與服務(wù)都無單點,Master宕機情況下,消息無延遲,服務(wù)可用性與數(shù)據(jù)可用性都非常高

缺點:性能比異步復(fù)制模式略低,大約低10%左右,發(fā)送單個消息的RT會略高。目前主宕機后,備機不能自動切換為主機,后續(xù)會支持自動切換功能。

啟動說明:
  先啟動 NameServer
  在機器 A,啟動第一個 Master
  在機器 B,啟動第二個 Master
  在機器 C,啟動第一個 Slave
  在機器 D,啟動第二個 Slave

以上 Broker 與 Slave 配對是通過指定相同的brokerName 參數(shù)來配對,Master
的 BrokerId 必須是 0,Slave 的BrokerId 必須是大與 0 的數(shù)。另外一個 Master
下面可以掛載多個 Slave,同一 Master 下的多個 Slave通過指定不同的 BrokerId
來區(qū)分。

5 集群部署案例-2m-2s-sync

5.1 環(huán)境說明

1) 軟件及其機器

軟件及版本 下載地址
系統(tǒng) centos7 https://www.centos.org/download/
軟件 rocketmq-all-4.2.0 https://www.apache.org/dyn/closer.cgi?path=rocketmq/4.2.0/rocketmq-all-4.2.0-source-release.zip
依賴 jdk1.8+ oracle官網(wǎng)
ip hostname 部署服務(wù) role/brokerid
192.168.59.2 mqnamesrv-*.env.rocketmq.com NameServer No
192.168.59.3 mqnamesrv-*.env.rocketmq.com NameServer No
192.168.59.4 mqbroker-*.env.rocketmq.com Broker SYNC_MASTER/0
192.168.59.5 mqbroker-*.env.rocketmq.com Broker SLAVE/1
192.168.59.6 mqbroker-*.env.rocketmq.com Broker SYNC_MASTER/0
192.168.59.7 mqbroker-*.env.rocketmq.com Broker SLAVE/1 表 5.2

綁定hosts或dns:

#測試環(huán)境hosts
#Name Server 提供給外部訪問
192.168.59.2 nameserver1.rocketmq.test.com
192.168.59.3 nameserver2.rocketmq.test.com
#Broker Server 綁定網(wǎng)卡,方便擴容
192.168.59.4 broker01.rocketmq.test.com
192.168.59.5 broker02.rocketmq.test.com
192.168.59.6 broker03.rocketmq.test.com
192.168.59.7 broker04.rocketmq.test.com

主機命名說明:

主機名命名規(guī)范:項目名-隨機數(shù).環(huán)境.組件.公司/機房

例如:表5.2中第一行,項目名:mqnamesrv,部署環(huán)境:dev,ip:192.168.59.2,組件是rocketmq,命名主機名為:

mqnamesrv-192168059002.dev.rocketmq.com

該命名好處:通過主機名可以判斷當(dāng)前機器部署的服務(wù)以及部署環(huán)境、機房情況,方便在報警系統(tǒng)里或者cmdb中很快判斷到該主機的的影響。

2) 多環(huán)境說明

在實際應(yīng)用中都會涉及多環(huán)境的問題,比如有線下環(huán)境(dev)和生產(chǎn)環(huán)境(prod),不同環(huán)境的應(yīng)用最好保持配置一致,減少各個每個環(huán)境的配置工作量。

Rocketmq各環(huán)境統(tǒng)一連接地址

NAMESRV_ADDR="nameserver1.rocketmq.test.com:9876;nameserver2.rocketmq.test.com:9876"

根據(jù)Rocketmq集群說明,其實最終只需暴露nameserver的地址給應(yīng)用即可,因此,各個環(huán)境綁定各個環(huán)境對應(yīng)的hosts/dns即可使用統(tǒng)一連接的地址。

3) 打包部署

  • 編譯

    官方提供的是源碼包,需要編譯成二進(jìn)制包:

      > unzip rocketmq-all-4.2.0-source-release.zip
      > cd rocketmq-all-4.2.0/
      > mvn -Prelease-all -DskipTests clean install -U
      > cd distribution/target/apache-rocketmq
    
  • 打包

    二進(jìn)制包雖然可以直接運行,批量安裝和批量管理以及不利于統(tǒng)一管理,這里我直接打成rpm包,規(guī)范目錄(安裝目錄、日志目錄、數(shù)據(jù)目錄),指定rocketmq用戶運行,設(shè)置服務(wù)自動啟動等;

    因為nameserver和broker基本上是一個包,只是啟動命令不一樣,因此,打包也是打成一個包了,根據(jù)啟動命令和當(dāng)前主機名判斷是何服務(wù)。

    #使用fpm打rocketmq,然后上傳到y(tǒng)um倉庫
    fpm -s dir -t rpm -n apache-rocketmq --epoch 1 -a 'x86_64' -v 4.2.0 --iteration 1.el7 -C rocketmq/root -d 'jdk >= 1.8.0' -d 'git' --license 'Apache License, Version 2.0' --description "Apache RocketMQ is a distributed messaging and streaming platform with low latency, high performance and reliability, trillion-level capacity and flexible scalability." --no-rpm-sign --url 'http://rocketmq.apache.org/' --before-install rocketmq/install_before.sh --after-install rocketmq/install_after.sh  --before-remove rocketmq/remove_before.sh
    
  • 部署

    打包以后,部署非常簡單,直接yum安裝

    #安裝rocketmq
    > yum install apache-rocketmq
    #啟動/停止/重啟 NameServer 服務(wù)
    > systemctl start/stop/restart rocketmq-mqnamesrv
    #啟動/停止/重啟 Broker 服務(wù)
    > systemctl start/stop/restart rocketmq-mqbroker
    
  • 配置文件

    NameServer沒有配置文件,直接可以啟動

    Broker配置文件:配置基本上一致,需要更改下表的一些內(nèi)容

    brokerClusterName brokerName brokerRole brokerId
    iotcls broker01 SYNC_MASTER 0
    iotcls broker01 SLAVE 1
    iotcls broker02 SYNC_MASTER 0
    iotcls broker02 SLAVE 1
    #broker.conf.j2
    brokerClusterName=iotcls
    brokerIP1={{broker_name}}-{{broker_id}}.rocketmq.test.com
    brokerIP2={{broker_name}}-{{broker_id}}.rocketmq.test.com
    brokerName={{broker_name}}
    brokerId={{broker_id}}
    deleteWhen=04
    fileReservedTime=48
    brokerRole={{broker_role}}
    flushDiskType=SYNC_FLUSH
    namesrvAddr=nameserver1.rocketmq.test.com:9876;nameserver2.rocketmq.test.com:9876
    

    需要注意的是:

    多網(wǎng)卡環(huán)境:需要配置brokerIP1(broker ip)和brokerIP2(ha ip),brokerIP1注冊到NameServer,brokerIP2 這個ip是master和slave同步數(shù)據(jù)的ip,如果不配置,默認(rèn)會選擇第一個網(wǎng)卡。

    BrokerName,master和slave組成一個broker group,通過broker name來區(qū)別是否是一個broker group。

  • ansible role 一鍵部署

    ansible-playbook -i environments/dev/hosts rocketmq.yml
    

    ansible role配置文件說明:

    rocketmq
    ├── README.md
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── tasks
    │   ├── install.yml
    │   ├── main.yml
    │   ├── mqbroker.yml
    │   └── mqnamesrv.yml
    ├── templates
    │   ├── broker.conf.j2
    │   ├── rocketmq-mqbroker.service
    │   └── rocketmq-mqnamesrv.service
    ├── tests
    │   ├── README.md
    │   ├── etc_hosts
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml
    
    #rocetmq.yml
    - name: run rocketmq role for all hosts
      hosts: rocketmq
      roles:
        - { role: commons, tags: ["hosts"] }
    
    - name: run mqnamesrv
      hosts: mqnamesrv
      roles:
        - { role: "rocketmq", rocket_type: "mqnamesrv"}
    
    - name: run mqbroker
      hosts: mqbroker
      roles:
        - { role: "rocketmq", rocket_type: "mqbroker"}
    
    #hosts
    [rocketmq:children]
    mqnamesrv
    mqbroker
    
    [mqnamesrv]
    192.168.59.2
    192.168.59.3
    
    [mqbroker]
    192.168.59.3 broker_name="broker03" broker_id=0 broker_role=SYNC_MASTER
    192.168.59.4 broker_name="broker01" broker_id=0 broker_role=SYNC_MASTER
    192.168.59.5 broker_name="broker01" broker_id=1 broker_role=SLAVE
    192.168.59.6 broker_name="broker02" broker_id=0 broker_role=SYNC_MASTER
    192.168.59.7 broker_name="broker02" broker_id=1 broker_role=SLAVE
    
    [mqbroker:vars]
    PROJECT_NAME=mqbroker
    
    [mqnamesrv:vars]
    PROJECT_NAME=mqnamesrv
    
    #broker.conf.j2
    brokerClusterName=iotcls
    brokerIP1={{broker_name}}-{{broker_id}}.rocketmq.test.com
    brokerIP2={{broker_name}}-{{broker_id}}.rocketmq.test.com
    brokerName={{broker_name}}
    brokerId={{broker_id}}
    deleteWhen=04
    fileReservedTime=48
    brokerRole={{broker_role}}
    flushDiskType=SYNC_FLUSH
    namesrvAddr=nameserver1.rocketmq.test.com:9876;nameserver2.rocketmq.test.com:9876
    
    #role-rocketmq tasks/main.yml
    #install jdk1.8
    - include: ../../commons/tasks/jdk.yml
    
    - name: install apache-rocketmq
      yum: name=apache-rocketmq state=present
      tags: install_apache-rocketmq
    
    - name: Update mqnamesrv.service
      template:
        src: rocketmq-mqnamesrv.service
        dest: "/etc/systemd/system/"
        force: true
        owner: root
        group: root
        mode: "0755"
      notify: reload systemd
      when: rocket_type == 'mqnamesrv'
    
    - include: mqbroker.yml
      when: rocket_type == 'mqbroker'
    
    - name: enable apache-rocketmq
      service:
        name: "rocketmq-{{ rocket_type }}"
        state: started
        enabled: True
    
    handlers:
      - name: reload systemd
          command: "systemctl daemon-reload"
    
      - name: restart apache-rocketmq
        service:
          name: "rocketmq-{{ rocket_type }}"
          state: restarted
    
    #role-rocketmq tasks/mqbroker.yml
    ---
    - name: Update mqbroker.service
      template:
        src: rocketmq-mqbroker.service
        dest: "/etc/systemd/system/"
        force: true
        owner: root
        group: root
        mode: "0755"
      notify: reload systemd
    
    - name: update conf for mqbroker
      template:
        src: broker.conf.j2
        dest: "/opt/apache-rocketmq/conf/broker.conf"
        force: true
        owner: root
        group: root
        mode: "0755"
      notify: restart apache-rocketmq
    

4) 集群擴容

rocketmq各個組件都支持橫向擴容:

組件 擴容
Producer 橫向擴容,添加機器
Consumer 橫向擴容,添加機器,數(shù)量<=隊列數(shù)(分區(qū))
NameServer 橫向擴容,無狀態(tài)
Broker 橫向擴容,新增topic會自動負(fù)載

5) WEB管理(rocketmq-console)

通過web可以查看集群狀態(tài),查看topic信息以及創(chuàng)建更改topic,管理producer和consumer等。

#安裝 && 啟動
mvn clean package -Dmaven.test.skip=true
java -jar target/rocketmq-console-ng-1.0.0.jar

用戶手冊:https://github.com/apache/rocketmq-externals/blob/master/rocketmq-console/doc/1_0_0/UserGuide_CN.md

rocketmq-console-gui
rocketmq-console-2
rocketmq-topic
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容