最近在部署rocketmq到物理机时, 发现并解决了一个主机Load异常飙高的问题, 觉得有必要记录一下。
部署架构如下:
| 机器 |
角色 |
备注 |
|
| ip1 |
nameserver + broker master |
落盘方式:ASYNC_FLUSH |
|
| ip2 |
nameserver + broker slave |
同步方式:异步复制 |
|
| ip3 |
nameserver + benchmark app +tomcat |
|
|
三台机器都是物理机 ,机器配置如下:
| 操作系统 |
centos 6.5 |
| linux 版本 |
2.6.32-431.el6.x86_64 |
| cpu |
40 核Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz |
| 内存 |
64g |
| 磁盘 |
SCSI 3.2T |
| 文件系统 |
ext4 |
| io调度算法 |
cfq(默认的完全公平算法, 并未采用官方文档提到的deadline) . |
| jdk |
1.7.0_71 |
启动rocketmq以后,我们创建了一个测试topic-a, 设置了5个队列(都具有读写权限), 然后启动了5个Producer和5个consumer进行疲劳测试(投递采用的是队列轮询投递, 消费采用的是集群消费方式),启动压力测试,在第二天的早上发现dashboard里面已经查看不到master的机器了 ,这时候试图通过openssh 远程登录也登录不了, 但是22端口仍然可以telnet ,也可以ping通 ,找到运维同事,重新启动机器。
启动后,查看rocketmq本身的gc日志 ,也只看到一些新生代的垃圾回收信息:
2016-08-17T16:02:10.349+0800: 13552.986: [GC2016-08-17T16:02:10.349+0800: 13552.987: [ParNew: 3404557K->47713K(3774912K), 0.2118670 secs] 5311800K->1954963K(7969216K), 0.2121470 secs] [Times: user=2.78 sys=0.00, real=0.21 secs]
2016-08-17T16:02:20.945+0800: 13563.583: [GC2016-08-17T16:02:20.945+0800: 13563.583: [ParNew: 3403233K->49831K(3774912K), 0.2107390 secs] 5310483K->1957085K(7969216K), 0.2110130 secs] [Times: user=2.74 sys=0.00, real=0.21 secs]
2016-08-17T16:02:31.497+0800: 13574.135: [GC2016-08-17T16:02:31.497+0800: 13574.135: [ParNew: 3405351K->48942K(3774912K), 0.2087310 secs] 5312605K->1956200K(7969216K), 0.2090060 secs] [Times: user=2.71 sys=0.00, real=0.21 secs]
这时候查看/var/log/messages, 看linux 系统日志 ,抓到了如下日志:
Aug 15 20:10:11**** kernel: INFO: task java:97019 blocked for more than 120 seconds.
Aug 15 20:10:11**** kernel: Tainted: G --------------- H 2.6.32-431.el6.x86_64 #1
Aug 15 20:10:11**** kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
Aug 15 20:10:11**** kernel: java D 0000000000000000 0 97019 96892 0x00000080
Aug 15 20:10:11**** kernel: ffff880eb8677cf0 0000000000000082 ffffffff810afa0a ffff880f199bf538
Aug 15 20:10:11**** kernel: 00000000000014bc 00000000199bf500 0000000000000000 ffffffffb8677ca8
Aug 15 20:10:11**** kernel: ffff880f198785f8 ffff880eb8677fd8 000000000000fbc8 ffff880f198785f8
Aug 15 20:10:11**** kernel: Call Trace:
Aug 15 20:10:11**** kernel: [<ffffffff810afa0a>] ? futex_wait+0x21a/0x380
Aug 15 20:10:11**** kernel: [<ffffffff81529f85>] rwsem_down_failed_common+0x95/0x1d0
Aug 15 20:10:11**** kernel: [<ffffffff8152a116>] rwsem_down_read_failed+0x26/0x30
Aug 15 20:10:11**** kernel: [<ffffffff8128e854>] call_rwsem_down_read_failed+0x14/0x30
Aug 15 20:10:11**** kernel: [<ffffffff81529614>] ? down_read+0x24/0x30
Aug 15 20:10:11**** kernel: [<ffffffff8104a92e>] __do_page_fault+0x18e/0x480
Aug 15 20:10:11**** kernel: [<ffffffff8152d45e>] do_page_fault+0x3e/0xa0
Aug 15 20:10:11**** kernel: [<ffffffff8152a815>] page_fault+0x25/0x30
Aug 15 20:10:11**** kernel: INFO: task java:97020 blocked for more than 120 seconds.
Aug 15 19:04:56 **** sssd: Killing service [hx], not responding to pings!
发现在晚上的八点多, 有java进程被阻塞了120秒 ,后面紧接着的红色信息大概意思是在开始杀服务,系统对ping操作都已经不响应了 ,询问运维,在这个时间段,也没有对问题主机做任何操作;
没有头绪的情况下,暂时只好重新再做一次benchmark了,发现问题依旧!!rocketmq master又登录不上,直观的感觉就是down掉了,但是端口却能telnet 通,只好再次让运维同事重启机器,登录到master, 通过sar命令,得到了如下信息:
cpu负载(sar -q 得到)
02:17:42 AM runq-sz plist-sz ldavg-1 ldavg-5 ldavg-15
03:15:22 AM 5 1120 14.43 17.30 14.87
cpu利用率:(sar -p 得到)
02:17:42 AM CPU %user %nice %system %iowait %steal %idle
03:15:16 AM all 0.25 0.00 23.40 0.04 0.00 76.30
03:15:22 AM all 0.02 0.00 13.83 0.04 0.00 86.11
内存:(sar -r 得到)
02:17:42 AM kbmemfree kbmemused %memused kbbuffers kbcached kbcommit %commit
03:15:16 AM 593108 65262556 99.10 197600 56394056 20486868 27.59
03:15:22 AM 592224 65263440 99.10 197648 56394296 20485052 27.59
磁盘:(sar -d得到)
02:17:42 AM DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
03:15:16 AM dev8-0 0.37 0.45 4.77 14.24 0.00 1.06 0.71 0.03
03:15:16 AM dev253-0 0.47 0.42 3.65 8.60 0.00 1.16 0.46 0.02
03:15:16 AM dev253-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
03:15:16 AM dev253-2 0.14 0.03 1.11 8.00 0.00 0.42 0.31 0.00
03:15:22 AM dev8-0 11.95 71.38 207.41 23.32 0.03 2.86 1.48 1.77
03:15:22 AM dev253-0 29.29 71.38 207.41 9.52 0.04 1.37 0.60 1.77
03:15:22 AM dev253-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
03:15:22 AM dev253-2 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
04:01:19 AM dev8-0 0.59 3.01 5.61 14.49 0.00 0.85 0.70 0.04
04:01:19 AM dev253-0 0.31 2.98 2.05 16.06 0.00 1.77 0.98 0.03
04:01:19 AM dev253-1 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
发现cpu的负载非常高,而且20%多的cpu都是在系统态,内存利用率已经到了99%以上, 磁盘几乎没有读写。
是什么引起了cpu load这么高,并且花在了系统态上呢,直观感觉就是内存已经很吃紧了.
结合rocketmq的commitlog ,consumequeue ,Index file 都采用了mmap做内存映射来操作文件,吃内存的地方就会是这三个地方,但是索引文件大概500M能索引2000万的消息, 而consumequeue的 一个item是20个字节(8字节commitlog offset+4字节 size+8字节message tag hashcode), 也不会吃太大内存,吃内存的地方就会在commitlog 了。
那疑问在于, 为什么吃内存会把系统的负载搞到这么高呢?我们做了一个mmap的测试程序:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.atomic.AtomicInteger;
/**
* * * Created by lk on 2016/8/16.
* * */
public class MapfileTest {
private static final AtomicInteger wrotePostion = new AtomicInteger(0);
public static void main(String []args) {
File file = new File(args[0]);
int filesize = Integer.MAX_VALUE;
FileChannel fileChannel = null;
MappedByteBuffer mappedByteBuffer = null;
try {
fileChannel = new RandomAccessFile(file,"rw").getChannel();
mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, filesize);
ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024 * 2);
for(int i = 0; i < 1000; ++i){
appendMessage(byteBuffer.array(),filesize,mappedByteBuffer);
try {
Thread.currentThread().sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.in.read();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fileChannel != null){
try {
fileChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static boolean appendMessage(final byte[] data,long fileSize,MappedByteBuffer mappedByteBuffer) {
int currentPos = wrotePostion.get();
if ((currentPos + data.length) <= fileSize) {
ByteBuffer byteBuffer = mappedByteBuffer.slice();
byteBuffer.position(currentPos);
byteBuffer.put(data);
wrotePostion.addAndGet(data.length);
return true;
}
return false;
}
}
上面这个程序是一次创建一个大小为2g的内存映射文件,我们在一个只有5g free内存的虚拟机上 ,逐个启动多个进程:
/opt/jdk/jdk1.7.0_71/bin/java MapfileTest ./testfile1
/opt/jdk/jdk1.7.0_71/bin/java MapfileTest ./testfile2
/opt/jdk/jdk1.7.0_71/bin/java MapfileTest ./testfile3
/opt/jdk/jdk1.7.0_71/bin/java MapfileTest ./testfile4
再通过sudo cat /proc/pid/status 查看进程状态中的VmRSS 指标(实际占用内存) , 得到一个结论,java内存映射文件只要内存够用,就尽量多消耗, 内存不够用的情况下,后起的进程会从先启的进程中抢占内存; 从这里看到,Java内存映射机制本身是没有什么问题的。
再结合前面的问题分析猜想, 虽然Java内存映射没问题 ,但是不是rocketmq的内存吃的太多 ,导致操作系统本身的内存不够用,而直接造成os crash呢?
我们试着调整内核参数:
#允许超量使用内存
echo 'vm.overcommit_memory=1' >> /etc/sysctl.conf
#给系统预留的内存,Kb, 保留16G
echo 'vm.min_free_kbytes=16777216' >> /etc/sysctl.conf
#释放pagecache;
echo 'vm.drop_caches=1' >> /etc/sysctl.conf
#节点内存不够,从其他节点获取内存
echo 'vm.zone_reclaim_mode=0' >> /etc/sysctl.conf
#限制进程的虚拟内存区域的数量
echo 'vm.max_map_count=655360' >> /etc/sysctl.conf
#最大限度使用内存,然后才是swap分区。
echo 'vm.swappiness=0' >> /etc/sysctl.conf
调整好内核参数以后,我们让内核参数实时生效
sudo sysctl -p
然后重启rocketmq ,继续进行benchmark,通过sar -r 3 命令,每3秒钟查看一次内存利用率,发现,
Linux 2.6.32-431.el6.x86_64 (s10-2-26-7.hx) 08/18/2016 _x86_64_ (40 CPU)
04:00:01 AM 23522004 42333660 64.28 151040 32570228 20337848 27.39
04:10:01 AM 22760760 43094904 65.44 153568 33319244 20337664 27.39
04:20:01 AM 22044920 43810744 66.53 154260 34011192 20338040 27.39
04:30:01 AM 21252440 44603224 67.73 154660 34765872 20337548 27.39
04:40:01 AM 24537392 41318272 62.74 153252 31503576 20338100 27.39
....
07:30:01 AM 21264948 44590716 67.71 156280 34532204 20337676 27.39
07:40:01 AM 24547740 41307924 62.72 156920 31266096 20337720 27.39
07:50:01 AM 23789356 42066308 63.88 157592 32016024 20337628 27.39
08:00:01 AM 23872952 41982712 63.75 156716 31929608 20338072 27.39
08:10:01 AM 23000656 42855008 65.07 157412 32785184 20338604 27.39
内存利用率每次达到接近68%的时候, 会立即下降到 62% ,
结合自己在前面设置的参数:
echo 'vm.min_free_kbytes=16777216' >> /etc/sysctl.conf
来分析,物理机器的内存是64g, 保留16g 给系统,
1-16/64= 75%
即从理论上看,内存利用率到75%的时候,就会禁止应用继续申请内存,而实际是到68%左右 ,会启动一次内存回收的动作。
调整完内核参数以后,继续压测一天, rocketmq运行平稳,没有出现之前的os crash的问题。
基本可以确认是之前rocketmq在做commitlog文件的内存映射操作时 ,因为持续的压测,导致commitlog的内存映射操作把内存吃满了,导致系统内存不足而造成。
- IntelliJ IDEA编辑文件的时候CPU飙高问题的解决
原文地址:https://www.javatang.com/archives/2018/04/26/25582403.html 上篇文章中说明了解决IntelliJ IDEA中文输入法无提示的问题,最 ...
- 主机cpu突然飙高,如何快速排查问题
[问题发现] 使用zabbix软件监控服务器时发现cpu突然异常,在业务主机上使用top命令查看系统的整体运行情况,使用top命令后发现mysqld占用CPU特别高,初步判断可能是mysqld出现问题 ...
- 数据库系统load飙高问题解决思路(转)
工作过程中有时候会接收到数据库服务器器load 飙高的报警,比如: load1 15.25 base: 8.52,collect time:2014-08-30 如何处理load 异常飙高的报警呢? ...
- 数据库系统load飙高问题解决思路
工作过程中有时候会接收到数据库服务器器load 飙高的报警,比如: load1 15.25 base: 8.52,collect time:2014-08-30 如何处理load 异常飙高的报警呢? ...
- 记一次yarn导致cpu飙高的异常排查经历
yarn就先不介绍了,这次排坑经历还是有收获的,从日志到堆栈信息再到源码,很有意思,下面听我说 问题描述: 集群一台NodeManager的cpu负载飙高. 进程还在但是看日志已经不再向Resourc ...
- Keepalived+LVS+Nginx负载均衡之高可用
Keepalived+LVS+Nginx负载均衡之高可用 上一篇写了nginx负载均衡,此篇实现高可用(HA).系统整体设计是采用Nginx做负载均衡,若出现Nginx单机故障,则导致整个系统无法正常 ...
- STORM在线业务实践-集群空闲CPU飙高问题排查
源:http://daiwa.ninja/index.php/2015/07/18/storm-cpu-overload/ 2015-07-18AUTHORDAIWA STORM在线业务实践-集群空闲 ...
- 强大核心功能矩阵,详解腾讯云负载均衡CLB高可靠高性能背后架构
1 前言 腾讯云负载均衡(Cloud LoadBalancer),简称CLB, 负载均衡通过设置虚拟服务地址(VIP)将来自客户端的请求按照指定方式分发到其关联的多台后端云服务器,服务器将请求的响应返 ...
- STORM在线业务实践-集群空闲CPU飙高问题排查(转)
最近将公司的在线业务迁移到Storm集群上,上线后遇到低峰期CPU耗费严重的情况.在解决问题的过程中深入了解了storm的内部实现原理,并且解决了一个storm0.9-0.10版本一直存在的严重bug ...
随机推荐
- C#中如果类的扩展方法和类本身的方法签名相同,那么会优先调用类本身的方法
新建一个.NET Core项目,假如我们有如下代码: using System; namespace MethodOverload { static class DemoExtension { pub ...
- sprinboot之mongodb
一.MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当 ...
- #2009. 「SCOI2015」小凸玩密室
神仙题啊.完全想不出 首先看方案.可以从任意一个点开始,在这个点要先走完子树,然后走到父亲,再走兄弟,再走父亲的父亲,父亲的兄弟..一直走到1,1的另外一个子树,结束. 完全不会鸭.jpg 设f[i] ...
- 新买的orico蓝牙usb连接器使用方法与驱动
因为买的型号是 BTA-403 ,所以需要下载该型号驱动 安装好后,可能会出现找不到蓝牙设备问题,所以需要重启机器,并且手动将pc蓝牙连接到手机蓝牙,然后手机蓝牙再连接蓝牙耳机,此时蓝牙耳机会显示连接 ...
- [坑况]——webpack搭建前端环境踩过的坑啊
前言 嘿哈,webpack搭建前端环境踩过的坑啊! 第一个:完全不知所措 webpack4 下面用不了HtmlWebpackPlugin 和 ExtractTextPlugin 解决方案: html- ...
- Apache和Nginx比较
Apache和Nginx对比 功能对比 Nginx和Apache一样,都是HTTP服务器软件,在功能实现上都采用模块化结构设计,都支持通用的语言接口,如PHP.Perl.Python等,同时还支持正向 ...
- UART、SPI、I2C协议异同点
I2C.SPI.UART都是常见的低速板级通信协议,目前主流的SoC都内置了这些通讯协议的控制器,同样,各种传感器.Touch控制器.指纹模块.蓝牙模块.WIFI模块也都兼容这三种通信方式的一种或几种 ...
- 使用Fiddler进行Web接口测试
一.Fiddler简介1.为什么是Fiddler?抓包工具有很多,小到最常用的web调试工具firebug,达到通用的强大的抓包工具wireshark.为什么使用fiddler?原因如下: A)Fir ...
- C# 通用树形数据结构
前言 树在图论中是一种重要的图,由于其自身的许多特殊性质,也是一种重要的计算机数据结构,在很多地方都有用.但是这些树大多都是作为其他应用的内部数据结构来使用.我们无法了解这些树的详细信息,而 .Net ...
- php+mysql 数据库分表分段备份程序--宋正河
<?php //宋正河 转载请注明出处 set_time_limit(0); header('content-type:text/html;charset=utf-8'); mysql_conn ...