记一次 RocketMQ broker 因内存不足导致的启动失败
原创:西狩
编写日期 / 修订日期: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 因内存不足导致的启动失败的更多相关文章
- 最小配置启动SQL SERVER,更改SQL Server最大内存大小导致不能启动的解决方法
如果存在配置问题而无法启动服务器,则可以使用最小配置启动选项来启动 Microsoft SQL Server 实例. 这就是启动选项 -f. 使用最小配置启动 SQL Server 实例会自动将服务器 ...
- 记:cloudstack--gluster主存储上的一个文件损坏导致SSVM启动失败
cloudstack的系统vm(ssvm不停的重建失败).- 1.cloudstack-management 的关键日志 这行 cannot read header 'mnt.......':Inva ...
- 记因PHP的内存溢出导致的事故之解决
如果对您有用记得关注,更多干货. 今天上午刚到公司,就有同事在公司群里反映某个计划任务出现问题了.我就怀着刨根问底的心,去查看了log.发现挺有意思的一个问题,PHP内存溢出导致脚本执行失败.那就一起 ...
- rocketMQ broker 分发并处理请求
使用 netty 监听端口 // org.apache.rocketmq.remoting.netty.NettyRemotingServer#start ServerBootstrap childH ...
- 解Bug之路-记一次JVM堆外内存泄露Bug的查找
解Bug之路-记一次JVM堆外内存泄露Bug的查找 前言 JVM的堆外内存泄露的定位一直是个比较棘手的问题.此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理内存的使用做了定量的分析,从而实锤 ...
- 《JavaScript 闯关记》之垃圾回收和内存管理
JavaScript 具有自动垃圾收集机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存.而在 C 和 C++ 之类的语言中,开发人员的一项基本 ...
- RocketMQ一个新的消费组初次启动时从何处开始消费呢?
目录 1.抛出问题 1.1 环境准备 1.2 消息发送者代码 1.3 消费端验证代码 2.探究CONSUME_FROM_MAX_OFFSET实现原理 2.1 CONSUME_FROM_LAST_OFF ...
- RocketMq灰皮书(二)------本地部署启动MQ
RocketMq灰皮书(二)------本地部署启动MQ Windows10本地部署RocketMQ 在上一篇文章中,我们对rocket的几个基本概念进行了介绍,也了解了业内几大消息中间件的区别.在本 ...
- 记一次centos6升级salt-minion启动失败的问题
记一次centos6升级salt-minion启动失败的问题 作者:耀耀 blog:https://www.liuyao.me 一.起因 升级Salt-minion后 使用/etc/init.d/sa ...
随机推荐
- Azure Service Bus(二)在NET Core 控制台中如何操作 Service Bus Queue
一,引言 上一篇讲到关于 Azure ServiceBus 的一些概念,讲到 Azure Service Bus(服务总线),其实也叫 "云消息服务",是微软在Azure 上提供的 ...
- openstack高可用集群20-openstack计算节点宕机迁移方案
openstack计算节点宕机迁移方案 情景一:/var/lib/nova/instances/ 目录不共享的处理方法(类似手动迁移云主机到其他节点)
- python装饰器学习详解-函数部分
本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理 最近阅读<流畅的python>看见其用函数写装饰器部分写的很好,想写一些自己的读书笔记. ...
- Python自动化办公第三方库xlwt
Python向excel表格写入内容,首先安装第三方库: pip3 install xlwt 代码实例(结合xlrd): #!usr/bin/env python3 #!-*-coding=utf-8 ...
- Python写一个对象,让它自己能够迭代
仿写range()对象,对象是可迭代的: 1 #!usr/bin/env python3 2 # -*- coding=utf-8 -*- 3 4 class myRange(): 5 #初始化,也叫 ...
- Excel 多/整列(多/整行)移位操作
步骤1:创建测试数据 步骤2:把B列和C列进行移位操作(整列移位操作,多列移位操作方法一样) 选中B列,鼠标放到B列边缘地带,直到鼠标显示带有四个箭头方向为止,点击键盘shift键进行拖拽,拖拽时显示 ...
- SpringBoot 的多数据源配置
最近在项目开发中,需要为一个使用 MySQL 数据库的 SpringBoot 项目,新添加一个 PLSQL 数据库数据源,那么就需要进行 SpringBoot 的多数据源开发.代码很简单,下面是实现的 ...
- NIO非阻塞式编程
/** * NIO非阻塞式编程<p> * 服务端和客户端各自维护一个管理通道的对象,我们称之为selector,该对象能检测一个或多个通道 (channel) 上的事件. * 我们以服务端 ...
- css浅谈
一 CSS文字属性: color : #999999; /*文字颜色*/ font-family : 宋体,sans-serif; /*文字字体*/ font-size : 9pt; /*文字大小*/ ...
- Spring框架之spring-webmvc源码完全解析
Spring框架之spring-webmvc源码完全解析 Spring框架提供了构建Web应用程序的全功能MVC模块.Spring MVC分离了控制器.模型对象.分派器以及处理程序对象的角色,支持多种 ...