新服务上线后观察到,CPU在10 ~ 70%间波动严重,但从每秒业务计数器看业务处理速度很平均。

  接下来是排查步骤:

  1. dstat -tam

  

  大概每10s一个周期,网络流量开始变得很小,随后突然增大,CPU也激增。

  网络流量变化和从性能计数器结果上并不符合,服务相关业务较为复杂,先找出那个业务占用网络流量。

  2. iftop

  找出流量最大的几个目标IP,并且周期的流量变为0随后激增。

  通过IP 知道是外部http接口地址,因为接口调用是异步进行的,性能计算是执行开始记录的,而不是结束记录,因此可以理解。

  也就是每过一段时间所有异步执行的接口调用都会被block一段时间。

  3. tcpdump

  既然被block,首先想到的就是依赖服务不稳定,不定期超时造成。

  抓取tcp 包确认

  但是从网络包中,没有找到任何tcp连接失败,重传等,IO统计流量为0 时,客户端就没有发起任何http 请求。

  也就说明问题出在调用方,httpclient。

  

  4.lhttpc

  仔细看了一遍lhttpc源码,能找到唯一可能影响的地方就是 lhttpc 限制并发连接数为50.

  线上查lhttpc配置时,却发现部署版本不是最新的,汗。。。找到对应版本发现老版本没有并发连接数限制,比较简单也找不到其他问题。

  5. 找出block 代码路径

  找出调用入口,手动执行,发现确实,存在block情况

  通过抓取进程栈:

    io:format("~s~n", [element(2, process_info(Pid, backtrace))]).

  定位到是 lhttpc 老实在调用其他一个接口时block 数秒

  6. fprof 工具

  fprof:start().

  fprof:apply(M, F, A).

  fprof:profile().

  fprof:analyze().

  得到如下结果(摘要)

{[{{lhttpc_client,request,9},                     1, 4993.730,    0.018}],
{ {lhttpc_client,execute,9}, 1, 4993.730, 0.018}, %
[{{lhttpc_client,send_request,1}, 1, 4993.486, 0.004},
{{lhttpc_lib,format_request,7}, 1, 0.130, 0.008},
{{gen_server,call,3}, 1, 0.046, 0.003},
{{lhttpc_lib,normalize_method,1}, 1, 0.038, 0.017},
{{proplists,get_value,3}, 6, 0.006, 0.006},
{{proplists,is_defined,2}, 2, 0.003, 0.003},
{{proplists,get_value,2}, 1, 0.003, 0.002}]}. {[{{lhttpc_client,execute,9}, 1, 4993.486, 0.004},
{{lhttpc_client,send_request,1}, 1, 0.000, 0.003}],
{ {lhttpc_client,send_request,1}, 2, 4993.486, 0.007}, %
[{{lhttpc_sock,connect,5}, 1, 4932.214, 0.006},
{{lhttpc_client,read_response,1}, 1, 61.202, 0.004},
{{lhttpc_sock,send,3}, 1, 0.061, 0.001},
{{erlang,setelement,3}, 1, 0.002, 0.002},
{{lhttpc_client,send_request,1}, 1, 0.000, 0.003}]}. {[{{inet_gethost_native,getit,2}, 1, 4929.280, 0.000},
{{prim_inet,recv0,3}, 1, 59.932, 0.000},
{{prim_inet,connect0,4}, 1, 2.082, 0.000},
{{lhttpc_client,request,9}, 1, 0.017, 0.000},
{{gen,do_call,4}, 1, 0.017, 0.000}],
{ suspend, 5, 4991.328, 0.000}, %
[ ]}. {[{{gen_tcp,connect,4}, 1, 4932.188, 0.007}],
{ {gen_tcp,connect1,4}, 1, 4932.188, 0.007}, %
[{{inet_tcp,getaddrs,2}, 1, 4929.488, 0.013},
{{gen_tcp,try_connect,6}, 1, 2.672, 0.020},
{{gen_tcp,mod,2}, 1, 0.019, 0.002},
{{inet_tcp,getserv,1}, 1, 0.002, 0.002}]}. {[{{gen_tcp,connect1,4}, 1, 4929.488, 0.013}],
{ {inet_tcp,getaddrs,2}, 1, 4929.488, 0.013}, %
[{{inet,getaddrs_tm,3}, 1, 4929.475, 0.008}]}. {[{{inet_tcp,getaddrs,2}, 1, 4929.475, 0.008}],
{ {inet,getaddrs_tm,3}, 1, 4929.475, 0.008}, %
[{{inet,gethostbyname_tm,3}, 1, 4929.445, 0.005},
{{inet_parse,visible_string,1}, 1, 0.022, 0.001}]}. {[{{inet,getaddrs_tm,3}, 1, 4929.445, 0.005}],
{ {inet,gethostbyname_tm,3}, 1, 4929.445, 0.005}, %
[{{inet,gethostbyname_tm,4}, 1, 4929.430, 0.002},
{{inet_db,res_option,1}, 1, 0.009, 0.002},
{{lists,member,2}, 1, 0.001, 0.001}]}. {[{{inet,gethostbyname_tm,3}, 1, 4929.430, 0.002}],
{ {inet,gethostbyname_tm,4}, 1, 4929.430, 0.002}, %
[{{inet,gethostbyname_tm_native,4}, 1, 4929.428, 0.004}]}. {[{{inet,gethostbyname_tm,4}, 1, 4929.428, 0.004}],
{ {inet,gethostbyname_tm_native,4}, 1, 4929.428, 0.004}, %
[{{inet_gethost_native,gethostbyname,2}, 1, 4929.423, 0.002},
{{inet,gethostbyname_tm,5}, 1, 0.001, 0.001}]}.

  从上面看,block在于 inet_tcp:getaddrs, 阅读源码发现是调用native 解析dns 的问题。

  

  7. erlang dns

  dig 域名,dnsserver 是内网服务器,响应都在1ms内,长时间测试,不存在任何延时。

  因为怀疑是erlang dns 实现的问题

  http://erlang.org/doc/apps/erts/inet_cfg.html

> inet_db:get_rc().
[{nameservers,{10,13,8,25}},
 {nameservers,{172,16,105,248}},
 {resolv_conf,"/etc/resolv.conf"},
 {hosts_file,"/etc/hosts"},
 {lookup,[native]}]
> ets:lookup(inet_db, cache_size).
[{cache_size,100}]

{lookup, Methods}.

Methods = [atom()]

Specify lookup methods and in which order to try them. The valid methods are: native (use system calls), file (use host data retrieved from system configuration files and/or the user configuration file) or dns (use the Erlang DNS client inet_res for nameserver queries).

上面说明,默认情况erlang 每次dns查询都是查询直接走系统调用,只有但 lookup [dns] 时才会启用erlang 内部的 dns cache。

  

8. 系统dns

既然erlang 没有dnscache 抓包分析一下,系统

tcpdump -i any udp port 53

21:34:58.739732 IP 10.77.128.49.49003 > 10.13.8.25.domain: 26954+ A? i.api.xxx.cn. (32)
21:34:58.739941 IP 10.13.8.25.domain > 10.77.128.49.49003: 26954 1/4/4 A 172.16.105.232 (193)
21:34:58.740546 IP 10.77.128.49.40072 > 10.13.8.25.domain: 39440+ A? i.api.xxx.cn. (32)
21:35:02.205299 IP 10.77.128.49.6060 > 10.13.8.25.domain: 48139+ A? bx49. (22)
21:35:02.207506 IP 10.13.8.25.domain > 10.77.128.49.6060: 48139 NXDomain 0/1/0 (97)
21:35:03.479277 IP 10.77.128.49.51277 > 10.13.8.25.domain: 11779+ A? bx49. (22)
21:35:03.479501 IP 10.13.8.25.domain > 10.77.128.49.51277: 11779 NXDomain 0/1/0 (97)
21:35:03.745591 IP 10.77.128.49.24134 > 172.16.105.248.domain: 39440+ A? i.api.xxx.cn. (32)
21:35:03.747254 IP 172.16.105.248.domain > 10.77.128.49.24134: 39440 1/4/4 A 172.16.105.232 (193)

从包中,存在大量频繁的请求对i.api.xxx.cn 域名的查询,而且被我标黄的那条记录没有应答,5s后重发请求才收到结果。

总结:

i.api.xxx.cn 接口不支持keepalive,每次都需要新建连接,erlang 每次都需要进行系统调用查询DNS

服务器没有启动 nscd 服务,没有缓存

DNS 使用UDP 协议,即使时内网,偶尔也会丢失

erlang 对于并发查询同一个DNS 会做合并,同时只会有一个DNS 请求

erlang 的系统调用超时时间太长(5s),没有及时的重发查询,造成期间请求堆积,等DNS返回,堆积的业务同时开始处理,造成CPU波动。

解决方案:

1. 启动nscd 2. 配置inet 使用内存dns 模块缓存

  

一次erlang 节点CPU严重波动排查的更多相关文章

  1. 云计算之路-阿里云上:节点 CPU 波动引发 docker swarm 集群故障

    非常抱歉,今天 10:05-10:20 左右,我们用阿里云服务器搭建的 docker swarm 集群又出现故障,又是因为突然的节点 CPU 波动. 受这次故障影响的站点有 闪存,博问,班级,园子,短 ...

  2. Erlang中如何在同一台机器上运行多个erlang节点?

    首先打开shell,然后在打开cmd输入:erl -sname bilbo  这样就启动了一个gandal的erlang节点. 如图:

  3. Java进程CPU使用率高排查

    Java进程CPU使用率高排查 生产java应用,CPU使用率一直很高,经常达到100%,通过以下步骤完美解决,分享一下.1.jps 获取Java进程的PID.2.jstack pid >> ...

  4. CPU高问题排查

    双11大战开始了,这几天公司系统压测,CPU各种报警,于是找了篇关于CPU高问题排查的文章. 一个应用占用CPU很高,除了确实是计算密集型应用之外,通常原因都是出现了死循环. (友情提示:本博文章欢迎 ...

  5. Linux(2)---记录一次线上服务 CPU 100%的排查过程

    Linux(2)---记录一次线上服务 CPU 100%的排查过程 当时产生CPU飙升接近100%的原因是因为项目中的websocket时时断开又重连导致CPU飙升接近100% .如何排查的呢 是通过 ...

  6. erlang节点互相ping,一个能ping通,另外一个不行。

    今天发现一个问题,2个erlang节点,1个主动ping另外一个不通,然后等待另外一个ping过来,2个节点才连通.记录一下. 首先,erlang节点的cookie是一致的.查了文档,cookie一致 ...

  7. erlang节点互通查看

    在局域网内部,一般用短节点名来完成短节点的全联通.     全联通的前提之一是cookie要相同,cookie记录在一个文件中.     对于同一个物理机上的两个erlang节点,不用其他配置就可以全 ...

  8. Erlang节点重启导致的incarnation问题(转)

    转自霸爷的博客: 转载自系统技术非业余研究 本文链接地址: Erlang节点重启导致的incarnation问题 遇到个问题, =ERROR REPORT==== 10-Mar-2016::09:44 ...

  9. erlang 虚机CPU 占用高排查

    -问题起因 近期线上一组服务中,个别节点服务器CPU使用率很低,只有其他1/4.排除业务不均,曾怀疑是系统top统计错误,从Erlang调度器的利用率调查 找到通过erlang:statistics( ...

随机推荐

  1. VS2013快捷键及技巧

    VS2013快捷键很多,灵活使用常用快捷键及各项技巧可以让你事半功倍.下面的visual studio 2013快捷键和操作技巧你知道多少? 1.回到上一个光标位置/前进到下一个光标位置 1)回到上一 ...

  2. __new__静态方法

    __new__静态方法 新式类都有一个__new__的静态方法,它的原型是object.__new__(cls[, ...]) cls是一个类对象,当你调用C(*args, **kargs)来创建一个 ...

  3. sql server多重行列转置的优化

    将表1转化成表2: 表1 表2 得到表2的结果,需要经过多次pivot转换,再经union连接到一起,代码如下: ] from ( select 'a' as type, * from Table_1 ...

  4. C#设计模式(2)——简单工厂模式

    一.概念:简单工厂模式(Simple Factory Pattern)属于类的创新型模式,又叫静态工厂方法模式(Static FactoryMethod Pattern),是通过专门定义一个类来负责创 ...

  5. json的场景应用与实战

    首先 要感谢慕课网的老师 地址:http://www.imooc.com/learn/68 下面我来开始总结: 什么是json的这些我就不多说了  不懂百度 <?php function cre ...

  6. xv6课本翻译之——第0章 操作系统接口

    Chapter 0 第0章 Operating system interfaces 操作系统接口 The job of an operating system is to share a comput ...

  7. oracle 修改字符集支持中文

    1.登录sys关闭服务 [oracle@t-e ~]$ export ORACLE_SID=kamiltest1 [oracle@t-e ~]$ sqlplus / as sysdba SQL> ...

  8. DedeCMS flink_add Getshell漏洞 管理员CSRF漏洞

    DedeCMS flink_add Getshell漏洞 管理员CSRF漏洞 1.漏洞利用 由于tpl.php中的$action,$content,$filename变量没有初始化,从而能操纵这些变量 ...

  9. php 使用函数中遇到的坑之----strpos

    strpos — 查找字符串首次出现的位置 mixed strpos ( string $haystack , mixed $needle [, int $offset = 0 ] ) <?ph ...

  10. 通过实现System.IComparable接口的CompareTo方法对两个类进行比较

    假设现在有一个学生类 class Student { int age; public Student(int age) { this.age = age; } } 要使学生类之间能进行比较,实现Sys ...