因為之前出了一個線上部署了404鏈接的小事故,組內(nèi)決定在原有的定時監(jiān)控上加一個“每10分鐘檢測一次線上404次數(shù)”的告警。
因為監(jiān)控的數(shù)據(jù)都是通過clickhouse存儲,所以數(shù)據(jù)的采集需要寫clickhouse的SQL腳本,這次寫還get了獲取clickhouse日期的方法,之前都是通過js手動獲取當(dāng)天日期,然后插到sql中去查詢。其實clickhouse的SQL語句已經(jīng)內(nèi)置了時間相關(guān)的函數(shù),具體可以看這里(感謝翻譯大佬的貢獻(xiàn),不過想微微吐槽一下翻譯把API也給翻譯成了中文,導(dǎo)致看半天發(fā)現(xiàn)怎么沒發(fā)現(xiàn)對應(yīng)的api,建議中英文結(jié)合查看)
言歸正傳,說回這個告警腳本,這個告警的原理是每10分鐘查一次數(shù)據(jù),看看線上404的告警會不會超過閾值,如果超出則告警到企業(yè)微信群。
一開始寫的時候就想到了一旦數(shù)據(jù)超出,那么每10分鐘就會收到一條告警,這樣工作群里就會充斥告警信息,污染了工作群的聊天記錄。所以還需要開發(fā)一個告警屏蔽功能,打開屏蔽功能后即使超出閾值,告警也不會繼續(xù)發(fā)送。
屏蔽功能簡單的實現(xiàn)就是在告警程序上加一個/close接口,只要調(diào)用接口并傳入對應(yīng)的定時腳本名稱,指定的定時腳本就會停止告警。再寫一個/open接口允許定時腳本繼續(xù)運行。
/close傳入的腳本名稱就需要保存在一個地方,這樣每次告警腳本運行的時候都判斷一次,是否要執(zhí)行當(dāng)前的告警腳本。那么,存在哪里合適呢?
說到存儲,最先想到的就是數(shù)據(jù)庫了,使用數(shù)據(jù)庫存取數(shù)據(jù)。但是一個數(shù)組大小的數(shù)據(jù),用數(shù)據(jù)庫就有點小題大做了。
第二種方法是腳本生成一個JSON文件,通過讀寫JSON文件里的配置,控制定時腳本的運行。這是個好辦法,但是程序手動讀寫文件總是給我一種“萬一讀寫出錯了怎么辦”的不安全感。于是我使用了第三種方法。
因為定時腳本是Egg.js寫的,Egg程序可以讀寫config這個屬性,那么我只要把需要屏蔽的腳本名保存為config里的一個屬性就可以了。于是,我在config里配置了一個disableSchedule屬性:
// config.default.js
export default = appInfo => {
const userConfig = {
// 關(guān)閉的告警
disableSchedule: [],
};
}
然后通過/close和/open讀寫disableSchedule數(shù)組,豈不是大功告成?而且本地測試的時候也是沒問題的。于是寫完后,第二天就上線了。
多進(jìn)程部署導(dǎo)致的讀取配置不一致
部署的時候,使用了egg默認(rèn)的npm run start讓程序成功運行了起來,功能上線的第一天晚上,404告警就出現(xiàn)了,但是個問題不大的404頁面,機智的我馬上開啟了告警屏蔽功能,沒想到10分鐘后,告警又出現(xiàn)了!再過10分鐘又一條!很顯然,保存在config里的配置并沒有成功生效,無奈只好手動先把定時腳本停止了再看問題出在哪。
調(diào)用/close 的時候,明顯配置是成功添加了,但是讀配置的時候,讀到的配置卻是空的,可以猜測到腳本可能是讀了一份“不一樣”的配置。一番檢查后發(fā)現(xiàn),有多個相同的腳本進(jìn)程在機器上運行,難道的egg默認(rèn)開啟了多進(jìn)程部署?查了一下文檔發(fā)現(xiàn)還真是:
啟動命令
$ egg-scripts start --port=7001 --daemon --title=egg-server-showcase
如上示例,支持以下參數(shù):
--workers=2 框架 worker 線程數(shù),默認(rèn)會創(chuàng)建和 CPU 核數(shù)相當(dāng)?shù)?app worker 數(shù),可以充分的利用 CPU 資源。
egg 默認(rèn)創(chuàng)建和 CPU 核數(shù)相當(dāng)?shù)?app worker 數(shù),這樣在調(diào)用接口改寫配置的時候,可能修改的是 worker1 的config,定時任務(wù)讀config的時候,讀到的卻是 worker2 的配置,導(dǎo)致修改的配置無效,除非統(tǒng)一把所有線程上的 config 都修改了?;蛘撸瑢⒕€程改為只啟動一個,修改配置:
// package.json
"scripts": {
"start": "egg-scripts start --daemon --workers=1 --title=egg-server-failUrl-schedule"
}
增加參數(shù)workers=1,將進(jìn)程設(shè)為1個,這樣定時任務(wù)就會只讀取 worker1 的配置,不會出現(xiàn)設(shè)置無效的問題了。