在我们的应用程序中,[Errno 54] Connection reset by peer
是随机出现的,看起来它是由redis服务器而不是客户端触发的。Python的redis客户端有backoff
策略实现,但它无法处理这种情况。
有github问题的官方回购以及和许多人评论最近证实了这个问题。
- Random ConnectionErrors (104, Connection reset by peer) #1186
- redis.exceptions.ConnectionError: Error while reading from socket: (104, 'Connection reset by peer') #1439
重现步骤
$ ipython
# in python client
import redis
from redis.retry import Retry
from redis.exceptions import (TimeoutError, ConnectionError)
from redis.backoff import ExponentialBackoff
# connect client with exponential backoff retry
client = redis.StrictRedis(retry=Retry(ExponentialBackoff(cap=10, base=1), 25), retry_on_error=[ConnectionError, TimeoutError, ConnectionResetError], health_check_interval=1)
client.keys()
# print all keys
现在直接从redis服务器重置连接
$ redis-cli
RESET
等待120秒或更长时间,然后再次运行客户端
# in client
client.keys()
---------------------------------------------------------------------------
ConnectionResetError Traceback (most recent call last)
<ipython-input-91-011ce9f936fc> in <module>
----> 1 client.keys("rq*")
~/path-to-python-env/env/lib/python3.8/site-packages/redis/commands/core.py in keys(self, pattern,**kwargs)
1386 For more information check https://redis.io/commands/keys
1387 """
-> 1388 return self.execute_command("KEYS", pattern,**kwargs)
1389
1390 def lmove(self, first_list, second_list, src="LEFT", dest="RIGHT"):
~/path-to-python-env/env/lib/python3.8/site-packages/redis/client.py in execute_command(self, *args,**options)
1168 pool = self.connection_pool
1169 command_name = args[0]
-> 1170 conn = self.connection or pool.get_connection(command_name,**options)
1171
1172 try:
~/path-to-python-env/env/lib/python3.8/site-packages/redis/connection.py in get_connection(self, command_name, *keys,**options)
1315 # closed. either way, reconnect and verify everything is good.
1316 try:
-> 1317 if connection.can_read():
1318 raise ConnectionError("Connection has data")
1319 except ConnectionError:
~/path-to-python-env/env/lib/python3.8/site-packages/redis/connection.py in can_read(self, timeout)
793 if not sock:
794 self.connect()
--> 795 return self._parser.can_read(timeout)
796
797 def read_response(self, disable_decoding=False):
~/path-to-python-env/env/lib/python3.8/site-packages/redis/connection.py in can_read(self, timeout)
315
316 def can_read(self, timeout):
--> 317 return self._buffer and self._buffer.can_read(timeout)
318
319 def read_response(self, disable_decoding=False):
~/path-to-python-env/env/lib/python3.8/site-packages/redis/connection.py in can_read(self, timeout)
222
223 def can_read(self, timeout):
--> 224 return bool(self.length) or self._read_from_socket(
225 timeout=timeout, raise_on_timeout=False
226 )
~/path-to-python-env/env/lib/python3.8/site-packages/redis/connection.py in _read_from_socket(self, length, timeout, raise_on_timeout)
192 sock.settimeout(timeout)
193 while True:
--> 194 data = self._sock.recv(socket_read_size)
195 # an empty string indicates the server shutdown the socket
196 if isinstance(data, bytes) and len(data) == 0:
ConnectionResetError: [Errno 54] Connection reset by peer
第二次运行它的效果很好,尽管它应该通过重试策略来处理。
client.keys()
# prints all keys
组态
redis server - 6.2.6
python redis - 4.1.0
我们可以编写自己的try/catch函数,但是我们使用了一些库,比如rq
和flask-cache
,它们在内部使用redis,并且没有接口来修改它的流。
任何帮助都是非常感谢的。
2条答案
按热度按时间rxztt3cl1#
尝试使用连接池,因为它将保持活动状态并自动尝试在后台恢复。在REPL
在另一个shell中,您可以通过运行redis-cli进行测试
然后运行
您应该会在redis-cli中看到一个新连接
rsl1atfo2#
您还可以设置healtcheck值,
client = redis.Redis(..., health_check_interval=30)
它将重新建立连接。https://github.com/redis/redis-py/issues/1186中提供了更多详细信息