poolboy: A hunky Erlang worker pool factory 是一個通用用途的 erlang pool library,主要是用在 pool 管理,對於 server 程式來說,最常見的就是連接資料庫的 connection pool。
連接資料庫最簡單的做法,是在程式中要呼叫使用資料庫時,要經過連線與認證,使用完畢後,就馬上關閉該資料庫連線,但對於 server 來說,因為大量的連線建立關閉,消耗了很多運算資源,故通常會以資料庫 connection pool 的方式來處理。
一般的 connection pool,會有初始的連線 pool 數量,就是一開始啟動時,固定會產生並維持幾個連線數量,然後在所有連線都被佔用時,有一個 overflow 的數量,設定超量使用時,一次多產生幾個連線。另外為了確保該網路連線是正常連線的狀態,DB pool 通常會定時發送一個 SQL 指令,以該指令有沒有回應來確認連線狀態。例如 MySQL 可以使用 SELECT CURRENT_TIMESTAMP
這樣的 SQL 指令。
poolboy 就是用 erlang process 來作為一個 connection 的資源,該 process 的 state 裡面,就記錄該資料庫連線,另外有個 supervisor 用來做連線的資源管理。
使用方式
poolboy 以 epgsql 為例,說明如何使用 poolboy,要實作兩個部分 worker 跟 supervisor,另外要做 pool 的設定。細節直接看 poolboy 的 github 首頁即可。
poolboy 裡面的 transaction 就是使用該 pool 的最簡單的方式,先 checkout 一個 worker,然後呼叫 worker 裡面的某一個 function,最終使用完成後,呼叫 checkin 釋放 worker。
transaction(Pool, Fun, Timeout) ->
Worker = poolboy:checkout(Pool, true, Timeout),
try
Fun(Worker)
after
ok = poolboy:checkin(Pool, Worker)
end.
checkout 有三種方式
% 取得可以使用的 worker process,如果沒有,預設會等待 5s
1> Worker = poolboy:checkout(PoolName).
% returns PID in under 5 seconds or full.
% 不等待,直接回傳可使用的 worker
2> Worker = poolboy:checkout(PoolName, false).
% no waiting, either you have an idle worker for me or not.
% 等待 10s
3> Worker = poolboy:checkout(PoolName, true, 10000).
% like the first one but wait 10 secs instead of 5
注意事項
poolboy 的坑(Erlang) - 开发者头条
使用 poolboy 時,要注意幾個問題,產生 worker process 時,不能失敗,如果 worker 失敗,會導致整個 gen_server crash,無法啟動 pool。
解決方法是使用 proxy,也就是在建立 worker 時,並不直接產生 db 的連線,而是直接將 worker process 建立起來,後續在使用到該 worker 時,才去檢查 worker 裡面的 conn state。
這邊的問題是在如何做連線維持,因為 worker 把連線建立延後了,這表示使用 worker 以前,不能確認該 worker 擁有的 conn 到底是不是正常的連線,連線也可能因為 idle 太久而被資料庫直接斷線。
連線維護的部分,會需要在 worker 裡面另外寫 timer,定時做 callback,然後定時發送一個 SQL 指令,以該指令有沒有回應來確認連線狀態。
References
GitHub - interline/epgsql_pool: Pooled epgsql connections using Poolboy
GitHub - hiroeorz/eredis_pool: eredis_pool is Pool of Redis clients, using eredis and poolboy.
erlang进程池-poolboy源码分析_食鱼酱的博客-CSDN博客
# erlang线程池poolboy源码阅读
Erlang poolboy notes – Triggers-World