greentor MySQL連接池實現
阿新 • • 發佈:2018-10-17
ack urn 如果 als 新建 mysql 會有 emc main
greentor MySQL連接池實現
https://en.wikipedia.org/wiki/Connection_pool
通過greentor實現了pymysql在Tornado上異步調用的過程後發現,每次建立數據庫連接都會經過socket 3次握手,而每一次socket讀寫都會伴隨著greenlet的切換,以及ioloop的callback過程,雖然是異步了,但是IO性能並沒有提升,所以在研究了TorMySQL連接池的實現後,實現了greentor自己的連接池。
https://github.com/zhu327/greentor/blob/master/greentor/green.py
class Pool(object): def __init__(self, max_size=32, wait_timeout=8, params={}): self._maxsize = max_size # 連接池最大連接數 self._conn_params = params # 連接參數 self._pool = deque(maxlen=self._maxsize) # 存儲連接的雙端隊列 self._wait = deque() # 等待獲取連接的callback self._wait_timeout = wait_timeout # 等待超時時間 self._count = 0 # 已創建的連接數 self._started = False # 連接池是否可用 self._ioloop = IOLoop.current() self._event = Event() # 連接池關閉時間,set該時間後,連接池所有的連接關閉 self._ioloop.add_future(spawn(self.start), lambda future: future) # 在greenlet中啟動連接池 def create_raw_conn(self): pass # 通過self._conn_params參數創建新連接,用於重寫 def init_pool(self): # 創建新的連接,並加入到連接池中 self._count += 1 conn = self.create_raw_conn() self._pool.append(conn) @property def size(self): # 可用的連接數 return len(self._pool) def get_conn(self): while 1: if self._pool: # 如果有可用連接,直接返回 return self._pool.popleft() elif self._count < self._maxsize: # 如果沒有可用連接,且創建的連接還沒有達到最大連接數,則新建連接 self.init_pool() else: self.wait_conn() # 如果沒有可用連接,且以創建了最大連接數,則等待連接釋放 def wait_conn(self): timer = None child_gr = greenlet.getcurrent() main = child_gr.parent try: if self._wait_timeout: # 創建計時器,如果等待了超時則拋出異常 timer = Timeout(self._wait_timeout) timer.start() self._wait.append(child_gr.switch) main.switch() # 切換到父greenlet上,直到child_gr.switch被調用 except TimeoutException, e: raise Exception("timeout wait connections, connections size %s", self.size) finally: if timer: timer.cancel() def release(self, conn): self._pool.append(conn) # 釋放連接,重新加入連接池中 if self._wait: # 如果有等待的greenlet callback = self._wait.popleft() self._ioloop.add_callback(callback) # 在下次ioloop過程中切換到等待獲取連接的greenlet def quit(self): # 關閉連接池 self._started = False self._event.set() def _close_all(self): for conn in tuple(self._pool): conn.close() self._pool = None def start(self): # self.init_pool() self._started = True self._event.wait() self._close_all()
這是一個通用連接池,通過繼承Pool
類,並重寫create_raw_conn
方法就可用實現一個簡單的連接池,比如mysql,memcache等
https://github.com/zhu327/greentor/blob/master/greentor/mysql.py
from pymysql.connections import DEBUG, Connection class ConnectionPool(Pool): def __init__(self, max_size=32, keep_alive=7200, mysql_params={}): super(ConnectionPool, self).__init__(max_size=max_size, params=mysql_params) self._keep_alive = keep_alive # 為避免連接自動斷開,配置連接ping周期 def create_raw_conn(self): conn = Connection(**self._conn_params) if self._keep_alive: self._ioloop.add_timeout(time.time()+self._keep_alive, self._ping, conn) return conn @green def _ping(self, conn): if conn in self._pool: self._pool.remove(conn) conn.ping() self.release(conn) self._ioloop.add_timeout(time.time()+self._keep_alive, self._ping, conn)
這裏實現了一個MySQL的連接池,MySQL默認會有一個8小時空閑,連接自動斷開的機制,為了避免連接池中出現無效連接,在設置了keep_alive
時間後會周期性的調用連接的ping
方法來保證連接的活躍,同時如果連接不在連接池中,說明連接正在被使用,就不需要再ping
了。
事隔三個月,在一位新認識的朋友提醒下,又撿起了greentor的開發,把之前準備實現的連接池寫了出來。
greentor MySQL連接池實現