小Cの已经记不起来的博客

性能优化手记:蓝绿部署 排查全过程

事情是这样的

上个月给我的一个服务上了套蓝绿部署,两套环境,蓝的跑线上流量,绿的发新版本,Nginx 把 upstream 一切就完事,出问题还能秒回滚,听着挺美的。

结果第一次真实切流就被上了一课:切完不到一分钟,告警群直接炸了,接口 P99 从平时的一百多 ms 飙到快两秒。QPS 倒是没掉,就是慢。赶紧把 upstream 切回蓝环境,流量立刻恢复。这就很迷惑了,绿环境这版就加了个导出功能,逻辑上不该慢这么多啊。

排查过程

先怀疑机器。上绿环境看了一眼,CPU、内存、磁盘 IO 都正常,和蓝环境基本一个水平。然后怀疑网络,两套环境在同一个内网,ping 了一下 0.2ms,也排除。

接着看 Nginx,给 log_format 加了个 $upstream_response_time:

log_format main '$remote_addr - $upstream_addr [$time_local] '
                '$request_time $upstream_response_time $status';

压了一波流量,发现 upstream 响应时间确实很慢,说明锅不在 Nginx,是后端服务本身慢。

然后去翻应用这边的慢请求日志,发现慢的基本都集中在同一个接口——查列表数据的那个。这个接口前面挡了一层 Caffeine 本地缓存,命中就不会去碰数据库。对着监控又看了一眼,切流那一分钟,数据库的 QPS 直接翻了好几倍,顺手 dump 了一下线程,好家伙,几十个线程全卡在 HikariPool.getConnection 上。

到这儿基本就清楚了:绿环境是刚启动的,本地缓存是空的。原本在蓝环境命中缓存的请求,切过去之后全部穿透到数据库了,连接池又没提前建好连接,两边一叠加,就变成了小型雪崩...

解决办法

原因找到了,剩下的就是让绿环境在接流量之前“热”起来。踩的坑主要有两个,一个一个说。

数据库连接池是冷的。 HikariCP 默认懒加载,第一个请求来了才去建连接,切流瞬间几十个请求一起建连,又慢又容易把池子打满。改下配置,让它在启动阶段就把连接建好:

spring:
  datasource:
    hikari:
      minimum-idle: 20
      # 启动时就初始化连接,建不起来直接报错,别等第一个请求踩坑
      initialization-fail-timeout: 30000

本地缓存是冷的。 这个没有通用解法,我的做法是加了个预热入口,服务启动完成后自己把热点数据拉一遍:

@Component
public class CacheWarmUp implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) {
        // 只提前拉热点页的数据,全量拉一遍也太久了
        hotQueryService.warmTopPages();
    }
}

注意预热别贪多,我只预热了访问最集中的那部分数据,全量拉一遍又慢又占内存,没必要。

切流方式也改了。 之前是一次性 100% 切,现在改成用 weight 灰度放量,先给绿环境一点流量,观察没问题再放大:

upstream backend {
    server 10.0.0.11:8080 weight=9;  # 蓝
    server 10.0.0.12:8080 weight=1;  # 绿,先放10%
}

放到 50% 再全量,每一步观察个几分钟。虽然比一键切换麻烦了点,但心里踏实多了。

验证

改完之后又完整走了一遍发布流程:绿环境启动、预热、挂到 upstream、逐步放量。这次盯着监控看,P99 只在放量的前几秒有一点波动,几秒就回去了,数据库 QPS 也稳稳的。再用 wrk 压一轮:

wrk -t4 -c100 -d30s http://10.0.0.12:8080/api/list

不出问题的话就没有问题了,各项数据和老的蓝环境基本持平,这波算是过去了。

写在最后

回头看,蓝绿部署这玩意儿本身没什么问题,问题出在“新环境不是热的”这件事上。只要你的服务有本地缓存、连接池、JIT 这种需要热身的东西,切流之前就得想清楚怎么预热,不然新环境一接真实流量就是一场小型的缓存雪崩。

另外这次能快速止损,靠的还是蓝绿架构本身——切回蓝环境就一条配置的事。所以发布流程和预热脚本得配套着来,一个保下限,一个保体验。没准儿哪天我又会因为别的原因被上一课,到时候再记一篇吧。

评论

还没有评论。

发表评论

提交后评论将经过自动审核,审核通过后公开展示。

未在播放