花了兩天幫同事追一個問題:為何有個服務重啟後,一直處於不穩甚至無法服務的狀態,但隨著時間是有機會變穩定的。
這算是一個 IoT 老服務了,當裝置上線時會跟服務保持連線(Websocket),其中有一些認證跟服務會使用到 DB server。當運行好一段時間,沒什麼大問題,反應速度也很良好。但碰到服務發布時,都會有一段期間無法正常使用。
此現象主要是 IoT 裝置們當初設計了自動連上雲台的架構,每台裝置啟動後,依序連上雲服務。但是,當服務更新時,若採到斷線機制時,將導致大量的裝置重新連線,而連線過程若有要認證就會佔用到 DB query 資源。此時若有些回應慢,將導致有些裝置認為服務不正常而自行斷線,並且又進入 retry 機制,導致災難性的自家人打自家人 DDoS 世界奇觀。
追了好一陣子,鎖定了一套使用 node.js - loopback 2 框架的服務,並且追到 DB query 瓶頸。主要透過對 db 查詢結果做 cache ,可以大幅度改善狀態,去減少 db query。並且當下 db 並未忙碌到回應緩慢。包括用其他對應機器追蹤查詢 db server 效率,以及在雲台出問題的機器上,直接用 mysql command line 查詢,即可交叉驗證應當是 node.js - loopback 的狀態問題。
原本也有意先把套件都升一升,可惜要跳到 LoopBack 4 並不是簡單的事 Orz 最後,老覺得這件事還是不太正常,就用 concurrent limit loopback mysql 關鍵字逛逛,大部分都在討論連線異常,很少提到連線數的問題,很幸運最後找到 connectionlimit 關鍵字,並且在查一下 loopback-connector-mysql 得知預設是只用 10 這個數字!
if (isNaN(s.connectionLimit)) {
s.connectionLimit = 10;
}
因此,就只需要在 loopback 框架下的 datasources.json ,多定義 connectionLimit 即可,例如來個 100 ,並且在系統上追蹤連線數:
$ netstat -np --inet | grep "YourDBServerIP:3306" | wc -l
100
這樣就搞定啦!當時想說 loopback 2 太舊太難升,是不是弄個類似 mysql command line 查詢機制來頂著用 XD 還因此配合 server 環境用 php5 寫好小工具了:
% echo '{"db_host":"DB_IP","db_user":"DB_USER","db_pass":"password","db_database":"DB_NAME","db_query":"SELECT count(*) FROM device;"}' | jq ''
{
"db_host": "DB_IP",
"db_user": "DB_USER",
"db_pass": "password",
"db_database": "DB_NAME",
"db_query": "SELECT count(*) FROM device;"
}
% echo '{"db_host":"DB_IP","db_user":"DB_USER","db_pass":"password","db_database":"DB_NAME","db_query":"SELECT count(*) FROM device;"}' | php db_helper.php /tmp/db_helper.log N M | jq ''
{
"input": [
[
{
"count(*)": "1234567"
}
]
],
"log": [
0.34358501434326,
0.11107587814331,
0.47047901153564
],
"status": true
}
還設計了
db_helper.php 能不能支援最多跑 N 隻,每隻也來個 timeout M 秒,並透過 lock 機制來保護溝通等,想想這段旅行也是滿好玩的。先把尚未妥善測試的 php5 工具丟到 github 記一下。