新服务上线后观察到,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. ACM模板(持续补完)

    1.KMP #include<cstring> #include<algorithm> #include<cstdio> using namespace std; ...

  2. MVC跨域CORS扩展

    一般的基于浏览器跨域的主要解决方法有这么几种:1.JSONP       2.IFrame方式    3.通过flash实现  4.CORS跨域资源共享  ,这里我们主要关注的是在MVC里面的CORS ...

  3. 工作邮件loop的用法

    examples come from native speaker Put john in the loop about this. He will have good advice. Why hav ...

  4. Android 第三方图表类 MPChart 的使用

    先看看条形图的的效果还不错是吧,实现这样的效果很合适呢! 还有折线图.饼图很多效果 效果不错对吧~ 下面我们就先来看看条形图的实现方法吧! 第一步: 引入第三方包 MPChart 如果你碰巧看过我之前 ...

  5. 在 kernel 下打 log。 怪異現象與解決方式。

    code battery_log(BAT_LOG_CRTI, "y t: %d \n", (int)my_timer_timeout); battery_log(BAT_LOG_C ...

  6. python基础补漏-02-collection

    collection系列 [1]计数器 Counter import collections res = collections.Counter("34234sdfgs45tsaf1&quo ...

  7. com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'dd' in 'where clause'

    今天在使用mysql数据库查找数据的时候报错,错误信息如下: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown co ...

  8. Newick format tree

    1. all branches + leaf names + internal supports ((D:0.723274,F:0.567784)1.000000:0.067192,(B:0.2793 ...

  9. Ajax基础

    1 概要 异步JavaScript和XML(Asynchronous Javascript And XML,Ajax)就是使用js来收发来自web服务器的数据,且无需重载整个页面的技术. 注 :xml ...

  10. Table 表单样式

    <style> table th { white-space: nowrap; background-color: #f5f5f5; height:30px; font-size:14px ...