背景#
組內現有的監控數據主要分為 系統日誌數據 與 業務埋點數據,分佈在對應兩個平台上,在系統上線後或是業務高峰期時研發同學需要持續關注線上數據來預判風險,兩個平台來回刷新操作頻繁,體驗不佳。
思考#
- 兩個平台來回查看麻煩,可以考慮整合不同平台的數據源做處理
- 將主動查看變為被動感知,進一步提升體驗
問題拆解與方案#
- 針對第一點,不同平台提供了對應的指標查詢 API ,這部分主要考慮數據源的定義、配置與整合
- 基於指標查詢 API,在自研監控平台站點上新增了一個業務偵查配置模塊,用戶可以以項目維度配置對應不同平台的監控指標
- 針對第二點,在做好數據源的配置整合後還需要實現數據的推送,內部 IM 工具也提供了開放平台 API 可接入調用
在常規的數據推送之外,還需要支持用戶自定義周期的訂閱推送,使用 node-cron 來生成對應的定時任務,一個訂閱配置對應一個任務,用戶更新了訂閱配置,對應的任務也需要更新。
目前方案拆解下來還是比較直觀清晰的,但問題在於我們自研監控平台服務是走的 PM2
同時會啟動 4 個進程,以及線上集群至少是 3 台機器,同時在運行的 node-cron
任務至少是 12 個,因此又出現了 多進程間的周期任務管理 的問題。
從整體的負載均衡考慮,允許多進程註冊多任務,但要保證只有一個任務會被執行,以及用戶修改配置的請求會打到其中任意一個進程,也需要保證剩餘進程同步註冊最新任務。
多進程管理方案#
從後端的角度看很明顯是需要實現一個分佈式鎖,最常見的方式就是使用 Redis
的 setnx
命令,但內部監控平台站點目前只使用到了 MongoDB
做存儲,秉承盡量不引入新依賴的原則仔細思考了一下,發現 MongoDB
自帶的原子性操作也能做到,詳細流程如下
核心邏輯是設計了兩個標誌位:
- 有效標誌位解決多進程同步問題
- 運行標誌位解決多進程並發問題
標誌位的規則是 IPv4
地址 + Node
進程號,其中進程號可以直接通過 process.env.NODE_APP_INSTANCE
獲取,而 IP 地址需要借助內置的 node:os
模塊
import { networkInterfaces } from 'os';
/**
* 返回 ipv4 地址
*/
export const getIPAddress = () => {
const interfaces = networkInterfaces();
let address = '';
for (const devName in interfaces) {
if (Object.prototype.hasOwnProperty.call(interfaces, devName)) {
const iface = interfaces[devName] || [];
iface.forEach((alias) => {
if (
alias.family === 'IPv4' &&
alias.address !== '127.0.0.1' &&
!alias.internal
) {
address = alias.address;
}
});
}
}
return address;
};
最終利用標誌位的設置很好地解決了多進程管理的問題。