非常抱歉, 今天上午的博客站点故障给大家带来了很大的麻烦, 请大家谅解. 这次故障是我们发布 .NET Core 版博客站点引起的, 虽然我们进行了充分的准备, 但还是低估了高并发下的复杂问题.
以下是故障背景与大致经过:
在这个炎炎夏日, 我们正热火朝天地忙着整个 .NET Core 迁移工程的收官 -- 发布 .NET Core 版博客站点与博客后台. 我们的其他系统都早已迁移至 .NET Core 并已在线上工作一番时日, 只剩下最难啃的硬骨头 -- 博客系统, 到这个月这根钢铁般坚硬的硬骨头也被啃得差不多了, 它的发布上线将为我们整个 .NET Core 迁移工程画上完美的句号, 并顺带以此里程碑迎接 .NET Core 3.0 正式版的发布.
所以, 发布 .NET Core 版博客站点与博客后台成为我们 8 月份最重要的工作..NET Core 版博客站点 7 月份就已经完成开发, 这段时间一边进行更进一步的内测, 一边进行灰度发布, 接入一些生产流量以发现我们测试中未能发现的问题并进行修复, 在上个周末接入更多生产流量进行测试与修复后, 我们已经很有信心, 评估后认为已具备正式发布条件, 除了我们无法在测试环境中模拟的博客系统所处的复杂高并发场景.
于是一边带着信心, 一边带着对高并发问题的担心, 我们决定在今天一大早进行发布.
发布时的部署场景是这样的, 博客系统基于 .NET Core 3.0 Preview 7 (EF Core 用的还是 3.0 Preview 5),7 台阿里云 CentOS 服务器组建了 docker swarm 集群, 6 台 4 核 8G 服务器作为 worker 节点跑博客站点的应用容器, 1 台 2 核 4G 的服务器作为 manager 节点 (不部署任何容器), 每个 worker 节点都部署 1 个 nginx 与 .net core 博客应用容器, 所有请求都由阿里云均衡转发到 nginx 容器, 再由 nginx 容器转发给 .net core 应用容器, nginx 通过端口映射的方式监听 worker 节点服务器的 80 端口.
这样的部署环境也是我们经过长期验证的, 唯一没有经过验证的就是博客系统这么高的并发.
顶着 2 个高并发问题的风险 (docker swarm 与 .net core ), 我们在今天早上 5:30 左右进行了发布.
开始访问量小, 并发低, 没出现问题, 但到 8:30 左右出现问题了, 打开很多博客页面要 1 秒多 (正常情况是几十毫秒), 而在容器内用 curl 命令请求都不到 10 毫秒.
- $ docker exec -t $(docker ps -f name=blog_web -q) curl -H 'X-Forwarded-Proto:https' -w %{
- time_total
- } -o /dev/null -s localhost
- 0.002876
怀疑是 nginx 的问题, 准备重新创建一个 docker 集群, 不用 nginx 直接用 kestrel 监听 80 端口.
后来同事指出, 不是 nginx 的问题, 是 docker swarm 端口映射在高并发下的性能问题, 只有将端口映射改为 host 网络模式才能解决这个问题.
9:30 左右, 随着并发越来越高, nginx 容器开始报 500 错误, 开始以为是集群中的服务器负载过高, 于是向 docker swarm 集群中添加服务器, 但于事无补, 500 错误越来越多.
出现 500 错误时, 有时刷新一次就会好, 有时要刷新好几次, 怀疑是集群中某些服务器不稳定, 于是一台一台登录集群中的服务器进入容器用 curl 命令进行测试, 除了 1 台服务器不稳定, 其他服务器 curl 命令测试时响应速度都正常, 将那台不太稳定的服务器下线, 问题依旧, 随着并发量继续增大, 500 错误也继续增多.
进一步分析后, 怀疑 500 错误是因为高并发下 nginx 容器与 .net core 应用容器之间的网络通信出现问题, 于是 10:30 左右决定放弃这次发布, 回退至跑在 Windows 上的 .net framework 版本博客站点, 恢复了正常.
来源: https://www.cnblogs.com/cmt/p/11302666.html