生產級Nodejs開發實踐-使用鏈接池

引言

作後端開發免不了要和一些 存儲服務器, 消息服務器 等等 打交道。node

原由 (傳統模式, 讀取數據庫)

你們都知道和這些使用 tcp鏈接 的服務傳遞數據的都必需要打開 一個 鏈接-connectionmysql

例如咱們打開一個數據庫並執行一段 sql, 一般都是git

  1. connection = open "mysql://127.0.0.1:3306/db" (打開數據庫,並取得持有鏈接的句柄)
  2. data = connection.exec "select * from table1" (執行 sql 並獲取數據)
  3. connection.close() 顯式的關閉鏈接

這個方式看上去彷佛沒有什麼不對的。github

可是對於併發量稍大一些的站點來講。一個單元批次的操做就須要打開並關閉一次鏈接。。。
顯然是不能接受的redis

爲這樣作不能接受呢?

創建一個tcp鏈接須要三次握手。並且還須要爲對象分配系統資源和內存空間。因此建立一個tcp鏈接能夠說是昂貴的。sql

回到剛纔的話題。這樣平凡的開啓關閉鏈接不只對增長客戶端io的壓力,最重要的是大大增長了 tcp 服務器的壓力(mysql, redis)。數據庫

那咱們再嘗試另一種方式,那就是不關閉鏈接,一直使用這個鏈接呢。答案是: 能夠。這種方式 被叫作 長鏈接npm

那這樣的話,也有一個問題。由於一段時間內一個鏈接只能作一件事情。那麼在併發的狀況下這顯然會阻塞整個系統。後端

那咱們能不能嘗試建立多個鏈接,而後當調用的時候,將沒有被使用的鏈接拿出來使用,當使用完畢以後,將鏈接放回去,以供其餘調用者使用的方式的呢?緩存

鏈接大管家(鏈接池)

答案是有的:那就是咱們要說的鏈接池。固然一個健全的鏈接池並不單單完成以上我所說的功能。

  • 鏈接預熱 (啓動時自動打開n個鏈接以供使用)
  • 使用 例如 輪轉法 均勻分發 鏈接請求
  • 當池中的鏈接即將耗盡得時候動態產生新的鏈接
  • 當池中的鏈接一段時間沒有被調用的時候,自動釋放鏈接
  • 自動丟棄 已經壞掉的 鏈接
  • 系統關閉的時自動釋放全部鏈接
    ........

以上都屬於鏈接池的功能。鏈接池可謂是咱們管理鏈接的管家

Node.js 中的 鏈接池

說到這裏好像仍是沒有說到要點。在Node中咱們應該怎麼呢?

咱們可使用 node-pool 這個模塊 GitHub

1. 安裝 

    npm install generic-pool
2. 建立一個鏈接池       
    // 建立一個 mysql 鏈接池
    var poolModule = require('generic-pool');
    var pool = poolModule.Pool({
        name     : 'mysql',
        //將建 一個 鏈接的 handler
        create   : function(callback) {
                var Client = require('mysql').Client;
                var c = new Client();
                c.user     = 'scott';
                c.password = 'tiger';
                c.database = 'mydb';
                c.connect();
                callback(null, c);
        },
        // 釋放一個鏈接的 handler
        destroy  : function(client) { client.end(); },
        // 鏈接池中最大鏈接數量
        max      : 10,
        // 鏈接池中最少鏈接數量
        min      : 2, 
        // 若是一個線程3秒鐘內沒有被使用過的話。那麼就釋放
        idleTimeoutMillis : 30000,
        // 若是 設置爲 true 的話,就是使用 console.log 打印入職,固然你能夠傳遞一個 function 最爲做爲日誌記錄handler
        log : true 
    });
3. 從鏈接池中得到連接並使用
    // 默認無任務優先級, 可是與高優先級同樣,在競爭隊列的前列
    pool.acquire(function(err, client) {
       pool.release(client);
    });

    // 高優先級得到連接, 在競爭隊列的前列
    pool.acquire(function(err, client) {
       pool.release(client);
    }, 0);

     // 中等優先級得到連接
     pool.acquire(function(err, client) {
         pool.release(client);
     }, 1);

     // pool.acquire(handler, priority) 方法接受連個參數 
     // handler: 獲取鏈接的回掉函數
     // priority: 獲取到連接的競爭優先級
     // pool.release(client) 方法會將連接放回到鏈接池當中,當得到的連接沒有release的話。將會致使該連接被一直佔用

更多相關的配置 我就不一一展開討論了。你們能夠去 github 上查看項目的 README.md

【生產級別Nodejs開發實踐-強壯的node進程容器PM2】- 敬請期待

注:
存儲服務器: (數據庫 mysql ..., 緩存 memcached, redis ...)
消息服務器: (RabbitMQ,ActiveMQ ...)

相關文章
相關標籤/搜索