为什么压测性能低

更新时间:2017-08-07 11:23:07

为什么7层负载均衡压测性能低?

我有一个HTTP负载均衡监听,后面挂了多个ECS,为什么压测性能跑不上去?

7层性能会比4层性能低

负载均衡集群采用LVS和Tengine实现,其中4层监听经过LVS后直接到达后端服务器,而7层监听经过LVS后,还需要再经过Tengine,最后达到后端服务器。就是说7层比4层多了一个处理环节,因此,7层性能没有4层性能好。

除了7层本身的性能较4层低外,有的用户发现7层性能很差,根本跑不上去,挂了两台ECS的7层负载均衡监听性能还不如一台ECS的性能,有可能是如下原因:

CASE1 客户端端口不足

尤其容易发生在压测的时候,客户端端口不足会导致建立连接失败,负载均衡默认会抹除tcp连接的timestamp属性,linux协议栈的tw_reuse(time_wait状态连接复用)无法生效,time_wait状态连接堆积导致客户端端口不足。

解决方法:

客户端端使用长连接代替短连接。

使用RST报文断开连接(socket设置SO_LINGER属性) ,而不是发FIN包这种方式断开。

CASE2 后端服务器accept队列满

后端服务器accept队列满,导致后端服务器不回复syn_ack报文,客户端超时。

解决方法:默认的net.core.somaxconn参数为128,执行sysctl -w net.core.somaxconn=1024 或者其它更大的值,并重启后端服务器上的应用。

CASE3 后端服务器连接过多

由于架构设计的原因,使用7层负载均衡时,用户长连接经过Tengine后变成短连接,可能造成后端服务器连接过多,从而表现为压测性能上不去。

CASE4 后端服务器依赖的应用成为瓶颈

请求经过负载均衡达到后端服务器后,后端服务器本身负载都正常,但由于所有的后端服务器上的应用又依赖其它应用,比如数据库,数据库成为瓶颈,也会引起。

CASE5 后端Server的健康检查状态异常

尤其在压测的时候容易忽略后端Server的健康检查状态,如果有后端Server健康检查失败或者健康检查状态经常跳跃(好到坏,又从坏到好,反复变化)也会导致性能跑不上去。

压测时的建议

基于以上分析,压测时建议关注如下点。

注意事项

压测负载均衡转发能力建议使用短链接。

一般来说压测除了验证会话保持,均衡性等功能外,主要想验证的是负载均衡的转发能力,因此使用短链接比较合适,用于测试负载均衡和后端服务器处理能力。但使用短连接测试时注意上述的case1 的客户端端口不足问题。

压测负载均衡吞吐量建议使用长连接,用于测试带宽上限或特殊业务。

压测工具的超时时间建议调小(5秒)。超时时间太大的话,测试结果会体现在平均RT加长,不利于判断压测水位是否已到达。超时时间调小,测试结果会体现在成功率上,便于快速判断压测水位。

后端服务器提供一个静态网页用于压测,以避免应用逻辑带来的损耗(I/O, DB等)。

压测工具建议

不建议使用apache ab。

ab在大并发场景下存在问题,会存在3s,6s,9s阶梯式停顿的现象。ab会通过判断content length来确定请求成败,在负载均衡挂载多台后端服务器的时候,返回的content length不一致,会干扰到测试结果。

建议使用阿里云PTS (https://pts.aliyun.com)。

可以选择多个Client作为压测源,测试结果清晰,并且可以通过配置监控,获取压测时后端服务器的性能数据。

压测建议的配置要求

以下设置仅用于压测负载均衡能力,并不表示用户生产环境也需要如此设置。

监听不开启会话保持功能,否则压力会集中在个别的后端服务器。

监听关闭健康检查功能,减少健康检查请求对后端服务器的访问请求。

用多个client(>5)进行压测,源IP分散,能够更好的模拟线上实际情况。

使用PTS简单压测示例

购买两台ECS用作后端服务器,购买一个负载均衡实例用于提供负载均衡服务,并且绑定之前购买的ECS作为后端服务器,分别创建TCP、HTTP监听各一个,后端端口80。ECS服务器信息可以为:(CPU 1核,内存 512M, CentOS 6.3 64位)。

安装apache web server,用于提供web服务:

yum install -y httpd

初始化默认首页index.html:

echo “testvm” > /var/www/html/index.html

启动http服务:

service httpd start

访问本机80端口,确认web服务可用:

curl localhost

在PTS中创建测试脚本,开始压测。

注意关闭长连接和设置超时时间。

超时时间5秒:

PTS.HttpUtilities.setTimeout(5000)

关闭长连接:

PTS.HttpUtilities.setKeepAlive(False)