如何監(jiān)測微型的網(wǎng)站服務(wù)
你好! 我最近又開始運行一些服務(wù)器(??nginx playground???、??mess with dns???、??dns lookup??),所以我一直在考慮監(jiān)控問題。
最初我并不完全清楚如何監(jiān)控這些網(wǎng)站,所以我想快速寫下我是如何做到的。
我根本不打算談如何監(jiān)控大型的、嚴(yán)肅的關(guān)鍵任務(wù)網(wǎng)站,只談微型的不重要的網(wǎng)站。
目標(biāo):在操作上幾乎不花時間
我希望網(wǎng)站大部分時間都能正常工作,但我也希望不用在持續(xù)的運營上花費時間。
我最初對運行服務(wù)器非常警惕,因為在我的上一份工作中,我是 24/7 輪流值班,負(fù)責(zé)一些關(guān)鍵的服務(wù),在我的印象中,“負(fù)責(zé)服務(wù)器”意味著“在凌晨 2 點被叫起來修理服務(wù)器”和“有很多復(fù)雜的儀表盤”。
所以有一段時間我只做靜態(tài)網(wǎng)站,這樣我就不用考慮服務(wù)器的問題。
但最終我意識到,我所要寫的任何服務(wù)器的風(fēng)險都很低,如果它們偶爾宕機 2 小時也沒什么大不了的,我只需設(shè)置一些非常簡單的監(jiān)控來幫助它們保持運行。
沒有監(jiān)控很糟糕
起初,我根本沒有為我的服務(wù)器設(shè)置任何監(jiān)控。這樣做的結(jié)果是非??深A(yù)見的:有時網(wǎng)站壞了,而我卻沒有發(fā)現(xiàn),直到有人告訴我!
步驟 1:uptime 檢查器
第一步是建立一個 uptime 檢查器。外面有很多這樣的東西,我現(xiàn)在使用的是 ??updown.io?? 和 ??uptime robot??。我更喜歡 updown 的用戶界面和 ??定價?? 結(jié)構(gòu)(它是按請求而不是按月收費),但 uptime 機器人有一個更慷慨的免費套餐。
它們會:
- 檢查網(wǎng)站是否正常
- 如果出現(xiàn)故障,它會給我發(fā)電子郵件
我發(fā)現(xiàn)電子郵件通知對我來說是一個很好的通知級別,如果網(wǎng)站宕機,我會很快發(fā)現(xiàn),但它不會吵醒我或做其它的什么打擾。
步驟 2:端到端的健康檢查
接下來,讓我們談?wù)劇皺z查網(wǎng)站是否正?!钡降资鞘裁匆馑肌?/p>
起初,我只是把我的健康檢查端點之一變成一個函數(shù),無論如何都會返回 ??200 OK?
?。
這倒是挺有用的 – 它告訴我服務(wù)器是啟動著的!
但不出所料,我遇到了問題,因為它沒有檢查 API 是否真的在 工作 – 有時健康檢查成功了,盡管服務(wù)的其他部分實際上已經(jīng)進入了一個糟糕的狀態(tài)。
所以我更新了它,讓它真正地發(fā)出 API 請求,并確保它成功了。
我所有的服務(wù)都只做了很少的事情(nginx playground 只有一個端點),所以設(shè)置一個健康檢查是非常容易的,它實際上貫穿了服務(wù)應(yīng)該做的大部分動作。
下面是 nginx playground 的端到端健康檢查處理程序的樣子。它非?;荆核皇前l(fā)出一個 POST 請求(給自己),并檢查該請求是成功還是失敗。
func healthHandler(w http.ResponseWriter, r *http.Request) {
// make a request to localhost:8080 with `healthcheckJSON` as the body
// if it works, return 200
// if it doesn't, return 500
client := http.Client{}
resp, err := client.Post("http://localhost:8080/", "application/json", strings.NewReader(healthcheckJSON))
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if resp.StatusCode != http.StatusOK {
log.Println(resp.StatusCode)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}
健康檢查頻率:每小時一次
現(xiàn)在,我大部分健康檢查每小時運行一次,有些每 30 分鐘運行一次。
我每小時運行一次,因為 ??updown.io?? 的定價是按健康檢查次數(shù)計算的,我正在監(jiān)控 18 個不同的 URL,而且我想把我的健康檢查預(yù)算保持在 5 美元/年的最低水平。
花一個小時來發(fā)現(xiàn)這些網(wǎng)站中的一個出現(xiàn)故障,對我來說是可以的 – 如果有問題,我也不能保證能很快修復(fù)它。
如果可以更頻繁地運行它們,我可能會每 5-10 分鐘運行一次。
步驟 3:第三步:如果健康檢查失敗,自動重新啟動
我的一些網(wǎng)站在 ??fly.io?? 上,fly 有一個相當(dāng)標(biāo)準(zhǔn)的功能,我可以為一個服務(wù)配置一個 HTTP 健康檢查,如果健康檢查失敗,就重新啟動服務(wù)。
“經(jīng)常重啟”是一個非常有用的策略來彌補我尚未修復(fù)的 bug,有一段時間,nginx playground 有一個進程泄漏,??nginx?
? 進程沒有被終止,所以服務(wù)器的內(nèi)存一直在耗盡。
通過健康檢查,其結(jié)果是,每隔一天左右就會發(fā)生這樣的情況:
- 服務(wù)器的內(nèi)存用完了
- 健康檢查開始失敗
- 它被重新啟動
- 一切又正常了
- 幾個小時后再次重復(fù)整個傳奇
最終,我開始實際修復(fù)進程泄漏,但很高興有一個解決方法可以在我拖延修復(fù) bug 時保持運行。
這些用于決定是否重新啟動服務(wù)的運行狀況檢查更頻繁地運行:每 5 分鐘左右。
這不是監(jiān)控大型服務(wù)的最佳方式
這可能很明顯,我在一開始就已經(jīng)說過了,但是“編寫一個 HTTP 健康檢查”并不是監(jiān)控大型復(fù)雜服務(wù)的最佳方法。 但我不會深入討論,因為這不是這篇文章的主題。
到目前為止一直運行良好!
我最初在 3 個月前的四月寫了這篇文章,但我一直等到現(xiàn)在才發(fā)布它以確保整個設(shè)置正常工作。
這帶來了很大的不同 – 在我遇到一些非常愚蠢的停機問題之前,現(xiàn)在在過去的幾個月里,網(wǎng)站的運行時間達到了 99.95%!