新年第一天,3000台Apache服务器宕机

【编者按】新婚现场给服务器扩容 , 下班路上修Bug……对于程序员来说 , 这样的日常并不陌生 。 在新年第一天 , 国外一名叫Ali Josie 的软件工程师、信息安全爱好者就经历了找Bug、复现、修复这样的事情 , 并且还发表了一篇《This Is Why Our 3000 Apache Servers Went Down On The First Day of 2022》 , 具体是怎么一回事呢?
作者 |Ali Josie 译者| 弯月
出品 | CSDN(ID:CSDNnews)
新年第一天 , 又恰逢周六 , 早上醒来却看到一堆整个基础设施挂掉的警报!我的一位同事就遭遇了这样的真实 , 他当时的心情可想而知 。
大清早
首先 , 最重要的是恢复服务 , 把服务宕机的影响降到最低 , 我们重启了所有Apache服务器 , 还好没有任何问题 。 接下来就要找出宕机的原因了 。 为什么所有服务器都在新年第一天宕机?这肯定不是偶然吧?
我们看到每台服务器上都记录了如下日志:
AH00171: Graceful restart requested, doing restart libgomp: could not create thread pool destructor.libgomp是什么?我们先上网查了一下这个错误 。 ServerFault上有人问过这个问题 , 但没人回答 , 至少没有我们能用的东西 。 不过这个问题有点奇怪 , 因为提问者说他的服务器每隔24~36小时就会发生一次 。
思考
回到错误本身 。我们每天早上都会做一次日志轮转 , 这样每天都用新的日志 。 因此要重启服务器 。 似乎Apache已经成功重启 , 但由于libgomp错误又宕机了 。
在网上搜索到的大量结果中寻找答案无异于大海捞针 , 于是我们开始阅读libgomp的源代码 , 看看究竟发生了什么 。 首先 , libgomp是什么?根据其主页的描述:
  • “GOMP项目是C、C++和Fortran编译器OpenMP的一个实现……GOMP能简化所有GNU系统上的并行编程 。 ”
所以它是OpenMP的实现 。 它怎么会出问题?
搜索了一下源代码 ,我们发现错误消息的唯一出处是这里:
所以显然 , 它在试图创建一个线程键 , 但出错了 。 检查pthread_key_create的手册:
  • “pthread_key_create会创建用于线程专有的数据键 , 可在进程的所有线程中使用 。 pthread_key_create提供的键值是不透明的对象 , 用于定位线程专有的数据 。 虽然不同线程可以使用相同的键名称 , 通过pthread_setspecific绑定到键的值是按照线程维护的 , 在线程的整个生命周期都有效 。 ”
有意思!那返回值是什么?
“pthread_key_create函数会在下述情况失败:
  • 系统资源不足 , 无法创建另一个线程特定数据键 , 或每个进程的键总数达到了 PTHREAD_KEYS_MAX 上限 。
  • 内存不足 , 无法创建键 。 ”
然后检查了代码 , 看看发生了什么 , 以及PTHREAD_KEYS_MAX最大值是多少:
新年第一天,3000台Apache服务器宕机
文章图片

所以说 , key只是一个0~1024之间(不含1024)的数字 , 赋给pthread_key_create的调用者 。 这些键由一个简单的CAS负责赋值 , 因此肯定有某个地方释放这些键 。 似乎我们找到了问题 。 我们只需要增大PTHREAD_KEYS_MAX 。 但是 , 这个值是常量 。 我们甚至找到了一个帖子 , 要求增加PTHREAD_KEYS_MAX:
  • “pthread_key_create会拒绝超过 PTHREAD_KEYS_MAX pthread_key_t的创建请求 。 我遇到的问题是在NetBSD上Apache无法与多种模块一起工作 , 因为这个值太低了 。 时间长了 , 服务器就会陷入无法提供服务的状态 。 ”
这篇帖子描述的问题域我们相似 , 因此我们的假设可能是正确的 。 但是我们依然没办法增大这个值 。

特别声明:本站内容均来自网友提供或互联网,仅供参考,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。