我们目前遇到了很多 Redis 错误,错误信息如下
无法连接:读取连接错误,正在尝试下一个服务器
我们在 FreeBSD 上使用 PHP Redis 运行 Redis,在 Ubuntu 上很难重现错误,所以这可能是一个提示。有一个长期运行的github 上关于该主题的 issue。
基本上,我们通过调用 phpredis 从操作系统获取套接字connect(host, port, timeout)
,但之后执行时select(db_index)
,我们收到异常。持久性可能存在问题吗?我假设 connect 在后台不执行任何操作,而 select 尝试访问实际上已关闭的连接。
我们没有遇到超时。我们尝试调整 TIME_WAIT,但没有成功。
关于问题可能出在哪里,还有其他想法吗?追踪问题的最佳方法是什么?也许使用 dtrace?
更新
我们目前正在研究我们的 BGSAVE 设置。有趣的是,创建定期将数据写入磁盘(持久性)的进程的分支需要半秒甚至更长时间,并且 redis 可能无法connect()
在这段时间内响应请求。
答案1
我们通过以下方法将错误率降低了 90%redis 命令:
CONFIG SET save ""
这将禁用 BGSAVE,它定期将所有数据库更改存储在磁盘上。连接错误的原因很可能是fork()
主 redis 进程启动 BGSAVE 进程的阻塞操作。
redis.conf 说:
# Redis may block too long on the fsync() call. Note that there is no fix for
# this currently, as even performing fsync in a different thread will block
# our synchronous write(2) call.
另请参见如何使用简单的fork()
这里。我们考虑使用我们池中的专用 redis 服务器,该服务器将负责 BGSAVE 操作,而其他服务器仅用于读取/写入。
从 IRC 聊天来看,似乎其他几家公司也遇到了同样的错误。撞也使用主/从系统。从服务器不接受连接,只用于保存数据(参见关于 hackernews 的讨论在这里)
葫芦说了以下内容:“为了保持分片上的性能一致,我们禁用了所有分片的磁盘写入功能,并且我们有一个 cron 作业,每天凌晨 4 点运行,在每个单独的实例上滚动执行“BGSAVE”命令。”(看这里)
编辑:
事实证明这只是一个临时解决方案。负载增加,错误率又回到了高位。不过,我很确定是后台操作(例如 fork 或短时间运行的后台进程)导致了错误,因为错误消息总是以块的形式出现。
编辑2:
由于 Redis 是单线程的,因此请始终关注长时间运行的操作,因为它们会阻止其他所有操作。keys *
命令就是一个例子。避免使用它,而scan
改用