Redis Python客户端打开许多连接

时间:2017-08-28 06:37:42

标签: python redis redis-py

我使用以下代码连接Redis服务器。 我看到TIME_WAIT状态的巨大连接。可能有什么不对?

root@ubuntu:~$ netstat | grep :6479 | grep TIME_WAIT |wc -l
9061
root@ubuntu:~$ netstat | grep :6479 | grep ESTABLISHED |wc -l
7

我想过使用下面的代码完成Redis服务器的操作后关闭连接。但是我得到了这个错误。

@staticmethod
def disconnectRedisConnection(r_server):
    if r_server is not None and r_server:
        r_server.connection.disconnect()

我收到以下错误,

r_server.connection.disconnect()
AttributeError: 'Redis' object has no attribute 'connection'

关于巨大的TIME_WAIT连接的任何想法/在使用Redis完成操作后关闭连接? 代码:

import threading
from time import sleep
import time, datetime
import traceback
import CACHE_CONST
import json
import os

import MySQLdb
import redis

# Static methods to interact with the Redis cache server
class CacheUtil(object):

    # Log Errors
    @staticmethod
    def log_message(msg):
        log_file = None
        log_file = open (os.path.abspath(CACHE_CONST.REDIS_LOG_FILE), "a")
        print(msg)
        if (log_file):
            message = time.strftime("%d-%m-%Y %H:%M:%S")    
            message += " :: " + str(msg)
            log_file.write(message + "\n")

    @staticmethod
    def saveToCache(hashName, hashValue):
        r_server = CacheUtil.getRedisConnection()
        r_server.hmset(hashName, hashValue)
        CacheUtil.disconnectRedisConnection(r_server)

    @staticmethod
    def getTrackerDetailsByID(trackerId):
        trackerDetail = None
        r_server = None
        hashName = "tDetails:" + str(trackerId)
        try:
            if trackerId is not None:
                print("getTrackerDetailsByID ")
                r_server = CacheUtil.getRedisConnection()
                trackerDetail = r_server.hgetall(hashName)
            else:
                CacheUtil.log_message("getDetailsByID failed with empty trackerId ")
        except:
            CacheUtil.log_message("getDetailsByID failed, ll fetch from DB " + str(traceback.format_exc()))
        finally:
            CacheUtil.disconnectRedisConnection(r_server)
        return trackerDetail

    @staticmethod
    def getRedisConnection():
        print("Get Redis Connection on Util ")
        r_server = redis.Redis(host=CACHE_CONST.REDIS_SERVER_URL, port=CACHE_CONST.REDIS_SERVER_PORT, db=0, password=CACHE_CONST.REDIS_PASS_PHRASE, socket_connect_timeout=2, socket_timeout=2)
        return r_server;

    @staticmethod
    def disconnectRedisConnection(r_server):
        if r_server is not None and r_server:
            r_server.connection.disconnect()

1 个答案:

答案 0 :(得分:2)

实际上,当你拨打import threading from time import sleep import time, datetime import traceback import CACHE_CONST import json import os import MySQLdb import redis r_server = redis.Redis(host=CACHE_CONST.REDIS_SERVER_URL, port=CACHE_CONST.REDIS_SERVER_PORT, db=0, password=CACHE_CONST.REDIS_PASS_PHRASE, socket_connect_timeout=2, socket_timeout=2) # Static methods to interact with the Redis cache server class CacheUtil(object): # Log Errors @staticmethod def log_message(msg): log_file = None log_file = open (os.path.abspath(CACHE_CONST.REDIS_LOG_FILE), "a") print(msg) if (log_file): message = time.strftime("%d-%m-%Y %H:%M:%S") message += " :: " + str(msg) log_file.write(message + "\n") @staticmethod def saveToCache(hashName, hashValue): r_server.hmset(hashName, hashValue) @staticmethod def getTrackerDetailsByID(trackerId): hashName = "tDetails:" + str(trackerId) try: if trackerId is not None: print("getTrackerDetailsByID ") trackerDetail = r_server.hgetall(hashName) else: CacheUtil.log_message("getDetailsByID failed with empty trackerId ") except: CacheUtil.log_message("getDetailsByID failed, ll fetch from DB " + str(traceback.format_exc())) return trackerDetail 时,它会创建"客户端"对于你有连接池,而不仅仅是一个连接。

每次发送redis.set()或其他命令时,它都会从其连接池中检索连接,并使用此连接发送此命令并等待回复。请求完成后,它会将连接重新连接到连接池以便重用。所以你不需要自己管理连接。查看此https://github.com/andymccurdy/redis-py了解更多信息。

就像这样:

    # COMMAND EXECUTION AND PROTOCOL PARSING
def execute_command(self, *args, **options):
    "Execute a command and return a parsed response"
    pool = self.connection_pool
    command_name = args[0]
    connection = pool.get_connection(command_name, **options)
    try:
        connection.send_command(*args)
        return self.parse_response(connection, command_name, **options)
    except (ConnectionError, TimeoutError) as e:
        connection.disconnect()
        if not connection.retry_on_timeout and isinstance(e, TimeoutError):
            raise
        connection.send_command(*args)
        return self.parse_response(connection, command_name, **options)
    finally:
        pool.release(connection)

<强>更新

每次使用redis instance send命令时,都会调用此方法:

for j in $(seq 2 10)
do
printf "#!/bin/csh
set cnt    = ${j}

set cnt2   = ${j}+1 > "prod_${j}.ll"
done

关于巨大的TIME_WAIT连接的任何想法/使用Redis完成操作后关闭连接

enter image description here

这是关于TCP连接终止过程的图像。当客户端(发起者)为服务器(接收者)FIN发送ACK时,它进入Time_WAIT状态。

TCP / IP引用的文字说明了第1卷:

  

当TCP执行主动关闭并发送时   最后的ACK,该连接必须保持TIME_WAIT状态两倍的MSL。这让TCP   如果丢失,则重新发送最终的ACK。重新发送最终ACK不是因为TCP重新发送ACK   (它们不消耗序列号而不是由TCP重传),而是因为另一方   将重新传输其FIN(消耗序列号)。实际上,TCP将始终重新传输   FIN直到收到最终的ACK。

因此它将处于TIME_WAIT状态四分钟,之后,它将自动关闭连接。因为您打开新的tcp连接并经常关闭它,所以许多已关闭的连接将处于TIME_WAIT状态。

还有一篇关于the purpose about TIME_WAIT

的更详细的文章