Rocketmq 集群

Rocketmq

Posted by BlueFat on Saturday, November 14, 2020

https://github.com/apache/rocketmq/tree/master/docs/cn

集群方案

https://github.com/apache/rocketmq/blob/master/docs/cn/operation.md

单Master模式 这种方式风险较大,一旦Broker重启或者宕机时,会导致整个服务不可用。不建议线上环境使用,可以用于本地测试。

多Master模式 一个集群无Slave,全是Master,例如2个Master或者3个Master,这种模式的优缺点如下:

  • 优点:配置简单,单个Master宕机或重启维护对应用无影响,在磁盘配置为RAID10时,即使机器宕机不可恢复情况下,由于RAID10磁盘非常可靠,消息也不会丢(异步刷盘丢失少量消息,同步刷盘一条不丢),性能最高;

  • 缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息实时性会受到影响。

多Master多Slave模式-异步复制 每个Master配置一个Slave,有多对Master-Slave,HA采用异步复制方式,主备有短暂消息延迟(毫秒级),这种模式的优缺点如下:

  • 优点:即使磁盘损坏,消息丢失的非常少,且消息实时性不会受影响,同时Master宕机后,消费者仍然可以从Slave消费,而且此过程对应用透明,不需要人工干预,性能同多Master模式几乎一样;

  • 缺点:Master宕机,磁盘损坏情况下会丢失少量消息。

多Master多Slave模式-同步双写 每个Master配置一个Slave,有多对Master-Slave,HA采用同步双写方式,即只有主备都写成功,才向应用返回成功,这种模式的优缺点如下:

  • 优点:数据与服务都无单点故障,Master宕机情况下,消息无延迟,服务可用性与数据可用性都非常高;

  • 缺点:性能比异步复制模式略低(大约低10%左右),发送单个消息的RT会略高,且目前版本在主节点宕机后,备机不能自动切换为主机。

安装

wget https://dlcdn.apache.org/rocketmq/5.0.0/rocketmq-all-4.9.4-bin-release.zip
unzip rocketmq-all-4.9.4-bin-release.zip
mv rocketmq-all-4.9.4-bin-release.zip /usr/local/rocketmq

useradd -s /bin/false rocketmq
mkdir -p /data/rocketmq
chown -R /usr/local/rocketmq /data/rocketmq

修改内存

namesrv内存

/usr/local/rocketmq/bin/runserver.sh 

    if [ -z "$JAVA_MAJOR_VERSION" ] || [ "$JAVA_MAJOR_VERSION" -lt "9" ] ; then
      JAVA_OPT="${JAVA_OPT} -server -Xms4g -Xmx4g -Xmn2g -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"

broker内存

vim /usr/local/rocketmq/bin/runbroker.sh 

JAVA_OPT="${JAVA_OPT} -server -Xms8g -Xmx8g"

修改日志路径

sed -i 's#${user.home}#/usr/local/rocketmq#g' /usr/local/rocketmq/conf/*.xml

namesrv配置文件

cat /usr/local/rocketmq/conf/namesrv.properties 

listenPort=8876 # 默认9876

broker配置文件

cat /usr/local/rocketmq/conf/broker.conf

# broker所属集群的名称
brokerClusterName = DefaultCluster
 
# broker的名称
brokerName = broker-a # 不同节点名称需不同
 
# broker的ID, 0表示Master,非0表示Slave
brokerId = 0
 
# 删除文件时间点,默认是凌晨4点
deleteWhen = 04
 
# 文件保留时间,默认保留48小时
fileReservedTime = 48
 
# broker的角色
# ASYNC_MASTER: 异步复制Master
# SYNC_MASTER: 同步双写Master
# SLAVE: slave
brokerRole = ASYNC_MASTER
 
# 刷盘方式
# ASYNC_FLUSH: 异步刷盘
# SYNC_FLUSH: 同步刷盘
flushDiskType = ASYNC_FLUSH
 
# NameServer的地址,如果有多个的话,使用分号分隔开
namesrvAddr=192.168.1.41:8876;192.168.1.42:8876;192.168.1.43:8876
 
# 当前broker监听的IP地址
brokerIP1=192.168.1.41
 
# 在发送消息时,自动创建服务器不存在的topic,默认创建4个队列 
defaultTopicQueueNums=4
 
# 是否允许broker自动创建Topic, 建议线下开启,线上关闭
autoCreateTopicEnable=false
 
#是否允许broker自动创建订阅组, 建议线下开启,线上关闭
autoCreateSubscriptionGroup=false
 
# 启动acl认证
aclEnable=true

# broker对外服务的监听端口 
listenPort=10911
 
# 每个commitLog文件的大小默认是1G
mapedFileSizeCommitLog=1073741824
 
# ConsumeQueue每个文件默认存30W条
mapedFileSizeConsumeQueue=300000
 
# store的存储路径
storePathRootDir=/data/rocketmq/store
 
# commitLog的存储路径 
storePathCommitLog=/data/rocketmq/store/commitlog
 
# 消费队列的存储路径
storePathConsumeQueue=/data/rocketmq/store/consumequeue
 
# 消息索引的存储路径
storePathIndex=/data/rocketmq/store/index
 
# checkpoint文件的存储路径
storeCheckpoint=/data/rocketmq/store/checkpoint
 
# abort文件的存储路径
abortFile=/data/rocketmq/store/abort
 
# 限制的消息大小,默认为4M 
maxMessageSize=65536
 
# 检测物理文件磁盘空间
diskMaxUsedSpaceRatio=75

多网卡需配置brokerIp

brokerIp brokerRole brokername brokerId
192.168.1.41 ASYNC_MASTER broker-a 0
192.168.1.42 ASYNC_MASTER broker-b 0
192.168.1.43 ASYNC_MASTER broker-c 0
192.168.1.44 SLAVE broker-a 1
192.168.1.45 SLAVE broker-b 1
192.168.1.46 SLAVE broker-c 1

ACL

注意用户或密码 长度需大于6个字符,即最多也要xxxx

https://github.com/apache/rocketmq/blob/master/docs/cn/acl/user_guide.md

broker用户信息 此配置会热加载,不用重启服务啦

cat /usr/local/rocketmq/conf/plain_acl.yml

#全局白名单,不受ACL控制
#通常需要将主从架构中的所有节点加进来
globalWhiteRemoteAddresses:
- 10.10.103.*
- 192.168.0.*

accounts:
#第一个账户,可以将accessKey和secretKey理解成用户名和密码
- accessKey: RocketMQ
  secretKey: 12345678
  whiteRemoteAddress:
  admin: false 
  defaultTopicPerm: DENY #默认Topic访问策略是拒绝
  defaultGroupPerm: SUB #默认Group访问策略是只允许订阅
  topicPerms:
  - topicA=DENY #topicA拒绝
  - topicB=PUB|SUB #topicB允许发布和订阅消息
  - topicC=SUB #topicC只允许订阅
  groupPerms:
  # the group should convert to retry topic
  - groupA=DENY
  - groupB=PUB|SUB
  - groupC=SUB
#第二个账户,只要是来自192.168.1.*的IP,就可以访问所有资源
- accessKey: rocketmq2
  secretKey: 12345678
  whiteRemoteAddress: 192.168.1.*
  # if it is admin, it could access all resources
  admin: true

namesrv连接broker要用到broker用户信息 若网段在globalWhiteRemoteAddresses可不操作

cat /usr/local/rocketmq/conf/tools.yml

accessKey: xxxadmin
secretKey: xxxxxxxxxxxxxxxxxxxx

Kernel

/usr/local/rocketmq/bin/os.sh

systemd

rmq-namesrv.service

cat << EOF >/etc/systemd/system/rmq-namesrv.service 
[Unit]
Description=rocketmq namesrv
After=network.target

[Service]
Type=simple  
User=rocketmq
Group=rocketmq
ExecStart=/usr/local/rocketmq/bin/mqnamesrv -c /usr/local/rocketmq/conf/namesrv.properties
ExecStop=/usr/local/rocketmq/bin/mqshutdown namesrv
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

rmq-broker.service

cat << EOF >/etc/systemd/system/rmq-broker.service 
[Unit]
cat /etc/systemd/system/rmq-broker.service 
[Unit]
Description=rocketmq broker
After=network.target

[Service]
Type=simple
User=rocketmq
Group=rocketmq
ExecStart=/usr/local/rocketmq/bin/mqbroker -c /usr/local/rocketmq/conf/broker.conf
ExecStop=/usr/local/rocketmq/bin/mqshutdown broker
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

mqadmin运维管理工具

https://github.com/apache/rocketmq/blob/master/docs/cn/operation.md#2-mqadmin%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7

Dashboard

https://github.com/apache/rocketmq-dashboard

自动主从切换

https://github.com/apache/rocketmq/blob/master/docs/cn/controller/quick_start.md https://github.com/apache/rocketmq/blob/master/docs/cn/controller/deploy.md

高可用测试

  1. master宕机,消息是否会丢失,消费是否正常?

    测试: producer生产消息,关闭所有master,producer不能生产消息,启动consumer,数据消费正常。启动producer生产消息,启动consumer消费消息,关闭其中一个master,producer生产消息和consumer消费消息均正常,但是此时存在consumer消费slave从master同步过来的所有数据,即重复消费。

    结论:消息持久化,master宕机后slave还可以读,在异步刷盘模式中,存在master宕机后极少量的消息丢失,同步刷盘模式中不会丢失数据。 master宕机导致consumer从slave上重复消费master宕机前同步到slave的消息。若master宕机后无法恢复,此时可以重建master,然后将slave的数据拷贝到master的数据目录下重启恢复数据, 此时,在master恢复后其对应的slave可能需要重建。

  2. namesrv宕机是否会影响生产和消费?

    测试:producer生产消息,关闭namesrv,已经连接的producer没有影响,启动consumer不会消费数据,启动namesrc,consumer需等待最多30秒可以开始消费数据。 namesrv之间是没有通信的,独立的,宕机其中任何一台都不会影响集群的使用。

    结论:只要namesrc不全宕机,集群就可用;若都宕机,则已经建立连接的生产者和消费者不受影响。

  3. 如果topic只在一个master上,宕机后还能写吗?

    测试:不管配置文件是否开启autoCreateTopicEnable,在控制台手动创建topic,只指定一个master的情况下,producer生产消息,consumer消费消息,在关闭指定的master后, 生产和消费消息均正常。

    结论:topic的建立是全局的,不会因为某个master或者namesrv宕机而不可用。

  4. slave宕机会影响生产和消费吗?

    结论:在master正常的情况下,slave只和master建立长连接同步数据,不做读写功能;只有master异常或者master消费压力过大(一般会选择brokerID=1的slave提供读)时,slave才提供读的功能。所以slave宕机不会影响生产和消费。

  5. 加入新的namesrv,master重启会有什么影响?

    结论:原有集群的broker添加新的namesrv后,逐一重启master和slave不会对生产和消费数据有影响,一个master重启后最多要30秒才能被producer再次更新连接上。 机制和master宕机是一样的,异步刷盘模式中可能存在极少量数据丢失的情况。但是已有的topic的路由信息不会更新添加新的broker的路由信息, 需要重建或者修改topic才行(若其中一个主broker宕机前删除了某个topic,这个broker宕机了,这时重新创建这个topic是不会有宕机的broker的路由信息的, 当broker恢复后,另一个broker发生宕机后这个topic将不可写了,因为路由信息没有更新,导致该topic不能在双master中高可用,目前版本只能手工使用命令: # ./mqadmin updateTopic -t benchtest -b new_broker_ip:port -n 10.21.17.xxx:9876在新的broker上创建topic),新创建的topic将会包含最新集群的所有broker的路由信息。 开启producer和consumer,然后restart一个broker的master,集群生产消息发送成功,消费正常,不会丢失数据。若是下线broker,为保证数据不丢,在重启前设置该broker的topic只读, 等待一段时间后再停服务下线。

  6. 旧broker不包含新的namesrv和新的broker包含旧namesrv能并存并读写数据正常吗?

    结论:在原有集群的基础上新添加一组namesrv,master和slave,新加的组配置中包含了就集群的namesrv,而旧集群的master和slave没有包含新加的namesrv, 此时producer和consumer仍然使用原有连接生产和消费数据正常,添加上新的namesrv连接地址后,重新运行发现数据的生产和消费还在原来的集群broker上,新加的没有读写。 查看控制台发现topic的路由信息还是指向旧broker,没有更新加入新的broker。如果停掉旧集群的主broker,那么将不能生产数据,会报错。

  7. 设置broker的topic只读,broker是否会丢数据?

    测试:启动producer和consumer正常生产和消费数据,此时设置某个broker的topic只读 (#./mqadmin updateTopicPerm -t hjdemo -p 4 -n 10.21.17.xxx:9876 -b 10.21.17.xxx:10911),生产和消费数据都正常,数据不会丢失。然后再停掉broker。 如果要设置回原来的权限6,需要使用updateTopic命令: (#./mqadmin updateTopic -t hjdemo -w 4 -r 4 -p 6 -n “10.21.17.xxx:9876;10.21.17.xxx:9876;10.21.17.xxx:9876” -b 10.21.17.xxx:10911) 在整个设置过程中生产消费数据正常。

    结论:先设置要关闭的broker的topic为只读,然后再停掉broker,保证不会在停止过程中丢失数据。

其他问题:

1、主,从服务器都在运行过程中,消息消费者是从主拉取消息还是从从拉取?
答:默认情况下,RocketMQ 消息消费者从主服务器拉取,当主服务器积压的消息超过了物理内存的40%,则建议从从服务器拉取。但如果slaveReadEnable为false,表示从服务器不可读,
从服务器也不会接管消息拉取。

2、当消息消费者向从服务器拉取消息后,会一直从从服务器拉取?
答:不是的。分如下情况:
如果从服务器的 slaveReadEnable 设置为 false,则下次拉取,从主服务器拉取。
如果从服务器允许读取并且从服务器积压的消息未超过其物理内存的40%,下次拉取使用的Broker 为订阅组的 brokerId 指定的 Broker 服务器,该值默认为0,代表主服务器。
如果从服务器允许读取并且从服务器积压的消息超过了其物理内存的40%,下次拉取使用的Broker 为订阅组的 whichBrokerWhenConsumeSlowly 指定的 Broker服务器,该值默认为1,代表从服务器。

3、主从服务消息消费进是如何同步的?
答:消息消费进度的同步时单向的,从服务器开启一个定时任务,定时从主服务器同步消息消费进度;无论消息消费者是从主服务器拉的消息还是从从服务器拉取的消息,在向Broker反馈消息消费进度时,
优先向主服务器汇报;消息消费者向主服务器拉取消息时,如果消息消费者内存中存在消息消费进度时,主会尝试跟新消息消费进度。

4、读写分离的正确使用姿势:
    1)主从Broker服务器的slaveReadEnable设置为true。
    2)通过 updateSubGroup 命令更新消息组 whichBrokerWhenConsumeSlowly、brokerId,特别是其 brokerId 不要设置为0,不然从从服务器拉取一次后,下一次拉取还是可能会从主去拉取。

https://www.modb.pro/db/166217