2

我正在使用以下代码连接 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()
4

1 回答 1

3

实际上,当您调用 时redis.Redis(),它会为您创建具有连接池的“客户端”,而不仅仅是一个连接。

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

像这样:

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 instance send 命令时,都会调用这个方法:

    # 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)

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

在此处输入图像描述

这是关于 TCP 连接终止过程的图像。当客户端(Initiator)向服务器(Reciever)发送 ACK FIN 时,进入 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 状态。

还有一篇关于TIME_WAIT用途的更详细的文章

于 2017-08-28T08:36:08.473 回答