一次非典型性 Redis 阻塞总结

南方逐渐进入一年中最好的时节,用户也开始骚动起来。看了眼数据,活跃用户已经double很远,马上triple了。

一日睡眼惺忪的清晨,正看着数据默默yy时候,线上开始告警…… MMP,用户早上骚动的增长比想象好快呢。同事第一时间打开立体监控瞥了一眼,结合服务的错误日志,很快把问题锁定到了一个Redis实例(事实上,自从立体监控上线以后,基本上处理流程从以前的 < 80%时间定位问题 + 20%解决问题 > 变成了 < 少量时间确认问题 + 解决问题 >)。团队处理效率还是挺快的,原因定位到AOF持久化:

这是当时的Redis配置:

127.0.0.1:6379> config get *append*
1) "no-appendfsync-on-rewrite"
2) "no"
3) "appendonly"
4) "yes"
5) "appendfsync"
6) "everysec"

从配置看,原因理论上就很清楚了:我们的这个Redis示例使用AOF进行持久化(appendonly),appendfsync策略采用的是everysec刷盘。但是AOF随着时间推移,文件会越来越大,因此,Redis还有一个rewrite策略,实现AOF文件的减肥,但是结果的幂等的。我们no-appendfsync-on-rewrite的策略是 no. 这就会导致在进行rewrite操作时,appendfsync会被阻塞。如果当前AOF文件很大,那么相应的rewrite时间会变长,appendfsync被阻塞的时间也会更长。

这不是什么新问题,很多开启AOF的业务场景都会遇到这个问题。解决的办法有这么几个:

  1. no-appendfsync-on-rewrite设置为yes. 这样可以避免与appendfsync争用文件句柄,但是在rewrite期间的AOF有丢失的风险。
  2. 给当前Redis实例添加slave节点,当前节点设置为master, 然后master节点关闭AOF,slave节点开启AOF。这样的方式的风险是如果master挂掉,尚没有同步到salve的数据会丢失。

我们采取了折中的方式:在master节点设置将no-appendfsync-on-rewrite设置为yes,同时添加slave节点。

理论上,问题应该解决了吧?啊蛤,的确是理论上。

修改后第一天,问题又出现了。惊不惊喜,意不意外?

于是,小伙伴又重新复习了一下当时出问题时候的Redis日志:

有两个点比较可以:

  1. 前几条AOF日志告警日志发生在晚上3~5点之间,而那个时候,我们整个系统负载是非常低的。
  2. 清晨的告警日志不是某一个Redis实例告警,而是该机器上的所有Redis实例都在告警。

在这种百思不得骑姐的情况下,结合历史上被坑的经验,我们99%断定是我们使用的云主机存在问题。

这个问题有可能是宿主机超售太多导致单个租户实际能使用到的云盘IO比标称值低,也有可能是租户隔离做得不好,导致坏邻居过度占用IO影响其他租户。

这个很好理解:我们使用的是阿里云的云SSD,而阿里云目前的架构还没有做到计算和存储分离,即计算和存储的网络IO是共享的。

当然目前这个问题还没有实锤,我们也还在跟阿里云积极沟通解决。同时为了避免给自己惹麻烦,我还是留了1%的其他可能性😅

祝大家周末愉快!

参考资料

Redis相关—Redis持久化

Ubuntu 14.04开启nginx http2支持的方法

再过不到两个月,Ubuntu18.04就要出来了,但是手上还有一些老机器还停留在14.04🤔:

没有足够的时间和动力来升级这几台老机器,但是一些常用的软件准备顺手升级一下。最基本的自然是升级nginx支持http2. http2的优势可以参见《当我们在谈论HTTP队头阻塞时,我们在谈论什么?》以及《低延迟与用户体验杂谈》

Ubuntu 14.04开启nginx http2支持的前置条件

  1. nginx >=1.9.5
  2. openSSL >= 1.0.2

第一个条件大家一般都不会漏掉。但是第二个条件一般是http2无法成功开启时才发现。这是因为随14.04一起分发的openSSL版本是1.0.1f. 那么要开启http2支持,有两种方式:

  1. 使用他人编译好的ngingx with http2 support package安装;
  2. 升级本地openSSL版本,然后从源码编译安装。

而随Ubuntu 18.04一起分发的openSSL版本为1.1.0g, 因此不存在这个问题。

使用packaege安装(懒人专用)

这里需要注意一下,很多为提供14.04提供nginx安装包的源虽然可以让你安装更高版本的nginx,但是大多是使用openSSL 1.0.1编译的,因此无法支持http2, 比如jessis, nginx mainline为14.04提供的安装包是使用1.0.1编译的,因此不支持http2的。这里我们使用ondrej提供的源。

  • 卸载已经安装的nginx(会保留配置文件,take is easy):

  • 添加ondrej nginx安装源:

如果出现如下错误:

应该是终端编码问题,尝试使用LC_ALL=C.UTF-8 add-apt-repository ppa:ondrej/nginx解决。

  • 更新源,并安装:

从源码安装

修改nginx配置开启http2

设置nginx支持http2最关键是在https端口添加http2指令:

一个网站的参考配置模板如下:

小结

nginx开启http2的支持不要忘记了对openSSL最低版本的要求。其实http2已经不再时髦啦,http2+TLS1.3才是未来,可以参见《低延迟与用户体验杂谈》。后面会讲讲docker+nginx开启http2和TLS1.3的方式,这种方式即可以方便的尝试各个nginx版本,同时也不会破坏本地的nginx环境。