解决 Redis 110 Connection timed out 问题记录

2017-06-29 00:44:00

背景

之前在某公司的时候,用 php-redis 扩展时,服务器会报错 110,"Connection timed out" after 0 ms,不可思议吧,0ms超时?当时一直以为是扩展层面的 bug。

现在直接用的 predis,同样的,总是能遇到 Connection timed out 这个报错。这次总不能又是 php 代码有问题了吧 :)

调试

调试代码的时候确认错误不是扩展返回的,110 代表了不是连接前的错误,而是 redis 服务器直接返回的错误。

这样问题就很明确了,直接从 redis 服务器入手。

1,首先 redis 是同步IO的,实例是单线程的,因此任何慢操作都可能会阻塞其它请求,而导致超时,可以参考的方向有 特大key导致的超时,rdb时同步写导致的超时(设置 no-appendfsync-on-rewrite yes 来解决)等等。但是这些都不会返回0ms的超时,而是在我们客户端设定的连接超时时间后超时。因此,这些尝试是有意义的,但是对解决瞬间超时毫无意义。

2,redis 服务器的 timeout 默认是 0,也不应该有问题才对(吧?) :(

3,然后检查最大连接数和当前连接数,没有一点问题,当前连接数远远小于 maxclients配置。

4,redis-cli CLIENT LIST,发现一堆 idle 时间超级久的连接,难道是有 idle 时再请求偶尔就会报超时?(idle连接是怎么造成的呢?长连接却没有复用?php-redis 扩展bug ?predis bug?还是其它异常崩溃导致客户端连接已经释放,但未通知到服务器?)虽然有 idle 连接,但是还是未达到 maxclients 数,不应该连接失败才对,而且超过连接数的错误日志也不是这个。

5,阅读了 redis 官方文档的一篇关于超时的文章,https://redis.io/topics/clients#client-timeouts,发现大坑来了,他的 timeout 指的是连接空闲多久被关闭,而不是熟知的连接超时或者执行超时。这样,结合4,猜测,如果超过了一定空闲连接数,客户端如果没有复用连接而还在建立新连接,redis 服务器再次接受新请求时会一定程度上拒绝。

所以,解决起来超级简单。更改配置文件,以便下次重启 redis 服务器会用到;同时用命令行动态更新配置,实时生效。具体超时时间根据业务需要做调整,其实一般不需要很大,只要不idle,就不会超时的。

vim /path/to/redis.conf
timeout 600
tcp-keepalive 60

$redis-cli
CONFIG SET timeout 600
CONFIG SET tcp-keepalive 60

后记

不得不说,虽然 redis 真的很好用,但 redis 的这个默认配置真的太坑了,不是每个人都有时间和精力把所有 redis 资料阅读一遍的。

看看人家 mysql,各种超时很详细,https://stackoverflow.com/a/4284212/5049871

自己搭建翻墙工具来科学上网(Shadowsocks)

前言 科学上网,是有需求的前提下正确翻墙,不要干坏事儿!具体见 我为什翻墙 题外话 如果懒得折腾,也可以联系我,根据使用情况,把我的服务器有偿共享一个给你,具体邮箱联系 itbudaoweng#gmail.com 概述 下面会需要购买一个 VPS,自己搭建 shadowsocks 这种翻墙服务,通信加密,更安全,同时还可以充分学习服务器知识,一举多得。免费的才是最贵的,你的时间很宝贵。 操作流程 1, 先购买 VPS,必须是国外服务器(墙外的服务器--)。推荐 vultr ,我一直在用,很不错一个月 $5。而且限时促销中,新账户充多少送多少,很合算。vultr注册地址 ,或者直接搬瓦工便宜搬瓦工注册。需要翻墙才能打开,好尴尬,建议找个会翻墙的朋友指导进行。这两个链接都有推荐码,也就是你成功付费后,我能拿到一点提成(10%

非常棒的资源

这个页面会持续更新内容。 Git 服务器软件 Gogs Gitlab 程序相关 电子书 程序员的自我修养 电子书 免费编程书籍集合 WEB开发个人站点 QuQu大神 insp.top 链接收藏 http2 akamai 图片加载测试