我们被一个 kong 的性能 bug 折腾了一个通宵

简介: 这一晚我们到底经历了什么

故事背景

在 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/issues/7543

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

1.png

现象二

然后我们来模拟在线上遇到的调用 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

2.png

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 进程的内存分布,变化的是第二张如中框起来来的部分,从地址上看整块内存都被换过了,但是将内存数据导出并且字符串化之后,没有什么有效的信息可供进一步排查。

3.png
4.png

结论

  • 该问题跟 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 方法里的其他逻辑到时的内存上涨;

5.png

  • 这也就表明这个问题是 kong 存在的一个性能 bug,及时在最新的版本中依然存在,当 route 跟 service 达到某个量级的时候会出现调用 admin 接口,导致 kong 的 worker 内存迅速上涨,使得 oom 进而引发业务访问性能变差的现象,临时的解决办法可以是减少 NGINX_WORKER_PROCESSES 的数量并且增加 kong pod 的内存量,保证调用 admin 接口后需要的内存足够使用不触发 oom,才能保证业务的正常使用。

最后,我们会在 https://github.com/Kong/kong/issues/7543 这个 issue 中将该现象补充进去,欢迎大家持续关注,一起讨论~


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

目录
相关文章
|
机器学习/深度学习 测试技术 Ruby
YOLOv8改进 | 主干篇 | 反向残差块网络EMO一种轻量级的CNN架构(附完整代码 + 修改教程)
YOLOv8改进 | 主干篇 | 反向残差块网络EMO一种轻量级的CNN架构(附完整代码 + 修改教程)
425 0
|
8月前
|
人工智能 Kubernetes 安全
Nacos 3.0 正式发布:MCP Registry、安全零信任、链接更多生态
Nacos 3.0正式发布,作为云原生时代的基础设施级产品,不仅提升了技术能力,还以更高效、安全的方式帮助用户构建云原生AI应用架构。此次更新重点包括:升级MCP Registry,支持多种类型注册与动态管理;增强安全架构,默认开启鉴权并支持零信任方案;扩展多语言生态,覆盖Python、GoLang、Rust等主流开发语言;提供Nacos-MCP-Router实现MCP动态发现与自动安装。此外,3.0版本改进了安全部署架构,加强K8S生态同步,并推出实验性功能如分布式锁和服务配置模糊订阅。Nacos致力于简化微服务管理和AI应用开发,欢迎加入社区共建!
1328 43
|
9月前
|
存储 算法 UED
鸿蒙特效教程07-九宫格幸运抽奖
在移动应用中,抽奖功能是一种常见且受欢迎的交互方式,能够有效提升用户粘性。本教程将带领大家从零开始,逐步实现一个九宫格抽奖效果,适合HarmonyOS开发的初学者阅读。
302 2
鸿蒙特效教程07-九宫格幸运抽奖
|
10月前
|
关系型数据库 分布式数据库 PolarDB
通过 PolarDB for PostgreSQL 实现一体化的 HTAP 能力
阿里云 PolarDB for PostgreSQL作为一款领先的云原生关系型数据库,利用向量化引擎+列存索引等技术实现了 OLTP 和 OLAP 的一体化。本方案为您展示如何通过 PolarDB for PostgreSQL 来实现一体化的 HTAP 能力。
通过 PolarDB for PostgreSQL 实现一体化的 HTAP 能力
|
人工智能 搜索推荐 程序员
AI 搜索引擎工具集合
AI 搜索引擎工具集合
1267 1
AI 搜索引擎工具集合
|
数据可视化 Docker 容器
一文教会你如何通过Docker安装elasticsearch和kibana 【详细过程+图解】
这篇文章提供了通过Docker安装Elasticsearch和Kibana的详细过程和图解,包括下载镜像、创建和启动容器、处理可能遇到的启动失败情况(如权限不足和配置文件错误)、测试Elasticsearch和Kibana的连接,以及解决空间不足的问题。文章还特别指出了配置文件中空格的重要性以及环境变量中字母大小写的问题。
一文教会你如何通过Docker安装elasticsearch和kibana 【详细过程+图解】
|
存储 Kubernetes 安全
在K8S中,etcdctl如何使用?
在K8S中,etcdctl如何使用?
|
机器学习/深度学习 人工智能 算法
人工智能(AI)中的数学基础
人工智能(AI)是一个多学科交叉的领域,它涉及到计算机科学、数学、逻辑学、心理学和工程学等多个学科。数学是人工智能发展的重要基础之一,为AI提供了理论支持和工具。
545 1
|
运维 监控 Unix
【专栏】Linux系统管理员面试中的常见问题,涵盖基础知识、系统管理和故障排查。
【4月更文挑战第28天】本文概述了Linux系统管理员面试中的常见问题,涵盖基础知识、系统管理和故障排查。面试官会询问Linux与Unix的关系、内核功能、文件系统类型、权限位、用户组概念、链接类型、输入输出、进程和环境变量等。此外,还会涉及软件安装、服务配置、日志监控、网络管理、防火墙配置、LVM、RAID、用户管理、备份策略等实践技能。故障排查和脚本编程能力也是重点,包括系统故障分析、脚本在系统管理中的应用、磁盘空间管理、服务故障诊断及性能优化。准备面试的求职者应注重理论与实践经验的结合,持续学习以提升专业能力。
229 0

热门文章

最新文章