本文講解夜鶯(Nightingale)的架構設計。包括中心化叢集的設計以及邊緣機房下沉部署模式。
夜鶯的架構比較簡單,如果只是測試功能,一個二進位就可以啟動,如果要上到生產環境,則要相依 MySQL 和 Redis。有些公司會有多個機房,有些邊緣機房和中心機房的網路品質較差,夜鶯也針對這種情況做了專門的設計。
架構圖
不考慮邊緣模式的話,夜鶯只有一個主程序,即 n9e 程序,相依 MySQL 和 Redis 儲存一些管理資料,可以接入多種資料來源,技術架構圖示意如下:

初期支援的資料來源:Prometheus、VictoriaMetrics、ElasticSearch,既支援看圖也支援告警,後面夜鶯側重在做告警引擎,所以後面新支援的資料來源就只支援告警。
根據監控資料是否流經夜鶯,可以分成兩個模式:
- 模式1:監控資料不流經夜鶯,使用者自己搞定資料採集的問題,僅把時序庫設定到夜鶯裡,使用夜鶯看圖和設定告警。機器列表為空、即沒法給機器分組沒法使用故障自愈(因為沒有部署 Categraf),但仍然可以使用類似 Prometheus 的告警規則設定。上面的架構圖就是典型的這種模式。
- 模式2:資料流經夜鶯,Categraf 透過 remote write 協定把資料推給夜鶯,夜鶯不直接儲存資料,而是把資料轉存到時序庫,轉存到哪些時序庫?由夜鶯設定檔 config.toml 中的
Pushgw.Writers來決定,模式2下的架構圖如下:

上圖中,夜鶯接到監控資料之後轉發給了 VictoriaMetrics,當然,也可以轉發給 Prometheus,如果要轉發給 Prometheus,記得 Prometheus 啟動的時候要開啟 remote receiver 的功能(./prometheus --help | grep receiver 可以看到具體是要加哪個控制參數),即開啟 Prometheus 的 /api/v1/write 介面。
🟢 如果是新使用者,建議直接使用 VictoriaMetrics,VictoriaMetrics 效能更好,且支援叢集模式,而且,和 Prometheus 介面相容。不過 VictoriaMetrics 的中文資料比 Prometheus 更少一些。
單節點測試模式
從夜鶯的 github releases 下載發佈包,解壓之後裡邊有個 n9e 二進位檔案,直接 ./n9e 就可以執行起來,預設連接埠是 17000,預設使用者名稱是 root,密碼是 root.2020。
n9e 程序只相依二進位同級目錄的 etc 和 integrations 目錄,不相依其他任何服務。
在這種單機模式下,方便做快速測試,不過不建議用於生產環境。此種模式下,夜鶯會把設定類資料(比如使用者資訊、告警規則、儀表板等)儲存在本地的 SQLite 資料庫檔案中,所以 n9e 程序啟動之後,同級目錄下會生成一個 n9e.db 的 SQLite 資料庫檔案。
單節點生產模式
如果要上到生產環境,則需要相依 MySQL 和 Redis。所以,需要在設定檔 etc/config.toml 中設定 MySQL 和 Redis 的連線資訊。
MySQL 的關鍵設定範例:
[DB]
DBType = "mysql"
DSN = "root:YourPa55word@tcp(localhost:3306)/n9e_v6?charset=utf8mb4&parseTime=True&loc=Local"
上面 DSN(連線字串)的格式是 使用者名稱:密碼@tcp(位址:連接埠)/資料庫名?參數,其中 n9e_v6 是夜鶯的資料庫名,從 V6 版本開始,就一直習慣使用這個名字了(即便現在是 V8+ 版本了),建表語句裡也一直延用了這個名字。
Redis 的關鍵設定範例:
[Redis]
Address = "127.0.0.1:6379"
RedisType = "standalone"
上面只是給了最基礎的設定範例,設定檔中還有很多其他設定項,具體可以參考設定檔中的註解,也可以參考這裡的設定檔說明。
夜鶯叢集
叢集模式很簡單,只需要搞多台機器,每台機器都部署 n9e 程序(程序要想正常工作相依 etc 和 integrations 目錄),多個 n9e 的設定檔確保完全一致,共用同一套 MySQL 和 Redis,即可。
多個 n9e 程序會自動分派告警規則,比如有 2 個 n9e 程序,使用者共設定了 100 條告警規則,夜鶯會自動把這 100 條告警規則分配到 2 個 n9e 程序上,每個程序大概 50 條告警規則(一個規則只會在某一個 n9e 實例上執行,不會重複告警)。如果某個機器掛了,另一個機器上的 n9e 會接管它的告警規則,繼續工作。
邊緣模式
上面講到的幾種模式,都是中心化模式,但實際生產環境裡,可能會有多個機房,中心機房和邊緣機房的網路品質可能不太好,如果讓中心機房的 n9e 負責邊緣機房的某個時序庫的告警,會不穩定,有時甚至 n9e 直接連不通邊緣機房的時序庫,這時就需要夜鶯的邊緣機房下沉部署模式。

我們這裡假設貴司有 3 個機房:中心主力機房、邊緣機房 A 和邊緣機房 B,其中邊緣機房 A 和中心機房之間有專線,網路鏈路很好,邊緣機房 B 和中心機房之間沒有專線,走公網,網路鏈路不夠可靠。
n9e 程序部署在中心主力機房,n9e 相依 mysql 和 redis,所以 mysql 和 redis 也部署在中心主力機房。如果你想做高可用,中心機房的 n9e 可以部署多個實例,設定檔保持一致,連同一個 mysql 和 redis 即可。
上圖中,我們有 5 個資料來源:
- 中心機房有一套 Loki,一套 ElasticSearch
- 邊緣機房 A 有一套 ElasticSearch,一套 Prometheus
- 邊緣機房 B 有一套 VictoriaMetrics
我們希望在中心 n9e 統一檢視這 5 個資料來源的資料,所以要把這 5 個資料來源的存取位址設定到夜鶯中,選單位置:整合中心-資料來源。
中心 n9e 可以透過內網位址直接連通中心機房和邊緣機房 A 的資料來源,但是無法直接連通邊緣機房 B 的資料來源(因為沒有專線),那只能把邊緣機房 B 的 VictoriaMetrics 暴露一個公網位址出來,中心 n9e 透過公網位址存取邊緣機房 B 的 VictoriaMetrics,即:
- 機房 B 的 VictoriaMetrics 暴露公網存取位址,比如為:https://ex.a.com
- 在夜鶯的 WEBUI 上設定資料來源時,把機房 B 的 VictoriaMetrics 的 URL 設定為:https://ex.a.com
架構圖中的 1、2、3、4、5 這 5 條線,表示中心 n9e 和 5 個資料來源的連線關係。使用者在查詢資料的時候,是在 n9e 的 web 上查的,發請求給 n9e 程序,n9e 程序此時相當於一個 proxy,把請求代理給後端的各個資料來源,然後把資料來源的資料回傳給使用者。
n9e-edge 部署在邊緣機房 B,用於處理 B 機房 VictoriaMetrics 的告警判定,n9e-edge 會從中心 n9e 同步告警規則(即圖中的 A 那條線),然後把告警規則快取在記憶體裡,對本機房的 VictoriaMetrics 做告警判定工作。這樣的架構下,n9e-edge 和 VictoriaMetrics 是內網連通的,所以告警比較可靠,另外即便 n9e-edge 連不通中心機房的 n9e 了,也不影響 B 機房的告警判定工作,因為 n9e-edge 記憶體中已經快取了告警規則。
n9e-edge 產生的告警事件會呼叫 n9e 的介面寫回中心 mysql,呼叫釘釘、飛書、Flashduty 等的介面發送通知。如果 n9e-edge 和 n9e 之間網路斷了,告警事件就寫不到 mysql 了,但是只要 n9e-edge 所在機房的外網出口是好的,告警通知還是可以發出去的。
架構圖中:
- 中心機房的 n9e 負責中心機房的 Loki、ElasticSearch 的告警判定,也負責機房 A 的 ElasticSearch 和 Prometheus 的告警判定
- 邊緣機房 B 的 n9e-edge 負責機房 B 的 VictoriaMetrics 的告警判定
那如何指定不同的資料來源和告警引擎之間的關聯關係呢?其實是在資料來源的管理頁面:

上圖中:
- URL 是中心 n9e 讀取資料的位址,在上例架構中,需要設定為 B 機房 VictoriaMetrics 的公網位址
- 時序庫內網位址是 n9e-edge 連線 VictoriaMetrics 的位址,如果 URL 已經是一個內網位址了,這個設定項就可以留空,留空之後 n9e-edge 就會使用 URL 中的位址。上例中,由於 n9e-edge 和 VictoriaMetrics 在同一個機房,所以這個位址應該設定為內網位址,這樣告警判定更可靠
- Remote Write URL 是 VictoriaMetrics 的 remote write 寫入位址,用於記錄規則,即 recording rule,n9e-edge 負責處理記錄規則,把結果寫回時序庫,所以需要知道時序庫的 remote write 位址,因為是給 n9e-edge 用的,所以使用內網位址。如果你沒有用到夜鶯的記錄規則,這裡可以不用設定
- 關聯告警引擎叢集,上圖選擇的是 edge-b,這是 B 機房 n9e-edge 的名字(由 edge.toml 的 EngineName 欄位指定),這樣設定之後,就建立了 B 機房 n9e-edge 和 B 機房 VictoriaMetrics 之間的關聯關係,就會由這個 n9e-edge 來處理 B 機房 VictoriaMetrics 的告警規則和記錄規則
新版本的夜鶯,n9e-edge 相依一個 redis,所以需要在 B 機房部署一個 redis 給 n9e-edge 使用,注意,n9e-edge 所用的 redis 和中心機房 n9e 所用的 redis 不是一個。架構圖中我特意標註了 R1、R2 兩個名字,表示兩個 redis,分別給 n9e 和 n9e-edge 使用。
最後說一下 categraf,如果網路鏈路比較好,categraf 可以把資料直接上報到中心機房的 n9e,比如中心機房和 A 機房的 categraf 都可以直接對接到中心機房的 n9e,但是 B 機房部署了 n9e-edge,那 B 機房的 categraf 就應該對接到 B 機房的 n9e-edge。
設定範例
要達到上述架構,各個元件的設定檔應該如何設定?這裡給出一個範例。
中心機房 n9e 設定
中心機房 n9e 的預設設定檔是 etc/config.toml:
[HTTP.APIForService]
Enable = true
[HTTP.APIForService.BasicAuth]
user001 = "ccc26da7b9aba533cbb263a36c07dcc5"
user002 = "ccc26da7b9aba533cbb263a36c07dcc6"
重點就是 HTTP.APIForService 這塊的設定。預設 Enable 是 false 是為了安全考慮,即預設不支援 n9e-edge 架構,如果要支援,需要改成 true。n9e-edge 呼叫 n9e 的介面時,可以使用 BasicAuth 認證,即 HTTP.APIForService.BasicAuth 下面的部分,上例中設定了兩個使用者,分別是 user001 和 user002,密碼是 ccc26da7b9aba533cbb263a36c07dcc5 和 ccc26da7b9aba533cbb263a36c07dcc6。其實設定一個使用者就行,我設定兩個只是為了演示。另外,如果你的 n9e 暴露在公網,千萬要修改 BasicAuth 的預設密碼,不然很容易被攻擊。
邊緣機房 n9e-edge 設定
邊緣機房 n9e-edge 的預設設定檔是 etc/edge/edge.toml,首先 n9e-edge 要呼叫中心 n9e 的介面,所以要設定中心 n9e 的位址:
[CenterApi]
Addrs = ["http://N9E-CENTER-SERVER:17000"]
BasicAuthUser = "user001"
BasicAuthPass = "ccc26da7b9aba533cbb263a36c07dcc5"
# unit: ms
Timeout = 9000
N9E-CENTER-SERVER:17000 表示中心 n9e 的位址,你按照自己的環境調整即可。BasicAuthUser 和 BasicAuthPass 是中心 n9e 的 BasicAuth 使用者名稱和密碼,如果中心 n9e 沒有開啟 BasicAuth,這兩個欄位可以不填。還是那句話,千萬要修改 BasicAuth 的預設密碼,不然很容易被攻擊。
新版本 n9e-edge 相依 redis,所以要設定 redis 位址,預設應該是在 edge.toml 的最下面,自行修改即可。如果你是老版本,不相依 redis,那就不用設定了。如何分辨你的版本的 n9e-edge 是否相依 redis?就看你下載下來的 edge.toml 預設設定中是否帶有 redis 設定,帶了就說明相依 redis。
邊緣機房 categraf 設定
主要是注意 2 個地方,writer 的位址和 heartbeat 的位址,都設定為 n9e-edge 的位址:
...
[[writers]]
url = "http://N9E-EDGE:19000/prometheus/v1/write"
...
[heartbeat]
enable = true
# report os version cpu.util mem.util metadata
url = "http://N9E-EDGE:19000/v1/n9e/heartbeat"
...
N9E-EDGE:19000 表示 n9e-edge 的位址,注意,n9e-edge 預設監聽的連接埠是 19000,也可以在 edge.toml 中自行修改。
ibex 設定
ibex 部分,即故障自愈的功能,這個功能有些公司擔心安全問題不開放。如果你們要開啟這個功能,同樣的道理,在 edge.toml 中開啟:
[Ibex]
Enable = true
RPCListen = "0.0.0.0:20090"
然後邊緣機房的 categraf 連邊緣機房的 n9e-edge 的 20090 連接埠即可,即 categraf 的 config.toml 要做如下設定:
[ibex]
enable = true
## ibex flush interval
interval = "1000ms"
## n9e ibex server rpc address
servers = ["N9E-EDGE-IP:20090"]
## temp script dir
meta_dir = "./meta"
N9E-EDGE-IP:20090 表示 n9e-edge 的 RPC 位址。注意這是 RPC 位址,不是 HTTP 位址,所以,不要在 N9E-EDGE-IP 前面畫蛇添足加上 http:// 啦。
其他適用場景
除了網路鏈路不好的場景之外,有時為了安全考慮,網路也會有分區,比如某個網路區域只有一台中轉機可以連通中心的 n9e,其他機器都不能連通,這時候就可以在中轉機上部署 n9e-edge,然後其他機器的 categraf 連中轉機的 n9e-edge 即可。