查看内存fd是否泄露

http://www.cnblogs.com/stable/archive/2011/01/17/1937657.html


逻辑server通常的处理能力在3k/s - 1w/s之间,因业务特点而不同。逻辑server一般是自主开发的,虽然在上线前大都经过功能和压力测试,但放到现网环境上部署后还是难免会出现一些问 题,有些问题是在灰度发布时就可以发现,而有些问题则是一个漫长的暴露过程。下面先总结一下大致的问题分类和定位方法。

 

    1. 程序BUG如fd泄漏或内存泄漏

    业务上线前一定要做压测,同时查看进程消耗的内存与fd数,结合业务特性分析fd使用量是否合理,同时观察内存使用是不是最终会趋于稳定的值,如果一直增加,就肯定有泄漏。

    fd泄漏确认方法是:ls /proc/pid/fd -al | wc,可以看到单个进程使用的fd数,观察是否一直在涨长,如果没有最终达到一个稳定值,则可以确认存在泄漏。同时可以cat /proc/net/sockstat观察整体的fd使用数量是否一直在涨长,通常32位的机器,fd超过10W时系统会到达瓶颈。

    内存泄漏确认方法是:top 看进程使用的RES 和 SHR,观察是否一直在涨长,如果没有最终达到一个稳定值,则可以确认存在泄漏。同时可以看下mem的使用量是否一直在增加。内存泄漏最终的结果是使用到 的swap分区,一旦出现这种情况,cpu的wa字段会出现远大于0的情况,表明cpu阻塞在等待输入输出上。

 

    2. 业务自然增长

    这一点依赖于对请求数的统计,通过对前后几天的对比,不难确认是否是业务自然增长,单机请求量上升使系统出现瓶颈,这种问题通过扩容可以轻松解决,但最好 的办法是对系统的容量和关键参数如cpu\mem\eth加上监控,能够做到提前告警,这样不至于在出问题的时候紧急扩容。

 

    3. 特性变更导致用户行为异常

    举个例子,有一次我在升级server时,基于性能的考虑,少返回了一个已无效的字段,灰度升级一台机器后,发现系统负载升高了3倍,当时的第一反应是有 bug,使到cpu的使用突增,但vmstat发现 升级前cpu使用率 usr 和 sys大致是 14  7,升级后为 42 21,大致同比增长了3倍,再看一下请求数,发现请求数也同比增长,可见,是某些原因达致用户在重试。

    因为上线前经过功能测试,所以正常用户的功能应该没有问题,对比这些的版本发更,发现有可能是少返回了一个字段,使外挂用户解析失败而不停重试,因此重新 加上字段后再次发布,问题解决。从那次之后,总结了一点,当返回给用户侧的数据出现字段变更时,一定要灰度发布确认是否影响到外挂用户,如果有影响的话可 以返回通过假数据解决。

 

    4. 系统参数配置不当

    举个例子,一段时间发现在访问高峰时段,进程会出现申请fd失败的情况,由于某些接口采用短连接,每次处理都需要申请fd、处理、释放fd,后来查看了系 统参数,发现/proc/sys/net/ipv4/tcp_tw_recycle 和 /proc/sys/net/ipv4/tcp_tw_reuse都配的是0,0表示不开启加快回收fd和复用time_wait状态的fd,导致短连接 关闭后,fd大面积处在time_wait状态,因些新的请求由于申请不到fd而失败,通过调整系统参数后问题解决。

 

    5. 编码问题导致系统处理能力较差

     其实这个范畴的不能算是运营问 题,但是处理能力较差的系统会很容易到达瓶颈。在编码过程中,一定要注意避免无谓的开销,特别是系统调用等。这里我总结了几条供大家参考:配置只解析一 次,然后常驻内存或共享内存;常用的工具类如上报、写日志等,使用static或单件模式,保证只初始化一个;尽量采用长连接,减少fd申请、建连接、释 放带来的开销;通知等非关键可丢失的消息使用udp,只发不收;不打印不必要的日志,而且要循环写,防止日志文件过大时出错;外部接口超时尽量短,防止进 程因外部接口问题被挂住;单个进程的设定最大处理时长,保证系统最差情况时的处理能力;少用time、stat等系统调用。

    系统调用方面,可以通过strace -c统计系统调用次数和耗时,从而对业务逻辑优化。strace -c的使用方法,详见我的另一篇文章。 

    这里举个例子,我有一次strace -c了一个处理进程,发现stat函数的cpu使用率非常高,然后strace跟踪了一下进程的系统调用发现,该进程用到了一个统计上报的类,类本身是用 static初始化的,但类的上报接口中,每次都会初始化一个对象,对采样进行分析,并进行上报,这时会解析一次采样配置文件同时再解析一次上报配置文 件,所以虽然类本身是static但是已经没有意义了,对象还是每次都会初始化,后来改造了一下,把接口中的对象用指针代替,只在第一次接口调用时初始 化,再次调用时,判断指针非NULL,则直接使用。优化后,发现系统的cpu使用下降了近20%,可见,减少无谓的系统调用对系统的处理能力是有很大提升 的。

 

    以上总结了常见的运维问题和定位方法,相信大家大致有一套自已定位问题的方法,这里我谈下我定位问题的基本流程,供大家参考:

    1. 查看日志

    通过查看系统日志,可以第一时间确定是不是业务逻辑或外部接口出了问题,并可以结合代码进程核实。

 

    2. 是否fd>10W

    cat /proc/net/sockstat,观察tcp_use字段,如果持续增长而不趋于稳定说明fd泄漏或连接数过多,>10w时系统会出现异常。

 

    3. 负载分析

    首先用vmstat 1,观察cpu 、swap和r字段,大致可以分为以下几种情况:

    cpu的wa字段远>0,并且swap的si字段远>0,说明已经用到了交换分区,这时通过top观察进程的RES和SHR字段,如果RES字段很大,并且持续增长,可以确认是存在内存泄漏。

    cpu的usr和sys成比例比较高,r字段值也比较高,而swap使用量为0,说明可能是请求量有变化,这时核对请求量数据,是否成比例增长,如果是成比例增长的话,可以确认是请求量增大的原因,这时要根据几天的请求量数据确认是突增还是自然增长。


你可能感兴趣的:(C++)