1. 背景與痛點
在開發分佈式系統時,日誌分散在多個服務節點中,傳統輪詢查詢方式存在延遲高、資源浪費的問題。某次線上故障中,因未能實時發現錯誤日誌,導致問題排查時間延長2小時。因此,決定自研一套低成本、實時性高的日誌監控系統。
2. 技術選型
- 數據存儲:Elasticsearch(高效檢索與聚合)
- 實時推送:WebSocket(全雙工通信,避免HTTP輪詢)
- 後端服務:Node.js + Express(輕量級,適合快速開發)
- 前端展示:Vue.js + ECharts(可視化日誌趨勢)
3. 核心實現步驟
(附代碼片段與關鍵配置)
3.1 Elasticsearch索引設計
json// 日誌索引模板(按時間分片)
PUT /log-template
{
"index_patterns": ["logs-*"],
"settings": {
"number_of_shards": 3
},
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"level": { "type": "keyword" },
"message": { "type": "text", "analyzer": "ik_max_word" }
}
}
}
// 日誌索引模板(按時間分片)
PUT /log-template
{
"index_patterns": ["logs-*"],
"settings": {
"number_of_shards": 3
},
"mappings": {
"properties": {
"timestamp": { "type": "date" },
"level": { "type": "keyword" },
"message": { "type": "text", "analyzer": "ik_max_word" }
}
}
}
3.2 WebSocket服務端實現
javascript// Node.js WebSocket服務器
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
console.log('New client connected');
// 訂閲Elasticsearch日誌變更(通過_changes API或輪詢模擬)
setInterval(() => {
// 模擬獲取新日誌(實際可通過ES的search_after或滾動查詢)
const newLogs = fetchNewLogsFromES();
ws.send(JSON.stringify(newLogs));
}, 1000);
});
// Node.js WebSocket服務器
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
console.log('New client connected');
// 訂閲Elasticsearch日誌變更(通過_changes API或輪詢模擬)
setInterval(() => {
// 模擬獲取新日誌(實際可通過ES的search_after或滾動查詢)
const newLogs = fetchNewLogsFromES();
ws.send(JSON.stringify(newLogs));
}, 1000);
});
3.3 前端實時渲染優化
javascript// Vue.js WebSocket客户端
const socket = new WebSocket('ws://localhost:8080');
socket.onmessage = (event) => {
const logs = JSON.parse(event.data);
// 使用虛擬滾動列表優化性能(避免DOM爆炸)
this.logs.unshift(...logs); // 追加到列表頂部
if (this.logs.length > 1000) this.logs.pop(); // 限制數量
};
// Vue.js WebSocket客户端
const socket = new WebSocket('ws://localhost:8080');
socket.onmessage = (event) => {
const logs = JSON.parse(event.data);
// 使用虛擬滾動列表優化性能(避免DOM爆炸)
this.logs.unshift(...logs); // 追加到列表頂部
if (this.logs.length > 1000) this.logs.pop(); // 限制數量
};
4. 性能優化與坑點
- ES查詢優化:使用
search_after替代from/size,避免深度分頁性能問題。 - WebSocket斷連重試:前端實現指數退避重連機制。
- 數據壓縮:對大文本日誌啓用Gzip壓縮,減少帶寬佔用。
5. 最終效果
- 實時性:日誌從產生到展示延遲 < 1秒
- 吞吐量:單WebSocket連接支持500條/秒日誌推送
- 成本:3節點ES集羣(4C16G)可支撐日誌量100GB/天
6. 擴展思考
- 如何結合Prometheus實現告警閾值動態配置?
- 針對海量日誌場景,是否需要引入Kafka作為消息隊列?