承上一篇,在測試完 mongo 與 redis 後,這篇要來討論的是如何將 worker 做水平擴展
需求與限制:
動態擴展:
由於 iot 的使用情境很多變,上傳的資料量在一天的不同時候差異很大,希望能透過 k8s 內建的擴展機制,自動根據 cpu、memory、net worker traffic 擴展 worker instance 數量
不處理重複資料:
worker 應該透過某種分配機制,讓設備上傳的資料分配到有空的 worker 去做,而不是兩個 worker 拿到一樣的資料去處理造成性能浪費
資料順序性:
由於 archiver 計算 recording data 時,需要資料按照資料時間依序傳給 archiver 計算,所以 worker 產出的資料須確保資料順序性
提案:
Load balancer:

透過一個 load balancer 去訂閱設備上傳上來的消息,之後根據 device id % worker instance 數量來分配資料給 worker
優點:
- worker 收到的訊息有順序性
 
缺點:
- load balancer 不能 scale
 - worker 死掉 or 新開 worker 後,topic 內殘存資料應該如何分配
 
Delayed queue:

使用 amqp 競爭消費的特性,讓 worker 自動根據自身處理能力去 rabbitmq 中爭搶訊息來處理,但由於不同 worker 處理速度快慢,處理完的資料可能順序會錯亂,所以需要透過第二層的 delayed queue 去將資料排序後再傳給 archiver 計算
優點:
- worker scale 起來方便,不需維護狀態
 
缺點:
- 為了排序,須將資料留在 Delayed Queue 中一段時間,可能會有延遲問題
 - worker 死掉 or 新開 worker 後,topic 內殘存資料應該如何分配
 
Save to db then query:

worker 一樣去搶消息,處理完資料後直接塞到 mongodb,archiver 改成過一段時間去 mongodb 撈資料出來算,算完再存回去
另外 mongo db 要開 replica set 做讀寫分離減低 mongo 壓力
優點:
- worker scale 方便,不用維護狀態
 - archiver scale 方便
 
缺點:
- mongo 壓力很大
 
取捨:
load balancer 方案因為不好 scale 以及 worker instance 數量增加/減少時需要處理的事情很多,因此先 pass
save to db then query 雖然整體架構最簡單,但在之前使用經驗中,問題常常都是因為 mongodb 的速度太慢導致,現在如果還要加上讓 archiver 去 mongo 拿資料,怕負擔會更重
於是折衷選了 delay queue 方案,讓 worker 去搶消息,之後在 delay queue 中停留一段時間排序後再給 archiver 處理