Python Redis连接timeout参数配置详解

Redis连接配置:socket_connect_timeout/socket_timeout/retry_on_timeout

1.socket_timeout

  • 此配置参数是指Redis发出命令接收响应的时间不能超过此参数设置时间. 如果超过了此时间, 将会抛出异常:redis.exceptions.TimeoutError: Timeout reading from socket, 即读取响应超时.

  • 如何来演示socket_timeout触发的超时问题呢? 可以从我们经常在list类型数据上进行BLPOP操作着手.

    from redis import StrictRedis
    
    redis = StrictRedis(host="192.168.0.111",
                        port=6380,
                        db=13,
                        socket_timeout=5,
                        socket_connect_timeout=2,
                        decode_responses=True)
    
    
    a = redis.blpop("test_key", timeout=10)
    

    如上所示: 当test_key列表为空时, BLPOP命令将会进行阻塞, 阻塞的timeout设置为10秒, 但Redis连接的socket_timeout设置为5秒. 此时会触发异常.

    原因如下: 当我们在进行BLPOP操作时, 阻塞的过程其实也是等待响应的过程(waiting for reading from socket). 因为socket_timeout设置为5秒, 所以阻塞5秒后会触发超时异常, 而非等待10秒后得到的None.

  • 解决方式: 将类BLPOP型命令的超时时间设置少于socket_timeout设置的时间即可.

    from redis import StrictRedis
    
    redis = StrictRedis(host="192.168.0.111",
                        port=6380,
                        db=13,
                        socket_timeout=10,
                        socket_connect_timeout=2,
                        decode_responses=True)
    
    
    a = redis.blpop("test_key", timeout=5)
    
  • 实际业务中遇到此问题是在使用redis_lock过程中, 其实原理和上述一致(实际redis_lock底层也是使用了BLPOP命令), 只是锁的过期时间需要小于socket_timeout设置的时间.示例代码如下:

    # -*- coding: utf-8 -*-
    import time
    import threading
    
    import redis_lock
    from redis import StrictRedis
    
    redis = StrictRedis(host="192.168.0.111",
                        port=6380,
                        db=13,
                        socket_timeout=5,
                        socket_connect_timeout=2,
                        decode_responses=True)
    
    
    def func1():
        with redis_lock.Lock(redis_client=redis, name="test_key", expire=10):
            print("线程01获取到了锁")
            time.sleep(120)
    
    
    def func2():
        with redis_lock.Lock(redis_client=redis, name="test_key", expire=10):
            print("线程02获取到了锁")
            time.sleep(120)
    
    
    if __name__ == '__main__':
        t1 = threading.Thread(target=func1)
        t2 = threading.Thread(target=func2)
        t1.start()
        t2.start()
        t1.join()
        t2.join()
    
    

2.socket_connect_timeout

  • 此配置参数指Redis建立连接超时时间. 当设置此参数时, 如果在此时间内没有建立连接, 将会抛出异常redis.exceptions.TimeoutError: Timeout connecting to server.

  • 可以用以下代码做测试, 比如, 将socket_connect_timeout设置尽可能小, 则很容易模拟实际的连接超时问题.

    from redis import StrictRedis
    
    redis = StrictRedis(host="192.168.0.111",
                        port=6380,
                        db=13,
                        socket_connect_timeout=0.001)
    
  • redis-py源码进行分析, 实际redis建立TCP连接使用socket包进行的连接. 源码如下:

        def connect(self):
            if self._sock:  # 如果连接已存在,则直接返回
                return
            try:
                sock = self._connect()
            except socket.timeout:  # 此处即捕获socket的timeout异常
                raise TimeoutError("Timeout connecting to server")
    
        def _connect(self):
            "Create a TCP socket connection"
            """此处即实际Redis使用socket进行tcp连接的方法,在此处会在连接超时时抛出异常"""
            err = None
            for res in socket.getaddrinfo(self.host, self.port, self.socket_type,
                                          socket.SOCK_STREAM):
                family, socktype, proto, canonname, socket_address = res
                sock = None
                try:
                    sock = socket.socket(family, socktype, proto)
                    # TCP_NODELAY
                    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
    
                    # TCP_KEEPALIVE
                    if self.socket_keepalive:
                        sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
                        for k, v in iteritems(self.socket_keepalive_options):
                            sock.setsockopt(socket.IPPROTO_TCP, k, v)
    
                    # set the socket_connect_timeout before we connect
                    sock.settimeout(self.socket_connect_timeout)
    
                    # connect
                    sock.connect(socket_address)
    
                    # set the socket_timeout now that we're connected
                    sock.settimeout(self.socket_timeout)
                    return sock
    
                except socket.error as _:
                    err = _
                    if sock is not None:
                        sock.close()
    
            if err is not None:
                raise err  # 此处抛出实际连接异常的错误信息
            raise socket.error("socket.getaddrinfo returned an empty list")
    

3.retry_on_timeout

  • 此参数为布尔型. 默认为False.
  • 当设置False时, 一个命令超时后, 将会直接抛出timeout异常.
  • 当设置为True时, 命令超时后,将会重试一次, 重试成功则正常返回; 失败则抛出timeout异常.

引用

Need clarification and better documentation on socket_timeout, socket_connect_timeout, and blocking commands

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容