摘要:快速搭建日志收集版本進行文章的第二次修改,包括了之前的簡單方案的升級過程。分割線快速搭建日志收集第一版本新項目短時間來實現日志采集。
快速搭建elk日志收集 kafka版本
進行文章的第二次修改,包括了之前的簡單方案的升級過程。
因為業務的不斷更新升級,為了保證線上業務也能正常使用elk服務,并且使得elk的服務和線業務流解耦(即避免直接寫入es的方式可能會帶來的耗時影響)所以我們采用了下面最新的方案,也是常規方案
方案業務層 >> kafka隊列 >> logstash 消費 >> elasticsearch
業務層將日志寫入到kafka隊列,同事logstash可以開啟多個線程,啟用同一個group_id來對kafka進行消費,將讀取到的日志進行解析后,寫入到elasticsearch中,并且按照索引模板進行解析。
優點業務層可以直接寫入到kafka隊列中,不用擔心elasticsearch的寫入效率問題。
缺點比起之前的簡單版本,需要保證kafka隊列、logstash的高可用(雖然logstash掛掉后,可以重啟后重新讀取隊列日志)
搭建整個搭建過程,寫入kafka是非常簡單的,這里遇到的問題是logstash和elasticsearch索引模板帶來的困擾。
logstash內置一套模板
elasticsearch 本身可以自定義一套模板
如何確定使用誰的模板呢?
網上找到的資料,建議采用將模板配置在elasticsearch側,這樣就不用每個logstash進行一個模板配置文件的維護。
官網的文檔kafka的input插件
https://www.elastic.co/guide/...
input { kafka { // 需要讀取的kafka隊列集群配置 bootstrap_servers => "xxx.xxx.xxx.xxx:9092" // 配置的消費者的group名稱,因為同一個組內的消費消息不會重復 group_id => "logstash-group" // 主題配置 topics => "kibana_log" // 從未消費過的偏移量開始 auto_offset_reset =>"earliest" } } // 重要,下面多帶帶講 filter { json { source => "message" } } output { // stdout可以省略,這個是為了命令行模式下方便調試 stdout{ codec => rubydebug } elasticsearch { // es 集群 hosts=>"xxx.xxx.xxx.xxx:9200" // 重要:取消logstash自定義模板功能,進而強制使用es的內置模板 manage_template=>false // 需要匹配的模板名稱 index=>"logstash-dev-%{+YYYY.MM.dd}" } }
先解釋下filter配置,當我們從kafka讀取消息的時候,消息體是通過message字段來進行傳遞的,所以message是一個字符串,但是我們的es索引模板可能會非常復雜,所以我們需要對其進行json解析后,再交給es。否則es收到的之后一個message字段。
filter { json { source => "message" } }
再說下模板配置,首先通過kibana的devtool向es中寫入了一個模板,我區分了兩套環境dev、prod。
Php 實現寫入這里字段都進行了strval轉義,為什么呢?這和下面要講的動態模板有關聯的。往下看
$position = YnUtil::getPosition(); $urlData = parse_url(Wii::app()->request->url); $path = $urlData["path"] ?? ""; $params = [ "category" => strval($category), "appType" => strval(YnUtil::getAppType()), "appVersion" => strval(YnUtil::getAppVersion()), "host" => strval(Wii::app()->request->hostInfo), "uri" => strval(Wii::app()->request->url), "uid" => strval(Wii::app()->user->getUid()), "path" => strval($path), "server" => strval(gethostname()), "geoip" => [ "ip" => strval(Yii::$app->request->userIP), "location" => [ "lat" => floatval($position["latitude"]), "lon" => floatval($position["longitude"]), ], ], "userAgent" => strval(Wii::app()->request->userAgent), "message" => is_array($message) ? Json::encode($message) : strval($message), // "@timestamp" => intval(microtime(true) * 1000), ];索引模板
下面的模板是寫入到es里面的自定義模板,為了防止索引規則名稱沖突,這里將order置為1。
我們先來看下第一個模板(這個是不推薦的,因為很繁瑣,但是類型很強制有效)
PUT _template/logstash-dev { "index_patterns": "logstash-dev*", "aliases": {}, "order":1, "mappings": { // 這里使用logs是因為logstash默認的type類型 "logs": { // 動態模板 "dynamic_templates": [ { "string_fields": { "match": "*", "match_mapping_type": "string", "mapping": { "fields": { "keyword": { "ignore_above": 256, "type": "keyword" } }, "norms": false, "type": "text" } } } ], // 這里對屬性進行了類型設置 "properties": { "@timestamp": { "type": "date" }, "@version": { "type": "keyword" }, "appType": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "appVersion": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "category": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "geoip": { "dynamic": "true", "properties": { "ip": { "type": "ip" }, "latitude": { "type": "half_float" }, "location": { "type": "geo_point" }, "longitude": { "type": "half_float" } } }, "host": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "message": { "type": "text", "norms": false }, "server": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "uid": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "uri": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "path": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "userAgent": { "type": "text", "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } } }, "settings": { "index": { "number_of_shards": "1" } } }動態模板概念
上面的模板不是最優的,但是卻是一種嘗試,模板里面針對每個屬性做了設置,這樣客戶端只需要寫入對應的屬性就好了。但是如何動態配置呢?如果想加入一個字段,難道還要修改模板么? 這里引入了動態模板的概念
Only the following datatypes can be automatically detected: boolean, date, double, long, object, string. It also accepts * to match all datatypes.
動態映射
https://www.elastic.co/guide/...
動態模板(注意看match和match_mapping_type)
https://www.elastic.co/guide/...
映射屬性
https://www.elastic.co/guide/...
然后我們給出了一個全新的模板
全新索引模板這個模板里面只針對特殊的屬性進行了設置,其他的都是通過動態模板擴展的,下面看下效果。
PUT _template/logstash-dev { "index_patterns": "logstash-dev*", "aliases": {}, "order":1, "mappings": { "logs": { "dynamic_templates": [ { "string_fields": { "match": "*", "match_mapping_type": "string", "mapping": { "fields": { "keyword": { "ignore_above": 256, "type": "keyword" } }, "norms": false, "type": "text" } } } ], "properties": { "@timestamp": { "type": "date" }, "@version": { "type": "keyword" }, "geoip": { "dynamic": "true", "properties": { "ip": { "type": "ip" }, "latitude": { "type": "half_float" }, "location": { "type": "geo_point" }, "longitude": { "type": "half_float" } } } } } }, "settings": { "index": { "number_of_shards": "1" } } }
我們上面說了,全都進行了strval轉義,為什么呢?因為動態模板里面,匹配的是string類型,如果我們寫入的是一個int類型,那么就不會進行自動擴展了。試驗后表明,會生成一個int類型的message字段,這樣是不合理的。最終生成的效果是如下圖的。
分割線 =============================
快速搭建elk日志收集 第一版本新項目短時間來實現日志采集。
資源一臺8G 4核 500G硬盤 服務器
部署方案項目部署在4臺服務器,每臺服務器通過phpsdk直接寫入一臺es服務器中。
(在本次部署中,沒有使用logstash的功能)
沒有使用異步隊列,導致直接寫入es可能會影響業務邏輯,但是目前只會在開發和測試環境使用。
組件主要利用elasticsearch 和 kibana
要使用x-pack做安全校驗,包括給kibana加入登錄授權功能
Elasticsearch
https://www.elastic.co/cn/pro...
Elasticsearch-clients
這里包含的多種語言的sdk包
https://www.elastic.co/guide/...
Kibana
https://www.elastic.co/cn/pro...
Logstash
https://www.elastic.co/cn/pro...
X-pack
安裝流程說明很詳細,秘鑰生成后記得保存下,并且加入x-pack后,kibana和elasticsearch的通訊,需要修改配置文件。另外phpsdk也需要加入秘鑰,后面說明。
https://www.elastic.co/cn/pro...
es的模板超級復雜的,所以我們要利用標準的現有的模板,需要從logstash中提取一個。
解壓下載的logstash-6.1.2.tar,執行搜索命令
$ find ./ -name "elasticsearch-template*" ./vendor/bundle/jruby/2.3.0/gems/logstash-output-elasticsearch-9.0.2-java/lib/logstash/outputs/elasticsearch/elasticsearch-template-es2x.json ./vendor/bundle/jruby/2.3.0/gems/logstash-output-elasticsearch-9.0.2-java/lib/logstash/outputs/elasticsearch/elasticsearch-template-es5x.json ./vendor/bundle/jruby/2.3.0/gems/logstash-output-elasticsearch-9.0.2-java/lib/logstash/outputs/elasticsearch/elasticsearch-template-es6x.json
會發現有2x 5x 6x三個模板,這里我們選擇6x,要根據你的es版本來選擇。
然后創建索引,索引要在數據寫入之前創建,因為要給每個字段設置類型。
https://www.elastic.co/guide/...
按照文檔的方式,將獲取到的6x通過curl的方式寫入到es
Es開啟外網訪問因為默認的es配置是開啟了localhost:9200端口,用于執行RESTFUL,但是本次我們采用php-sdk的方式,直接寫入es,就要求每臺業務服務器,都能訪問到es。
# ---------------------------------- Network ----------------------------------- # # Set the bind address to a specific IP (IPv4 or IPv6): # 修改此處的host配置為0.0.0.0,這樣所有的請求都可以接入進來 network.host: 0.0.0.0 # # Set a custom port for HTTP: # #http.port: 9200使用client sdk
下載地址
https://www.elastic.co/guide/...
try { $hosts = [ // 這個地方要填寫x-pack分配的密碼和用戶名 "http://{用戶名}:{密碼}@192.168.1.11:9200", // HTTP Basic Authentication // "http://user2:pass2@other-host.com:9200" // Different credentials on different host ]; $client = ClientBuilder::create()->setHosts($hosts)->build(); $position = YnUtil::getPosition(); $params = [ "index" => "logstash-yn-" . date("Ymd"), // elastic6版本有個bug,每個索引只能有一個type類型 "type" => "xxxx", "id" => md5(rand(0, 999999999)) . (microtime(true) * 1000), "body" => [ // 索引創建好后,寫入數據一定要注意類型,不然會報錯,我這里都會進行格式化一遍 // 類別作為一個主要字段用于區分日志 "category" => strval($category), "appType" => strval(YnUtil::getAppType()), "appVersion" => strval(YnUtil::getAppVersion()), "host" => strval($hostInfo), "uri" => strval($url), "uid" => strval($user->getUid()), "server" => strval(gethostname()), "geoip" => [ "ip" => strval($ip), // 這個很重要,可以實現geo可視化圖形 "location" => [ "lat" => floatval($position["latitude"]), "lon" => floatval($position["longitude"]), ], ], "userAgent" => strval($userAgent), "message" => Json::encode($message), // 這里一定要寫入毫秒時間戳 "@timestamp" => intval(microtime(true) * 1000), ], ]; $client->index($params); } catch (Exception $e) { }
安裝好x-pack后,sdk也要配置用戶名和密碼
日志的索引,按照日期來構建名稱
elastic6版本,每個索引只能有一個type類型,這是一個bug
geoip是logstash的模板中定義的字段,可以實現geo可視化(稍后解釋模板)
@timestamp 這里一定要毫秒時間戳
要捕獲報錯日志,不要影響業務邏輯
模板說明官方說明
https://www.elastic.co/guide/...
我們這里以6x作為模板
{ // 將這個模板應用于所有以 logstash- 為起始的索引。 "template": "logstash-*", "version": 60001, "settings": { "index.refresh_interval": "5s" }, "mappings": { "_default_": { // 動態模板說明,很重要,配置了動態模板后,我們可以添加任意字段 // https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic-templates.html "dynamic_templates": [{ // 信息字段 官方說這里可以自定義 The template name can be any string value. "message_field": { "path_match": "message", "match_mapping_type": "string", "mapping": { "type": "text", "norms": false } } }, { // 字符串字段說明 "string_fields": { // 匹配所有 "match": "*", // 并且字段類型是string的 "match_mapping_type": "string", // "mapping": { "type": "text", // 這里應該是和受歡迎程度評分相關 "norms": false, "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } }], // 定義好的屬性說明 "properties": { // 時間字段,這個很重要,不然kibana不會出現時間相關的查詢控件 "@timestamp": { "type": "date" }, "@version": { "type": "keyword" }, // 這個可以只寫入properies里面的任意一個字段 "geoip": { "dynamic": true, "properties": { "ip": { "type": "ip" }, // 我只是用了這個location "location": { "type": "geo_point" }, "latitude": { "type": "half_float" }, "longitude": { "type": "half_float" } } } } } } }遇到的問題 索引創建太復雜怎么辦?
使用logstash內置的模板
添加了時間字段后,創建數據不顯示?檢查是否是毫秒時間戳
安裝x-pack后,clientsdk向es寫入數據報錯,提示校驗失敗?需要在鏈接中添加用戶名和密碼
類型和模板不匹配導致錯誤?寫入類型,一定要和索引模板中定義的一致,不然肯定報錯!
同一個索引,添加多個type報錯?elasticsearch6的 bug,官方承諾在7進行修復
kibana加入登錄驗證?安裝x-pack吧
如何保證高可用,無人值守?使用supervisor
如何清理elasticsearch老數據?我的方案是:定時腳本來清理7天之前的索引DELETE logstash-xxxx
如何快速執行curl查詢?在kibana中有一個Dev Tools 可以執行curl,并且看到結果
如何格式化kibana的日期格式?在kibana菜單的Management->Index Patterns中可以管理
結束不詳細的地方,可以留言
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/28196.html
摘要:日志監控和分析在保障業務穩定運行時,起到了很重要的作用。本文搭建的的是一個分布式的日志收集和分析系統。對于隊列上的這些未處理的日志,有不同的幾臺進行接收和分析。再由統一的進行日志界面的展示。如等配置文件可以配置,等日志報表可視化熟練 ELK簡介ELKStack即Elasticsearch + Logstash + Kibana。日志監控和分析在保障業務穩定運行時,起到了很重要的作用。比...
閱讀 3027·2023-04-25 18:06
閱讀 3272·2021-11-22 09:34
閱讀 2857·2021-08-12 13:30
閱讀 2045·2019-08-30 15:44
閱讀 1661·2019-08-30 13:09
閱讀 1630·2019-08-30 12:45
閱讀 1715·2019-08-29 11:13
閱讀 3608·2019-08-28 17:51