redis-py連接池的實現

說起連接池,可能很多人直接望而卻步,覺得好複雜,還是直接調用別人現成的好了,其實都是連接池也是扮豬喫老虎。

但是之前看redis-py連接池的實現,覺得好簡單,但是卻又很巧妙,正好最近又在研究redis-py的連接池,將連接池相關的實現抽象出來,接單說明一下。

class Connection:
    def __init(self, **db_info):
        """初始化需要一些redis服務器的連接信息,此處以db_info代替"""
        self._sock = None
        pass
        
        
    def connect(self):
        """供上層調用"""
        if not self._sock:
            self._connect()
            
        pass
        
    def _connect(self):
        """同redis服務器建立socket"""
        self._sock = socket(**db_info)
    
    def disconnect(self):
        """關閉socket連接,此處很巧妙"""
        """連接對象不會銷燬,內部的socket會被銷燬"""
        self.socket = None
        
    def send_command(self, **args):
        if not self._socket:
            self.connect()
        self._sock.sendall(**args)
        
    def read_response(self):
        return self._sock.readall()
    
    
class ConnectionPool:
    def __init__(self, **pool_config, **db_info):
        """實例化需要連接池配置(如連接池大小),數據庫連接信息"""
        self.reset()
        
    def reset(self):
        """初始化內部維護的連接"""
        self._available_connections = []
        self._in_use_connections = set()
    
    def make_connection(self):
        """創建新的連接對象"""
        conn = Connection(**db_info)
        
    def get_connection(self):
        """獲取一條連接,供上層調用"""
        if self._available_connections:
            conn = self._available_connections
        else:
            conn = self.make_connection()
        
        self._in_use_connections.add(conn)
        return conn
        
    def release(self, connection):
        """釋放單個連接對象到連接池"""
        self._in_use_connections.remove(connection)
        self._available_connections.append(connection)
    
    def disconnect(self):
        """將關閉所有在用的,可用的連接對象"""
        all_conns = chain(self._available_connections,
                          self._in_use_connections)
        for connection in all_conns:
            connection.disconnect()
        
class Redis:
    """redis對象,實例化之後內部同時實例化一個連接池對象"""
    def __init__(self, **pool_config, **db_info):
        self.pool = ConnectionPool(**pool_config, **db_info)
        
    def execute_command(data):
        """從連接池取出一條連接,發送信息,釋放給連接池"""
        connection = self.pool.get_connection()
        try:
            connection.send_command(data)
        except:
            connection.disconnect()
        pool.release(connection)
        

當然關於上面的代碼遺漏了很多的防禦代碼 ,比如檢測父子進程是否共用一個相同的描述符等,但是我覺的把redis-py連接池的關鍵表達出來了。

連接池內部維護兩個集合,一個可用的連接集合,一個在用的連接集合,當上層獲取連接的時候,從可用集合拿出一個返回,同時加到在用集合。

還有一個很巧妙的細節,就是連接在傳遞數據出錯的時候,不是銷燬連接對象,而是銷燬連接對象內部的socket。因爲連接對象一旦實例化就沒有足夠的理由去銷燬它,即使出錯也是socket連接出錯,銷燬socket就好了,避免了連接對象的頻繁生成、銷燬。

最後推薦一下老錢的《Redis 深度歷險:核心原理與應用實踐

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章