[alibaba/tengine]upstream导致cpu占用异常

2024-02-21 546 views
9

最近发现当upstream后端服务故障后,nginx的cpu占用就会飙升,后端服务故障的数量越多,cpu飙升就会越高。当后端有超过接近10台服务故障时,8个进程的nginx,有之前平均每个进程5-10%的cpu占用,直接飙升到99-100%,当注释掉故障后端服务后,cpu占用马上就正常了。 配置大致如下:

upstream https_backend {
        consistent_hash $real_uri;
        server 172.29.184.4:40443 weight=100;
        server 172.29.184.5:40443 weight=100;
        ...serverlist...

        check interval=3000 rise=2 fall=5 timeout=1000 type=http;
        check_keepalive_requests 100;
        check_http_send "HEAD /xxxx.jpg HTTP/1.1\r\nConnection: keep-alive\r\n\r\n";
        check_http_expect_alive http_2xx http_3xx http_4xx;
}

回答

7

@zczww
1、请提供使用的Tengine版本信息,以及复现方法及配置。 2、观察Tengine的错误日志是否有什么异常信息。 3、当CPU升高后,请执行 sudo pstatck $pid 其中 $pid表示对应CPU升高进程的进程号。

9

1、版本号:2.2.2 2、复现方法:按照上一个帖子的配置,配置几个正常的backend,再配置10个不网络上不可达的backend,然后有一定量请求即可复现 3、错误日志看起来正常,截取一段如下: 2019/07/04 17:31:13 [error] 7726#0: send() failed (111: Connection refused) 2019/07/04 17:31:13 [error] 7733#0: send() failed (111: Connection refused) 2019/07/04 17:31:13 [error] 7733#0: send() failed (113: No route to host) 2019/07/04 17:31:13 [error] 7729#0: send() failed (111: Connection refused) 2019/07/04 17:31:14 [error] 7718#0: send() failed (113: No route to host) 2019/07/04 17:31:14 [error] 7718#0: send() failed (113: No route to host) 2019/07/04 17:31:14 [error] 7730#0: send() failed (111: Connection refused) 2019/07/04 17:31:14 [error] 7730#0: send() failed (111: Connection refused) 2019/07/04 17:31:14 [error] 7731#0: send() failed (111: Connection refused) 2019/07/04 17:31:14 [error] 7732#0: send() failed (111: Connection refused) 2019/07/04 17:31:15 [error] 7721#0: check time out with peer: 172.29.184.72:40080 2019/07/04 17:31:15 [error] 7721#0: check time out with peer: 172.29.184.78:40443 2019/07/04 17:31:15 [error] 7721#0: check time out with peer: 172.29.184.78:40080 2019/07/04 17:31:15 [error] 7719#0: check time out with peer: 172.29.184.72:40443 2019/07/04 17:31:16 [error] 7718#0: send() failed (113: No route to host) 2019/07/04 17:31:16 [error] 7726#0: send() failed (111: Connection refused) 2019/07/04 17:31:16 [error] 7733#0: send() failed (111: Connection refused) 2019/07/04 17:31:16 [error] 7733#0: send() failed (113: No route to host) 2019/07/04 17:31:16 [error] 7729#0: send() failed (111: Connection refused) 2019/07/04 17:31:16 [error] 7721#0: check time out with peer: 172.29.184.94:40443 2019/07/04 17:31:16 [error] 7719#0: check time out with peer: 172.29.184.67:40443 2019/07/04 17:31:17 [error] 7718#0: send() failed (113: No route to host) 2019/07/04 17:31:17 [error] 7718#0: send() failed (113: No route to host)

4、从pstack看,大部分集中在ngx_http_upstream_get_chash_peer,以及__epoll_wait_nocancel两个函数上。

7

目前分析到的情况是,在ngx_http_upstream_consistent_hash_module.c的ngx_http_upstream_get_chash_peer函数中,这个while(q != ngx_queue_sentinel(&ucscf->down_servers))循环语句需要执行好几万次才能出来。

5

@zczww 是的,这个是一个特定场景下的已知问题,后面可以优化一下,当前你可以通过把server的权重改下来缓解这个问题。

详细原因

由于consistent hash算法为了保证机器列表足够的散列在环中,引入了虚拟节点的概念。即每个RealServer对会对应160 * Weight个虚拟节点,在你所给的列子里面,其upstream配置中server的权重都是100,如果有2个RealServer,则对应32000个虚拟节点。

另外,如果检测到某台机器不可用后,则会将该机器对应的所有虚拟节点全部加载到down_servers队列、并从线段树中摘除,从而避免有问题的机器被再次选择。在后续执行的过程中,会循环检测down_servers里面的机器状态是否恢复,所以导致循环检测集中。

7

感谢解答,因为我们一致性hash会影响后端存储,修改weight会导致大部署数据失效。想再请教一下,我这里可否做一个简单的处理,不在每次请求处理的时候都去检测,而是每N次请求才检测一次down_servers是否恢复,来缓解这个问题?

7

嗯,权重的值最好是按照比例达到互质的状态。关于N次后再进行一次检测的方案看起来可短暂解决问题、但可也能会恶化问题。其实问题的根本原因是由于堆积的不可用机器太多了,而集中检测导致CPU飙高。所以可以把检测的逻辑打散就好了,比如通过定时器的方式分别来检测每个机器的状态。当然也有更简单方法,如当机器不可用的时候放入“小黑屋” ,N 秒后直接恢复到可用也是可以解决的。

9

这个tengine有计划优化一个这个功能么?