原创:西狩

编写日期 / 修订日期:2020-01-12 / 2020-01-12

版权声明:本文为博主原创文章,遵循 CC BY-SA-4.0 版权协议,转载请附上原文出处链接和本声明。

背景

该小节交代问题发生的背景,急需解决问题的小伙伴,可以跳过本节,直接看下一小节。

因为项目提测,需要搭建一套测试环境。所以呢,是时候展示真正的技术啦!在搞定了容器、中间件、项目镜像后,小西登录系统对各大模块的功能进行测试。事情到了这里,小西本来应该会就这样愉快地完成了部署任务,可是生活总是会给你带来意想不到的“惊喜”。

  • 在测试一类预警事件消息时,忽然发现压根没有消息,就去 RocketMQ 的控制台界面查看,发现控制台原本应该乖乖被监控的 broker 一个都不在了。

  • 在不考虑 broker 不会自己罢工跑掉的情况下,登录服务器查看 broker 服务,发现服务没有启动成功。

  • 再查看 broker 的启动日志,发现启动报错了。

于是,就有了这篇分享。

部署环境

操作系统:centos7 linux 系统

部署方式:docker 容器 + docker-compose 容器编排

部署版本:RocketMQ 4.4.0

问题描述

开发环境访问 RocketMQ 控制台,发现 broker 服务宕机。登录服务器查看日志发现以下报错:

Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000c0000000, 7163871232, 0) failed; error=
...
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 7163871232 bytes for Failed to commit area from 0x00000000c0000000 to
...

提示内存分配无法满足 7163871232 字节的需求。那为什么会出现这个问题呢?

问题定位

重启broker

刚开始没有排查日志时,以为环境被人停掉了,所以对 broker 进行了重启。

[root@172-30-1-135 nginx]# docker-compose restart

发现 broker 启动依旧失败,而 namesrv 和 console 启动正常。

分析启动脚本

登录 RocketMQ 的 docker 容器。

注意,因为 broker 无法启动,使用 docker exec 是无法进入容器的,需要使用 docker run 命令进入容器。

[root@37-128-28-177 nginx]# docker run -it rocketmqinc/rocketmq:4.4.0 bash

查看启动脚本 broker.sh

[rocketmq@38bc66dd72c3 bin]$ vi runbroker.sh

发现 runbroker.sh 启动脚本中有最大允许堆内存的配置项 MAX_POSSIBLE_HEAP

...
# Get the max heap used by a jvm, which used all the ram available to the container.
if [ -z "$MAX_POSSIBLE_HEAP" ]
then
MAX_POSSIBLE_RAM_STR=$(java -XX:+UnlockExperimentalVMOptions -XX:MaxRAMFraction=1 -XshowSettings:vm -version |& awk '/Max\. Heap Size \(Estimated\): [0-9KMG]+/{ print $5}')
MAX_POSSIBLE_RAM=$MAX_POSSIBLE_RAM_STR
CAL_UNIT=${MAX_POSSIBLE_RAM_STR: -1}
if [ "$CAL_UNIT" == "G" -o "$CAL_UNIT" == "g" ]; then
MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
elif [ "$CAL_UNIT" == "M" -o "$CAL_UNIT" == "m" ]; then
MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024 \* 1024` | awk '{printf "%d",$1*$2}')
elif [ "$CAL_UNIT" == "K" -o "$CAL_UNIT" == "k" ]; then
MAX_POSSIBLE_RAM=$(echo ${MAX_POSSIBLE_RAM_STR:0:${#MAX_POSSIBLE_RAM_STR}-1} `expr 1 \* 1024` | awk '{printf "%d",$1*$2}')
fi
MAX_POSSIBLE_HEAP=$[MAX_POSSIBLE_RAM/4]
fi # Dynamically calculate parameters, for reference.
Xms=$MAX_POSSIBLE_HEAP
Xmx=$MAX_POSSIBLE_HEAP
Xmn=$[MAX_POSSIBLE_HEAP/2]
...

从脚本中可以看出,在 runborker.sh 脚本中, MAX_POSSIBLE_HEAP 参数值会通过参数进行设置,而如果没有任何设置就会走下面这个判断:

MAX_POSSIBLE_HEAP=$[MAX_POSSIBLE_RAM/4]

也就是说 MAX_POSSIBLE_HEAP 参数如果没有指定,它会使用四分之一的最大可用内存 MAX_POSSIBLE_RAM ,这一机制可以保护服务器的操作系统不会因为被服务占据全部内存而无法正常运行。但当服务器的可用内存较小时,这个四分之一对于 RocketMQ 来说就有些“捉襟见肘”了。所以,也就导致了 RocketMQ 因内存不足而无法启动。

分析出原因以后,就可以考虑通过显式指定参数的方式解决这个问题。

解决方案

方案一:修改最大堆内存

退出 docker 容器,修改 RocketMQ 服务 docker-compose.yml 文件,给 broker 指定 MAX_POSSIBLE_HEAP 参数,指定为 1024m

broker:
image: rocketmqinc/rocketmq:4.4.0
container_name: rmqbroker
ports:
- 10909:10909
- 10911:10911
- 10912:10912
volumes:
- /data/admin/app/yunying/mq/logs/broker:/home/rocketmq/logs
- /data/admin/app/yunying/mq/broker:/home/rocketmq/store
- /data/admin/app/yunying/mq/broker.conf:/opt/rocketmq-4.4.0/conf/broker.conf
command: sh mqbroker -n 172.30.1.135:9876 -c /opt/rocketmq-4.4.0/conf/broker.conf
depends_on:
- namesrv
environment:
- "autoCreateTopicEnable=true"
- "JAVA_HOME=/usr/lib/jvm/jre"
# 指定堆内存大小
- "MAX_POSSIBLE_HEAP=1024m"
- TZ=Asia/Shanghai

重启 broker。查看日志,发现以下报错。

/opt/rocketmq-4.4.0/bin/runbroker.sh: line 58: 1024m: value too great for base (error token is "1024m")

由于原始问题报错信息中的单位是 bytes,考虑到参数单位可能与 JVM 内存设置参数不同,再次修改堆内存配置。

# 省略其他无关信息
broker:
environment:
# 指定堆内存大小
- "MAX_POSSIBLE_HEAP=1073741824"

重启 broker,启动成功。

[admin@zw-yunying-172.30.1.135 mq]$ docker logs -f --tail 10 rmqbroker
The broker[broker-a, 172.30.1.135:10911] boot success. serializeType=JSON and name server is 172.30.1.135:9876

至此,问题解决。

方案二:修改JVM元空间大小

本方案是网上查找资料发现的解决方案,报错问题类似但不完全一致。该方案没有做验证,不确定是否能够解决该问题。

感兴趣的小伙伴可以验证一下,下面是问题描述和解决方案。

问题描述为:

JRE version: (8.0_172-b11) (build )
Java VM: Java HotSpot(TM) 64-Bit Server VM (25.172-b11 mixed mode linux-amd64 compressed oops)
Java运行时环境的内存不足,无法继续,本机内存分配(mmap)未能映射8589934592字节,用于提交保留内存

解决方案如下:

找到 runserver.sh 和 runbroker.sh,编辑

JAVA_OPT=”${JAVA_OPT} -server -Xms256m -Xmx1024m -Xmn125m -XX:MetaspaceSize=1024m -XX:MaxMetaspaceSize=1024m”

参考资料

记一次 RocketMQ broker 因内存不足导致的启动失败的更多相关文章

  1. 最小配置启动SQL SERVER,更改SQL Server最大内存大小导致不能启动的解决方法

    如果存在配置问题而无法启动服务器,则可以使用最小配置启动选项来启动 Microsoft SQL Server 实例. 这就是启动选项 -f. 使用最小配置启动 SQL Server 实例会自动将服务器 ...

  2. 记:cloudstack--gluster主存储上的一个文件损坏导致SSVM启动失败

    cloudstack的系统vm(ssvm不停的重建失败).- 1.cloudstack-management 的关键日志 这行 cannot read header 'mnt.......':Inva ...

  3. 记因PHP的内存溢出导致的事故之解决

    如果对您有用记得关注,更多干货. 今天上午刚到公司,就有同事在公司群里反映某个计划任务出现问题了.我就怀着刨根问底的心,去查看了log.发现挺有意思的一个问题,PHP内存溢出导致脚本执行失败.那就一起 ...

  4. rocketMQ broker 分发并处理请求

    使用 netty 监听端口 // org.apache.rocketmq.remoting.netty.NettyRemotingServer#start ServerBootstrap childH ...

  5. 解Bug之路-记一次JVM堆外内存泄露Bug的查找

    解Bug之路-记一次JVM堆外内存泄露Bug的查找 前言 JVM的堆外内存泄露的定位一直是个比较棘手的问题.此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理内存的使用做了定量的分析,从而实锤 ...

  6. 《JavaScript 闯关记》之垃圾回收和内存管理

    JavaScript 具有自动垃圾收集机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存.而在 C 和 C++ 之类的语言中,开发人员的一项基本 ...

  7. RocketMQ一个新的消费组初次启动时从何处开始消费呢?

    目录 1.抛出问题 1.1 环境准备 1.2 消息发送者代码 1.3 消费端验证代码 2.探究CONSUME_FROM_MAX_OFFSET实现原理 2.1 CONSUME_FROM_LAST_OFF ...

  8. RocketMq灰皮书(二)------本地部署启动MQ

    RocketMq灰皮书(二)------本地部署启动MQ Windows10本地部署RocketMQ 在上一篇文章中,我们对rocket的几个基本概念进行了介绍,也了解了业内几大消息中间件的区别.在本 ...

  9. 记一次centos6升级salt-minion启动失败的问题

    记一次centos6升级salt-minion启动失败的问题 作者:耀耀 blog:https://www.liuyao.me 一.起因 升级Salt-minion后 使用/etc/init.d/sa ...

随机推荐

  1. Fabric 配置 order节点问题

    问题描述: Error: failed to create deliver client: orderer client failed to connect to orderer.example.co ...

  2. vue第十七单元(电商项目逻辑处理,电商划分)

    第十七单元(电商项目逻辑处理,电商划分) #课程目标 1.什么是电商项目 2.什么是B2B,B2C,C2C模式,常见的电商项目 3.移动端电商项目常见的逻辑处理 4.[知识扩展]传统系统架构及分布式系 ...

  3. Spark-6-如何缓解消除数据倾斜

    1 尽量避免数据源的数据倾斜 比如数据源是Kafka 以Spark Stream通过DirectStream方式读取Kafka数据为例.由于Kafka的每一个Partition对应Spark的一个Ta ...

  4. pytest接口测试轻松入门

    通过Postman请求结果如下图: 那我们怎么用pytest进行测试呢? 在接口测试,我们要用到requests包,实现代码如下: import pytest import allure import ...

  5. mysql 查询出来的内容无法显示全部

    前几天在做查询的时候,由于使用了字段拼接,所以查出来的其中一列,数据很长,但是每次显示一定的长度后,后面的就无法显示 原因是因为mysql设置查询出来的长度,好像默认是1024,因为我使用的是yii2 ...

  6. 高可用K8S构建3master+3node+keepalived+haproxy

    视频地址:https://www.bilibili.com/video/BV1w4411y7Go?p=66 所需安装包在视频评论区 安装准备 系统: CentOS-7-x86_64-Minimal-1 ...

  7. .net下com调用支持x86/x64

    起因 项目涉及u3d/wpf端的渲染图形合成,采用了开源项目spout,为了便捷,采用了spout的com版本作为c#端的调用 项目调整后,细节已经捋清楚了. 但是考虑桌面应用采用anypc,根据运行 ...

  8. Azure Databricks 第一篇:创建工作区、集群和Notebook

    Azure Databricks是一个可扩展的数据分析平台,基于Apache Spark.Azure Databricks 工作区(Workspace)是一个交互式的环境,工作区把对象(noteboo ...

  9. Spring AOP 实战运用

    Spring AOP 实战 看了上面这么多的理论知识, 不知道大家有没有觉得枯燥哈. 不过不要急, 俗话说理论是实践的基础, 对 Spring AOP 有了基本的理论认识后, 我们来看一下下面几个具体 ...

  10. 初始MQTT

    初识 MQTT   物联网 (IoT) 设备必须连接互联网.通过连接到互联网,设备就能相互协作,以及与后端服务协同工作.互联网的基础网络协议是 TCP/IP.MQTT(消息队列遥测传输) 是基于 TC ...