关于云原生:我们被一个-kong-的性能-bug-折腾了一个通宵

7次阅读

共计 3381 个字符,预计需要花费 9 分钟才能阅读完成。

故事背景

在 Erda 的技术架构中,咱们应用了 kong 作为 API 网关的技术选型。因其具备高并发低延时的个性,同时联合了 Kubernetes Ingress Controller,基于云原生的申明式配置形式,可能实现丰盛的 API 策略。

在咱们最早交付的集群中,kong 还是较为晚期的 0.14 版本,随着业务层面对平安的要求日益趋增,咱们须要基于 kong 实现平安插件,帮忙零碎可能具备更好的平安能力。因为较为晚期的 0.14 版本不能应用 go-pluginserver 来扩大 kong 的插件机制,咱们不得不在古老的集群中将 kong 降级为绝对较新的 2.2.0 版本。

降级过程就不在此赘述了,根本就是照着官网文档一步步顺利的降级下来,然而在降级下来之后的几天里,咱们的 SRE 团队收到了十分密集的征询甚至是声讨,部署在该集群上的业务 间歇性的无法访问,提早十分高

一系列失败的尝试

参数调优

最开始为了疾速修复这个问题,咱们对 kong 的 NGINX_WORKER_PROCESSESMEM_CACHE_SIZEDB_UPDATE_FREQUENCYWORKER_STATE_UPDATE_FREQUENCY 参数以及 postgres 的 work_memshare_buffers 都进行了适当的调优。

然而,没有任何成果 😓。

清理数据

因为这个集群的历史起因,会频繁的注册或者删除 api 数据,因而集群中累计了大概 5 万多条 route 或者 service 数据。

咱们狐疑是数据里量大导致的性能降落,于是联合 erda 中的数据对 kong 中的历史数据进行删除,在删除的过程中呈现的删除较慢并且同时 kong 的性能急剧下降的景象。

重复测试了几次后咱们确定了「只有调用 admin 的接口导致 kong 性能降落」这一论断,跟社区的这个问题十分类似,链接如下:

https://github.com/Kong/kong/…

kong 实例的读写拆散

确定了是 admin 接口的起因后,咱们决定将 admin 跟业务的 kong 实例离开,心愿 admin 的调用不会影响到业务的失常流量拜访,期待达到 kong 的 admin 接口慢就慢吧,然而不要影响业务的拜访性能。

然而,没有任何成果😫。

postgres 迁徙 RDS

kong 层面的致力无果之后,咱们在测试过程中同时察看到了当调用 admin 接口试,postgres 的过程也增多了很多,CPU 使用率也涨了起来,也是决定将 pg 迁徙到 更为业余的 RDS 中。

还是,没有任何成果😭。

回滚

最终咱们还是回滚到了 0.14 版本,谋求临时“心灵的平静”。

至此,线上的尝试根本搞一段落,也大抵摸清了问题复现的条件,于是咱们决定在线下结构一个环境来持续找出问题的起因。

问题的复现之路

咱们将出问题的 kong 的 postgres 数据导一份到开发环境中,模仿「调用 admin 接口是性能急剧下降」的状况,并寻找解决之道。

导入数据

咱们将有问题的集群中的 postgre 的数据备份之后而后在一个新的集群中导入:

psql -h 127.0.0.1 -U kong < kong.sql

并且开启 kong 的 prometheus 插件,方便使用 grafana 来查看性能图标:

curl -X POST http://10.97.4.116:8001/plugins --data "name=prometheus"

景象一

调用 admin 服务的 / 同样的慢,跟线上的景象吻合,当数据量大的时候调用 admin 的 / 目录须要消耗更多的工夫。

curl http://10.97.4.116:8001

景象二

而后咱们来模仿在线上遇到的调用 admin 接口后业务拜访性能变差的景象,先调用 admin 接口创立个业务的 api,以供测试,咱们创立了一个 service 以及一个 routes:

curl -i -X POST http://10.97.4.116:8001/services/ -d 'name=baidu2'  -d 'url=http://www.baidu.com'

curl -i -X POST http://10.97.4.116:8001/services/baidu2/routes \
-d "name=test2" \
     -d "paths[1]=/baidu2"

前面能够应用 curl http://10.97.4.116:8000/baidu2 来模仿业务接口进行测试。

筹备 admin 接口的测试脚本,创立并删除一个 service/route,两头交叉一个 service list。

#!/bin/bash

curl -i -X POST http://10.97.4.116:8001/services/ -d 'name=baidu'  -d 'url=http://www.baidu.com'

curl -i -X POST http://10.97.4.116:8001/services/baidu/routes \
     -d "name=test" \
     -d "paths[1]=/baidu" 

curl -s http://10.97.4.116:8001/services

curl -i -X DELETE      http://10.97.4.116:8001/services/baidu/routes/test

而后继续调用该脚本:

for i in `seq 1 100`; do sh 1.sh ; done

在继续调用该脚本的过程中去拜访一个业务的接口,会发现十分慢,跟线上的景象齐全吻合。

curl  http://10.97.4.116:8000/baidu2

PS:精简脚本,后只触发一条写入,或者删除也会触发该景象

随同景象

  • kong 实例的 cpu 跟 mem 都继续上涨,且当 admin 接口调用完结后此景象仍然没有完结。mem 上涨到肯定水平会到时 nginx worker 过程 oom 掉,而后重启,这个兴许是拜访慢的起因;
  • 咱们设置了 KONG_NGINX_WORKER_PROCESSES 为 4,并且为 pod 的内存为 4G 的时候,pod 的整体内存会稳固在 2.3G,然而 调用 admin 接口试,pod 的内存就会始终上涨至超过 4G,触发 worker 的 OOM,于是我将 pod 的内存调整到了 8G。再次调用 admin 接口,发现 pod 的内存仍然始终上涨,只是上涨到了 4.11 G 就完结了,这仿佛意味着咱们是要设置 pod 的内存为 KONG_NGINX_WORKER_PROCESSES 两倍,这个问题就解决了(然而还有个重要的问题是为什么调用一次 admin 接口,会导致内存涨了那么多);
  • 另外,当我继续调用 admin 接口的时候,最终的内存会持续增长并且稳固到 6.9G。

这个时候咱们将问题形象一下

调用「kong admin 接口」导致内存始终上涨,进而触发 oom 导致 worker 被 kill 掉,最终导致业务拜访慢。

持续考察内存是被什么占用了

我应用 pmap -x [pid] 前后两次查看了 worker 过程的内存散布,变动的是第二张如中框起来来的局部,从地址上看整块内存都被换过了,然而将内存数据导出并且字符串化之后,没有什么无效的信息可供进一步排查。

论断

  • 该问题跟 kong 的降级(0.14 –> 2.2.0)没有关系,间接应用 2.2.0 版本也会有这个问题;
  • kong 每隔 worker_state_update_frequency 工夫后会在内存中重建 router,一旦开始重建就会导致 内存上涨,看了下代码问题出在了 Router.new 的办法这里,会申请 lrucache 然而应用后没有 flush_all,依据最新的 2.8.1 版本的 lrucache 进行了开释问题仍然存在;
  • 也就是 kong 的 Router.new 办法里的其余逻辑到时的内存上涨;
  • 这也就表明这个问题是 kong 存在的一个性能 bug,及时在最新的版本中仍然存在,当 route 跟 service 达到某个量级的时候会呈现调用 admin 接口,导致 kong 的 worker 内存迅速上涨,使得 oom 进而引发业务拜访性能变差的景象,长期的解决办法能够是缩小 NGINX_WORKER_PROCESSES 的数量并且减少 kong pod 的内存量,保障调用 admin 接口后须要的内存足够应用不触发 oom,能力保障业务的失常应用。

最初,咱们会在 https://github.com/Kong/kong/… 这个 issue 中将该景象补充进去,欢送大家继续关注,一起探讨~


更多技术干货请关注【尔达 Erda】公众号,与泛滥开源爱好者独特成长~

正文完
 0