RocketMQ 在 linux 的部署(单机 & 集群)

传统单机部署

1. 下载:https://archive.apache.org/dist/rocketmq/
2. unzip rocketmq-all-4.5.0-bin-release.zip
3. cd rocketmq-all-4.5.0-bin-release
4. 启动 NameServer:bin/mqnamesrv  #The Name Server boot success. serializeType=JSON 表示成功
5. 启动 Broker:bin/mqbroker -n 127.0.0.1:9876 # -n 指当前 Broker 指向的 NameServer 的地址
# 启动异常说明
1. 异常信息:Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000005c0000000, 8589934592, 0) failed; error='Cannot allocate memory' (errno=12)
2. 异常原因:内存不足,MQ 默认配置是生产环境的,初始 JVM 的内存大小为 4G
3. 解决方案:调整默认内存的大小
3.1 设置 NameServer 的内存大小
vim bin/runserver.sh
JAVA_OPT="${JAVA_OPT} -server -Xms128m -Xmx128m -Xmn128m -XX:MetaspaceSize=128m - XX:MaxMetaspaceSize=128m"
3.2 设置 Broker 的内存大小
vim bin/runbroker.sh
JAVA_OPT="${JAVA_OPT} -server -Xms128m -Xmx128m -Xmn128m"
1. 测试发送消息
export NAMESRV_ADDR=127.0.0.1:9876
cd bin
sh tools.sh org.apache.rocketmq.example.quickstart.Producer
2. 测试结果
SendResult [sendStatus=SEND_OK, msgId=AC110001473C7D4991AD336AEA5703E0, offsetMsgId=AC11000100002A9F00000000000E8580, messageQueue=MessageQueue [topic=TopicTest, brokerName=itcast, queueId=3], queueOffset=1323]
SendResult [sendStatus=SEND_OK, msgId=AC110001473C7D4991AD336AEA5903E1, offsetMsgId=AC11000100002A9F00000000000E8634, messageQueue=MessageQueue [topic=TopicTest, brokerName=itcast, queueId=0], queueOffset=1323]
3. 测试发送消息
sh tools.sh org.apache.rocketmq.example.quickstart.Consumer
4. 测试结果
ConsumeMessageThread_7 Receive New Messages: [MessageExt [queueId=2, storeSize=180, queueOffset=1322, sysFlag=0, bornTimestamp=1544456244818, bornHost=/172.16.55.185:33702, storeTimestamp=1544456244819, storeHost=/172.17.0.1:10911, msgId=AC11000100002A9F00000000000E84CC, commitLogOffset=951500, bodyCRC=684865321, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=1325, CONSUME_START_TIME=1544456445397, UNIQ_KEY=AC110001473C7D4991AD336AEA5203DF, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 32, 57, 57, 49], transactionId='null'}]]
ConsumeMessageThread_6 Receive New Messages: [MessageExt [queueId=2, storeSize=180, queueOffset=1323, sysFlag=0, bornTimestamp=1544456244833, bornHost=/172.16.55.185:33702, storeTimestamp=1544456244835, storeHost=/172.17.0.1:10911, msgId=AC11000100002A9F00000000000E879C, commitLogOffset=952220, bodyCRC=801108784, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=1325, CONSUME_START_TIME=1544456445397, UNIQ_KEY=AC110001473C7D4991AD336AEA6103E3, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 32, 57, 57, 53], transactionId='null'}]]

Docker 单机部署

1. 拉取镜像
docker pull foxiswho/rocketmq:server-4.5.0
docker pull foxiswho/rocketmq:broker-4.5.0
2. 创建 NameServer 容器
docker create -p 9876:9876 --name mqserver 
-e "JAVA_OPT_EXT=-server -Xms128m -Xmx256m -Xmn128m" 
-e "JAVA_OPTS=-Duser.home=/opt" 
-v /usr/local/rocketmq/mqserver/logs:/opt/logs 
-v /usr/local/rocketmq/mqserver/store:/opt/store 
foxiswho/rocketmq:server-4.5.0
3. 创建 Broker 容器
docker create -p 10911:10911 -p 10909:10909 --net host --name mqbroker 
-e "JAVA_OPTS=-Duser.home=/opt" 
-e "JAVA_OPT_EXT=-server -Xms128m -Xmx256m -Xmn128m" 
-v /usr/local/rocketmq/mqbroker/conf/broker.conf:/etc/rocketmq/broker.conf 
-v /usr/local/rocketmq/mqbroker/logs:/opt/logs 
-v /usr/local/rocketmq/mqbroker/store:/opt/store 
foxiswho/rocketmq:broker-4.5.0
4. 启动容器
docker start mqserver mqbroker
5. 停止容器
docker stop mqbroker mqserver
6. 删除容器
docker rm rmqbroker rmqserver

Docker 部署管理工具

  • RocketMQ 提供了 UI 管理工具,名为 [rocketmq-console](https://github.com/apache/rocketmq-exter nals/tree/master/rocketmq-console),该工具支持docker以及非docker安装,这里选择使用docker安装
1. 拉取镜像
docker pull styletang/rocketmq-console-ng:1.0.0
2. 创建并启动容器
docker create --name mqconsole -p 7000:8080
-e "JAVA_OPTS=-Drocketmq.namesrv.addr=150.158.186.40:9871;150.158.186.40:9871 -Dcom.rocketmq.sendMessageWithVIPChannel=false" 
styletang/rocketmq-console-ng:1.0.0
docker pull apacherocketmq/rocketmq-console:2.0.0
docker create --name mqconsole -p 7000:8080 
-e "JAVA_OPTS=-Drocketmq.namesrv.addr=150.158.186.40:9876;150.158.186.40:9877 -Dcom.rocketmq.sendMessageWithVIPChannel=false" 
apacherocketmq/rocketmq-console:2.0.0

集群部署介绍

单 Master 模式
  • 风险大,一旦 Broker 重启或者宕机,直接导致整个服务不可用,不建议线上环境使用。
多 Master 模式
  • 一个集群中没有 Slave,全是 Master
  • 单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息实时性会收到影响
多 Master 多 Slave 模式,异步复制
  • 每个 Master 配置一个 Slave,HA 采用异步复制方式,主备有短暂消息延迟,毫秒级
  • 优点:即使磁盘损坏,消息丢失的非常少,且消息实时性不会受影响,因为 Master 宕机后,消费者仍然可以从 Slave 消费,此过程对应用透明,不需要人工干预。性能同多 Master 模式几乎一样
  • 缺点:Master 宕机,磁盘损坏情况下会丢失少量消息
多 Master 多 Slave 模式,同步双写
  • 每个 Master 配置一个 Slave,HA 采用同步双写,主备都写成功,向应用返回成功
  • 优点:数据与服务都无单点,Master 宕机情况下,消息无延迟,服务可用性与数据可用性都非常高
  • 缺点:性能比异步复制模式略低,大约低 10% 左右

Docker 部署 2m2s 集群

创建2个 NameServer Master
1. 创建 NameServer01
docker create -p 9871:9876 --name mqserver01 
-e "JAVA_OPT_EXT=-server -Xms128m -Xmx128m -Xmn128m" 
-e "JAVA_OPTS=-Duser.home=/opt" 
-v /usr/local/rocketmq/cluster/mqserver01/logs:/opt/logs 
-v /usr/local/rocketmq/cluster/mqserver01/store:/opt/store 
foxiswho/rocketmq:server-4.7.0

2. 创建 NameServer02
docker create -p 9872:9876 --name mqserver02 
-e "JAVA_OPT_EXT=-server -Xms128m -Xmx128m -Xmn128m" -e "JAVA_OPTS=-Duser.home=/opt" 
-v /usr/local/rocketmq/cluster/mqserver02/logs:/opt/logs 
-v /usr/local/rocketmq/cluster/mqserver02/store:/opt/store foxiswho/rocketmq:server-4.7.0
创建第一组 Broker(Master - Slave)
1. 创建 broker01-master
docker create --net host --name mqbroker01 
-e "JAVA_OPTS=-Duser.home=/opt" -e "JAVA_OPT_EXT=-server -Xms128m -Xmx128m -Xmn128m" 
-v /usr/local/rocketmq/cluster/mqbroker01/conf/broker.conf:/etc/rocketmq/broker.conf 
-v /usr/local/rocketmq/cluster/mqbroker01/logs:/opt/logs 
-v /usr/local/rocketmq/cluster/mqbroker01/store:/opt/store 
foxiswho/rocketmq:broker-4.7.0

2. 配置 broker01-master
namesrvAddr=150.158.186.40:9871;150.158.186.40:9872
brokerClusterName=zy-cluster
brokerName=broker01
brokerId=0
deleteWhen=04
fileReservedTime=48
brokerRole=SYNC_MASTER
flushDiskType=ASYNC_FLUSH
brokerIP1=150.158.186.40
listenPort=10811
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
#defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
#autoCreateSubscriptionGroup=true
messageDelayLevel=1s 1m 5m 15m 30m 1h 2h 3h 4h 5h 6h 7h 8h 12h 18h 1d 36h 3d
3. 创建 broker01-slave
docker create --net host --name mqbroker02 
-e "JAVA_OPTS=-Duser.home=/opt" -e "JAVA_OPT_EXT=-server -Xms128m -Xmx128m -Xmn128m" 
-v /usr/local/rocketmq/cluster/mqbroker02/conf/broker.conf:/etc/rocketmq/broker.conf 
-v /usr/local/rocketmq/cluster/mqbroker02/logs:/opt/logs 
-v /usr/local/rocketmq/cluster/mqbroker02/store:/opt/store
foxiswho/rocketmq:broker-4.5.0

4. 配置 broker01-slave
namesrvAddr=150.158.186.40:9871;150.158.186.40:9872
brokerClusterName=zy-cluster
brokerName=broker01
brokerId=1
deleteWhen=04
fileReservedTime=48
brokerRole=SLAVE
flushDiskType=ASYNC_FLUSH
brokerIP1=150.158.186.40
listenPort=10812
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
#defaultTopicQueueNums=4
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
#autoCreateSubscriptionGroup=true
messageDelayLevel=1s 1m 5m 15m 30m 1h 2h 3h 4h 5h 6h 7h 8h 12h 18h 1d 36h 3d
创建第二组 Broker(Master - Slave)
1. 创建 broker02-master
docker create --net host --name mqbroker03 
-e "JAVA_OPTS=-Duser.home=/opt" -e "JAVA_OPT_EXT=-server -Xms128m -Xmx128m -Xmn128m" 
-v /usr/local/rocketmq/cluster/mqbroker03/conf/broker.conf:/etc/rocketmq/broker.conf 
-v /usr/local/rocketmq/cluster/mqbroker03/logs:/opt/logs 
-v /usr/local/rocketmq/cluster/mqbroker03/store:/opt/store foxiswho/rocketmq:broker-4.5.0

2. 配置 broker02-master
namesrvAddr=127.0.0.1:9871;127.0.0.1:9872
brokerClusterName=zy-cluster
brokerName=broker02
brokerId=0
deleteWhen=04 
fileReservedTime=48 
brokerRole=SYNC_MASTER 
flushDiskType=ASYNC_FLUSH 
brokerIP1=127.0.0.1
brokerIp2=127.0.0.1
listenPort=10813
3. 创建 broker02-slave
docker create --net host --name mqbroker04 
-e "JAVA_OPTS=-Duser.home=/opt" -e "JAVA_OPT_EXT=-server -Xms128m -Xmx128m -Xmn128m" 
-v /usr/local/rocketmq/cluster/mqbroker04/conf/broker.conf:/etc/rocketmq/broker.conf 
-v /usr/local/rocketmq/cluster/mqbroker04/logs:/opt/logs 
-v /usr/local/rocketmq/cluster/mqbroker04/store:/opt/store foxiswho/rocketmq:broker-4.5.0

4. 配置 broker02-slave
namesrvAddr=127.0.0.1:9871;127.0.0.1:9872 
brokerClusterName=zy-cluster 
brokerName=broker02
brokerId=1
deleteWhen=04
fileReservedTime=48
brokerRole=SLAVE 
flushDiskType=ASYNC_FLUSH 
brokerIP1=127.0.0.1
brokerIp2=127.0.0.1 
listenPort=10814
启动
docker start mqserver01 mqserver02
docker start mqbroker01 mqbroker02 mqbroker03 mqbroker04

DLedger 模式

  • 基于 raft 协议的 commitlog 存储库,是 RocketMQ 实现新的高可用多副本架构的关键
聊一聊 Master-Slave 模式的缺陷
  • 针对于 RocketMQ 4.5 版本之前,RocketMQ 只有 Master-Slave 模式,一组 Broker 中有一个 Master,零到多个 Slave,Slave 通过同步复制或异步复制的方式去同步 Master 数据。这种模式提供了一定的高可用性。
  • Master-Slave 模式的缺陷:如果主节点挂了,需要人为手动进行重启或者切换,无法自动将一个从节点转换为主节点
缺陷解决的两种方式:也就是说要解决自动故障转移的问题,本质上也就是如何完成自动选主的问题
  • 引入三方协调服务:如 zookeeper 或 etcd 等,重量级部署,增加了额外的维护成本
  • 基于 Raft 协议完成自动选主:不需要引入外部组件,自动选主逻辑集成到各个节点的进程中,节点直接通过通信就可以完成选主
什么是 Raft 协议
  • Raft 协议可以使得一个集群的服务器组成复制状态机
什么是 复制状态机
  • 一组服务器,每个服务器都是一个状态机,服务器的运行状态只能通过一行行的命令来改变,每一个状态机存储一个包含一系列指令的日志,要求每个状态机必须严格按照顺序执行,如果所有状态机都能按照相同的日志执行指令,那么它们最终将达到相同的状态。
  • 因此,在复制状态机模型下,只要保证操作日志的一致性,就可以保证分布式系统状态的一致性
如何保证操作日志的一致性(Raft 一致性算法)
  • 为了让一致性协议变得简单,Raft 协议主要采用了两种策略
    • 复杂问题分解:raft 协议中,一致性问题被分解为:leader election、log replication、safety 三个简单问题
    • 减少状态空间中的状态数目
Raft 一致性算法
  • 在 Raft 体系中,有一个强 leader,负责全权接收客户端的请求命令,并将该请求命令作为日志条目复制给其他服务器,在确认安全的时候,将日志命令提交执行。当 leader 故障时,会通过选举产生一个新的 leader
  • 复杂问题分解
    • leader election:leader 选举,当已有 leader 故障时必须选出一个新的 leader
    • log replication:leader 接收来自客户端的命令,记录为日志,并复制给集群中的其他服务器,并强制其他节点的日志与 leader 保持一致
    • safety:通过一系列措施保证系统的安全性,如确保所有状态机按照相同顺序执行相同命令的措施
  • 关于 leader 选举:集群刚启动的时候,所有节点都是 follower,之后在 time out 信号的驱使下,follower 会转换成 candidate 去拉取选票,获得大多数选票后就会成为 leader,其他候选人发现了新的 leader 已经诞生,就会自动转变为 follower。如果另一个 time out 信号发出是,还没有选举出 leader,将会重新开始新一次的选举。time out 信号是促使角色转换的关键因素,类似于操作系统中的中断信号。
  • 关于日志处理
    • 日志复制:一旦 leader 选举成功,就可以对客户端提供服务,客户端提交每一条命令都会被顺序记录到 leader 的日志中,每一条指令都包含一个编号和顺序索引,然后向其他节点并行发送指令用以发送指令(如果命令丢失会不断重发),当各个节点均复制成功后,leader 就会提交命令,执行该命令并将执行结果响应给客户端,raft 保证已经提交的命令最终也会被其他节点执行,leader 会保存当前已经提交的最高日志编号,顺序性确保了相同日志索引处的命令是相同的。leader 向各节点发送指令的时候,会包含 leader 上一条刚处理过的指令,接收节点如果发现上一条命令不匹配,就会拒绝执行。
    • 日志复制中的异常情况:
      • leader 宕机,日志部分指令未被 follower 复制完毕,这时候会进行新的选举来产生 leader,在 raft 中 leader 会强制要求 follower 复制自己的日志来解决日志不一致的问题,也就必定会造成部分指令失败的情况。
    • 日志压缩
      • 系统的全部状态会写入一个 snapshot 保存起来,然后丢弃截止到 snapshot 时间点之前的所有日志,虽然每一个 server 都保存有自己的snapshot,但是当 follower 严重落后于 leader 时,leader 需要把自己的 snapshot 发送给 follower 加快同步,此时用到了一个新的 RPC:InstallSnapshot RPC。follower 收到 snapshot 时,需要决定如何处理自己的日志,如果收到的 snapshot 包含有更新的信息,它将丢弃自己已有的日志,按 snapshot 更新自己的状态,如果 snapshot 包含的信息更少,那么它会丢弃 snapshot 中的内容,但是自己之后的内容会保存下来。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值