初入职常见问题:弱网络环境构造、压力测试、内存泄漏、性能持续优化工具

文章参考自:

作者:helloworlds
链接:https://zhuanlan.zhihu.com/p/21348220
来源:知乎

弱网络环境的构造 traffic control

traffic control是一个很好的构造弱网络环境的工具,能够控制网络速率、丢包率、延时等网络环境,作为iproute工具集中的一个工具,由linux系统自带。但TC的配置规则很复杂,facebook在tc的基础上封装成了一个开源工具apc,有兴趣的可以试试。

WRK压力测试工具

WRK是一款非常优秀的开源HTTP压力测试工具,采用多线程 + 异步事件驱动的框架,其中事件机制使用了redis的ae事件框架,协议解析使用了nginx的相关代码。相比ab(apache bench)等传统压力测试工具的优点就是性能好,基本上单台机器发送几百万pqs,打满网卡都没有问题。 wrk的缺点就是只支持HTTP类协议,不支持其他协议类测试,比如protobuf,另外数据显示也不是很方便。

nginx的测试用法: wrk -t500 -c2000 -d30s https://127.0.0.1:8443/index.html

内存泄漏

valgrind的缺点

出现内存泄漏或者内存问题,大家第一时间都会想到valgrind.valgrind是一款非常优秀的软件,不需要重新编译程序就能够直接测试。能够检测常见的内存错误包括内存初始化、越界访问、内存溢出、free错误等都能够检测出来。推荐大家使用。
valgrind 运行的基本原理是: 
待测程序运行在valgrind提供的模拟CPU上,valgrind会纪录内存访问及计算值,最后进行比较和错误输出
简单分享下valgrind测试nginx的经验:

  1. nginx通常都是使用master fork子进程的方式运行,使用–trace-children=yes来追踪子进程的信息

  2. 测试nginx + openssl时,在使用rand函数的地方会提示很多内存错误。比如Conditional jump or move depends on uninitialised value,Uninitialised value was created by a heap allocation等。这是由于rand数据需要一些熵,未初始化是正常的。如果需要去掉valgrind提示错误,编译时需要加一个选项:-DPURIFY

  3. 如果nginx进程较多,比如超过4个时,会导致valgrind的错误日志打印混乱,尽量减小nginx工作进程,保持为1个。因为一般的内存错误其实和进程数目都是没有关系的。

但是valgrind也有一个非常大的缺点,就是它会显著降低程序的性能,官方文档说使用memcheck工具时,降低10-50倍。也就是说,如果nginx完全握手性能是20000 qps,那么使用valgrind测试,性能就只有400 qps左右。对于一般的内存问题,降低性能没啥影响,但是有些项目的内存泄漏是在大压力测试时才可能遇到的,如果性能降低这么明显,内存泄漏的错误有可能检测不出来。

AddressSanitizer的优点

address sanitizer(简称asan)是一个用来检测c/c++程序的快速内存检测工具。相比valgrind的优点就是速度快,官方文档介绍对程序性能的降低只有2倍。 对Asan原理有兴趣的同学可以参考asan的算法这篇文章,它的实现原理就是在程序代码中插入一些自定义代码,如下:

编译前: 

 *address = ...; // or: ... = *address; 

编译后: 

if (IsPoisoned(address))

 ReportError(address, kAccessSize, kIsWrite);

*address = ...; // or: ... = *address;`

和valgrind明显不同的是,asan需要添加编译开关重新编译程序,好在不需要自己修改代码。而valgrind不需要编程程序就能直接运行。 
address sanitizer集成在了clang编译器中,GCC 4.8版本以上才支持。我们线上程序默认都是使用gcc4.3编译,于是我测试时直接使用clang重新编译nginx: 

--with-cc="clang" \ --with-cc-opt="-g -fPIC -fsanitize=address -fno-omit-frame-pointer" 其中with-cc是指定编译器,with-cc-opt指定编译选项, -fsanitize=address就是开启AddressSanitizer功能。

由于AddressSanitizer对nginx的影响较小,所以大压力测试时也能达到上万的并发,内存泄漏的问题很容易就定位了。 

性能热点分析

到此,经过改造的nginx程序没有core dump和内存泄漏方面的风险了。但这显然不是我们最关心的结果(因为代码本该如此),我们最关心的问题是: 
1. 代码优化前,程序的瓶颈在哪里?能够优化到什么程度? 
2. 代码优化后,优化是否彻底?会出现哪些新的性能热点和瓶颈? 
这个时候我们就需要一些工具来检测程序的性能热点。

perf,gprof,systemtap

linux世界有许多非常好用的性能分析工具,我挑选几款最常用的简单介绍下: 
1. [perf](Perf Wiki)应该是最全面最方便的一个性能检测工具。由linux内核携带并且同步更新,基本能满足日常使用。**推荐大家使用**。 
2. gprof主要是针对应用层程序的性能分析工具,缺点是需要重新编译程序,而且对程序性能有一些影响。不支持内核层面的一些统计,优点就是应用层的函数性能统计比较精细,接近我们对日常性能的理解,比如各个函数时间的运行时间,,函数的调用次数等,很人性易读。 
3. systemtap 其实是一个运行时程序或者系统信息采集框架,主要用于动态追踪,当然也能用做性能分析,功能最强大,同时使用也相对复杂。不是一个简单的工具,可以说是一门动态追踪语言。如果程序出现非常麻烦的性能问题时,推荐使用 systemtap。

这里再多介绍一下perf命令,tlinux系统上默认都有安装,比如通过perf top就能列举出当前系统或者进程的热点事件,函数的排序。 
perf record能够纪录和保存系统或者进程的性能事件,用于后面的分析,比如接下去要介绍的火焰图。 

火焰图 flame graph

perf有一个缺点就是不直观。火焰图就是为了解决这个问题。它能够以矢量图形化的方式显示事件热点及函数调用关系。 
比如我通过如下几条命令就能绘制出原生nginx在ecdhe_rsa cipher suite下的性能热点: 

  1. perf record -F 99 -p PID -g -- sleep 10

  2. perf script | ./stackcollapse-perf.pl > out.perf-folded

  3. ./flamegraph.pl out.perf-folded>ou.svg

直接通过火焰图就能看到各个函数占用的百分比,比如上图就能清楚地知道rsaz_1024_mul_avx2和rsaz_1024_sqr_avx2函数占用了75%的采样比例。那我们要优化的对象也就非常清楚了,能不能避免这两个函数的计算?或者使用非本地CPU方案实现它们的计算? 当然是可以的,我们的异步代理计算方案正是为了解决这个问题,

 

从上图可以看出,热点事件里已经没有RSA相关的计算了。至于是如何做到的,后面有时间再写专门的文章来分享。

猜你喜欢

转载自blog.csdn.net/qq_33249383/article/details/85112109
今日推荐