嘗鮮初體驗(yàn):使用 Loggie 和 VictoriaLogs 快速構(gòu)建新一代的日志系統(tǒng)
如果你熟悉Prometheus,想必你肯定也知道VictoriaMetrics,這款越來(lái)越流行的監(jiān)控項(xiàng)目,可作為Prometheus的增強(qiáng)或者平替。VictoriaMetrics一個(gè)重要的亮點(diǎn)就是解決Prometheus在大規(guī)模Metrics指標(biāo)數(shù)據(jù)量級(jí)下的存儲(chǔ)問題。
同屬于可觀測(cè)性,當(dāng)我們把眼光聚焦到日志領(lǐng)域,其實(shí)很久以來(lái)日志的一個(gè)痛點(diǎn)是也是存儲(chǔ)。
當(dāng)前日志存儲(chǔ)的痛點(diǎn)
時(shí)下比較常見的一些開源日志存儲(chǔ)項(xiàng)目有:Elasticsearch、Clickhouse、Loki等。當(dāng)然,Elasticsearch和Clickhouse并非天生針對(duì)日志存儲(chǔ)而設(shè)計(jì),我們只是可以拿來(lái)存儲(chǔ)日志數(shù)據(jù)而已。
比如Elasticsearch的核心是一個(gè)搜索引擎。針對(duì)日志存儲(chǔ)的場(chǎng)景,可以全文檢索是一大優(yōu)勢(shì),但同時(shí)存在以下一些不足:
- 寫入性能相對(duì)慢
- 資源占用較高
- 針對(duì)日志存儲(chǔ)的壓縮差
總體來(lái)說(shuō),Elasticsearch是一款歷史悠久、被廣泛使用的日志存儲(chǔ)數(shù)據(jù)庫(kù),畢竟當(dāng)年ELK的概念深入人心。但是,在當(dāng)前降本增效的大背景下,很多企業(yè)還是會(huì)對(duì)Elasticsearch占用的機(jī)器資源比較敏感,如果只用于存儲(chǔ)大量的運(yùn)維類日志,性價(jià)比還是偏低。
所以前兩年Grafana家的Loki橫空出世,還是掀起了一點(diǎn)水花的,畢竟日志領(lǐng)域早就苦Elasticsearch久矣。
簡(jiǎn)單介紹一下Loki的優(yōu)點(diǎn):
- 天生就是為了存儲(chǔ)日志設(shè)計(jì)
- 資源占用還不錯(cuò)
- 引入了日志流Log Stream的概念
大半年前,我們公司內(nèi)部有部門開始嘗試使用Loki存儲(chǔ)一些系統(tǒng)日志。但總會(huì)遇到一些小問題,并不是很讓人放心。除此之外,Loki的不足之處還有:
- 沒有實(shí)際意義上的全文檢索,所以關(guān)鍵字查詢等可能會(huì)比較慢
- 不支持獨(dú)立設(shè)置檢索的label,可能導(dǎo)致性能等一系列問題
當(dāng)然,Loki還是一個(gè)相對(duì)年輕的項(xiàng)目,我們可以理解這些穩(wěn)定性、性能、設(shè)計(jì)上的問題可能是發(fā)展早期的陣痛。
但是,貌似很多人已經(jīng)等不及了。
姍姍來(lái)遲:VictoriaLogs的優(yōu)勢(shì)
最近VictoriaMetrics發(fā)布了預(yù)覽版的VictoriaLogs,類似Loki專門用于存儲(chǔ)日志。鑒于VictoriaMetrics的良好名聲,還是讓大家對(duì)這條攪局的「鯰魚」充滿了一定的期待。
VictoriaMetrics為什么要入局搞VictoriaLogs呢?
其實(shí)從2020年的這個(gè)Issues開始:https://github.com/VictoriaMetrics/VictoriaMetrics/issues/816
VictoriaMetrics就有了研發(fā)VictoriaLogs的想法。從該issues的討論中我們可以看出,大家對(duì)Loki還是有點(diǎn)微辭的,比如說(shuō)存儲(chǔ)依賴S3(本地存儲(chǔ)不支持分布式),比如說(shuō)性能。
這里節(jié)選一下issues里的吐槽:
almost 2 years passed and Loki is still unusable for scenarios with real logging data. Trying to query anything hitting more than 50k logs is exploding servers :)
不用翻譯了,隔著屏幕我們都能感受到這個(gè)用戶的強(qiáng)烈不滿。
時(shí)隔兩年多,VictoriaLogs終于正式來(lái)到了我們面前,那VictoriaLogs到底有哪些優(yōu)勢(shì),又能解決日志存儲(chǔ)領(lǐng)域的哪些問題呢?
這里我簡(jiǎn)略總結(jié)幾點(diǎn),感興趣的同學(xué)可以在[官方文檔]: https://docs.victoriametrics.com/VictoriaLogs/ 中尋找更多答案。
- 兼容Elasticsearch bulk接口
- 支持橫向和縱向擴(kuò)容
- 資源占用低
- 支持多租戶
- 繼承(抄)了Loki的log stream概念,但有一些優(yōu)化
- 支持全文檢索,提供了簡(jiǎn)單強(qiáng)大的LogsQL查詢語(yǔ)法
先說(shuō)VictoriaMetrics家的一大特色:兼容性。VictoriaLogs直接支持了Elasticsearch bulk API,由于市面上幾乎所有的日志采集Agent都支持發(fā)送至Elasticsearch,所以可以基本做到無(wú)縫對(duì)接和遷移,無(wú)需讓這些Agent都去研發(fā)增加新的輸出源。(這里確實(shí)要吐槽一下Loki,連個(gè)公開的客戶端Client SDK包都沒有提供,這讓人怎么對(duì)接呢)
但是支持橫向和縱向擴(kuò)容,這點(diǎn)由于現(xiàn)在VictoriaLogs預(yù)覽版只提供了單節(jié)點(diǎn)的,暫時(shí)還無(wú)法確認(rèn)。
另外在 資源占用 方面,我們可以直接看 VictoriaLogs提供的[benchmark]: https://github.com/VictoriaMetrics/VictoriaMetrics/tree/master/deployment/logs-benchmark 結(jié)果。對(duì)比Elasticsearch,從下圖可以看出:
- 平均內(nèi)存
- Elasticsearch:4.4 GiB
- VictoriaLogs:144 MiB
- 平均磁盤占用:
- Elasticsearch:53.9 GB
- VictoriaLogs:4.20 GB
內(nèi)存和磁盤占用確實(shí)要低太多,基本上是差了一個(gè)數(shù)量級(jí),如果存儲(chǔ)量大的話,能省下不少臺(tái)服務(wù)器的錢,無(wú)疑是現(xiàn)在降本增效患者的一大福音。
VictoriaLogs同樣引入了 log stream 的概念,結(jié)合多租戶的能力,似乎可以做到日志存儲(chǔ)場(chǎng)景下的性能、資源占用權(quán)衡下的最優(yōu)解,這也是VictoriaLogs區(qū)別于Elasticsearch等非專門為日志存儲(chǔ)設(shè)計(jì)數(shù)據(jù)庫(kù)的核心因素。
所以在使用VictoriaLogs之前,請(qǐng)務(wù)必先好好了解一下log stream。
log stream是什么呢?
簡(jiǎn)單來(lái)說(shuō),表示應(yīng)用(服務(wù))的一個(gè)日志實(shí)例。至于這個(gè)日志實(shí)例的具體粒度,可以由我們自行設(shè)計(jì)和掌控,但是不建議整體數(shù)量特別大。
舉例說(shuō)明,一個(gè)日志實(shí)例可以為:
- 主機(jī)部署下一個(gè)Linux進(jìn)程產(chǎn)生的日志
- Kubernetes上一個(gè)應(yīng)用運(yùn)行的Pod的Container容器產(chǎn)生的日志,或者更細(xì)粒度,容器里的一個(gè)日志文件也可以表示一個(gè)log stream
log stream設(shè)計(jì)的關(guān)鍵是可以被唯一標(biāo)識(shí),這樣可以確定日志在分布式系統(tǒng)中產(chǎn)生的位置,比如在哪個(gè)節(jié)點(diǎn)的哪個(gè)容器的哪個(gè)日志文件中。
一個(gè)log stream由多個(gè)label來(lái)標(biāo)識(shí),所以其實(shí)這里和Prometheus metrics的label類似,我們可以拿Prometheus中的一些概念類比:
- job label:表示多個(gè)副本上面的應(yīng)用,比如deployment名稱
- instance label:表示哪個(gè)進(jìn)程和端口號(hào)產(chǎn)生的metrics
在VictoriaLogs中也可以自己設(shè)計(jì)一些類似的label,加在日志采集的元信息中,這樣還能用于后續(xù)的日志和指標(biāo)的關(guān)聯(lián)和檢索。當(dāng)然在實(shí)際的應(yīng)用中,我們還可以增加諸如:環(huán)境、數(shù)據(jù)中心、namespace等的label。
如果你之前了解Loki,肯定會(huì)想說(shuō),Loki不也是這樣設(shè)計(jì)label的嗎?
對(duì),但是等你深入用過Loki后,可能會(huì)遇到這樣的坑:當(dāng)發(fā)送的日志labels里攜帶了一些頻繁修改的字段,比如說(shuō)一條日志,將其中的偏移量offset字段作為一個(gè)label,大概如下所示:
{
"message": "xxx",
"timestamp": "",
"logconfig": "foo",
"podname": "bar",
"offset": 20,
...
}
Loki會(huì)將所有l(wèi)abels的值作為一個(gè)唯一的log stream標(biāo)識(shí),比如上面的內(nèi)容就會(huì)將{logconfig: "foo", "podname":"bar", "offset": 20}作為一個(gè)log stream。由于在同一個(gè)文件中,offset會(huì)隨著采集的每行日志都在增加,因此會(huì)導(dǎo)致log stream個(gè)數(shù)無(wú)限增長(zhǎng),對(duì)Loki造成巨大的壓力。
為了規(guī)避這類問題,VictoriaLogs設(shè)計(jì)上就將stream label和普通label做了區(qū)分,比如以上這種場(chǎng)景,我們只需要將logconfig和podname作為stream label即可,offset則作為普通的label。
了解了stream label后,我們就可以更好的理解以下VictoriaLogs中的數(shù)據(jù)格式:
- _msg :日志內(nèi)容字段。
- _time :時(shí)間字段。
- _stream label:在同一個(gè)log stream中,label不變。
- 普通labels:在同一個(gè)log stream中可以變化,比如level, traceId等等。
真實(shí)世界:使用Loggie采集日志至VictoriaLogs中
下面我們開始真實(shí)的體驗(yàn)一下如何使用Loggie和VictoriaLogs快速構(gòu)建一套日志系統(tǒng)。
1、部署VictoriaLogs
可執(zhí)行以下命令:
helm repo add vm https://victoriametrics.github.io/helm-charts/
helm repo update
helm install vlsingle vm/victoria-logs-single -nvictoria-logs --create-namespace
更多的詳情可參考[helm chart部署]: https://github.com/VictoriaMetrics/helm-charts/blob/master/charts/victoria-logs-single/README.md。
這里我們?cè)O(shè)置部署的namespace為victoria-logs,如果修改了該namespace名稱,下面的一些配置也請(qǐng)同步修改。
2、部署Loggie
如果你還不知道Loggie,請(qǐng)進(jìn)[這里]: https://github.com/loggie-io/loggie。
為了方便起見,我們?cè)贚oggie catalog中提供了一個(gè)適配VictoriaLogs的部署配置。
VERSION=v1.4.0
helm pull https://github.com/loggie-io/installation/releases/download/$VERSION/loggie-$VERSION.tgz && tar xvzf loggie-$VERSION.tgz
# 從catalog中下載適配victoriaLogs所用的部署配置values文件
wget https://raw.githubusercontent.com/loggie-io/catalog/main/scenarios/victoriaLogs/values.yml
# 指定該values文件部署Loggie
helm install loggie ./loggie -nloggie --create-namespace -f values.yml
3、生成和采集日志
部署完了VictoriaLogs和Loggie后,創(chuàng)建一個(gè)測(cè)試用的Deployment genfiles用于產(chǎn)生日志。
wget https://raw.githubusercontent.com/loggie-io/catalog/main/common/genfiles/deployment.yml
kubectl apply -f deployment.yml
然后創(chuàng)建一個(gè)相匹配的日志采集任務(wù),告訴Loggie要去采集這個(gè)Deployment容器中的日志文件:
wget https://raw.githubusercontent.com/loggie-io/catalog/main/scenarios/victoriaLogs/genfiles_logconfig.yml
kubectl apply -f genfiles_logconfig.yml
這里我們重點(diǎn)關(guān)注下genfiles_logconfig.yml中的sink部分配置:
sink: |
type: elasticsearch
hosts: [ "vlsingle-victoria-logs-single-server.victoria-logs.svc:9428/insert/elasticsearch/" ]
parameters:
_msg_field: "body"
_time_field: "@timestamp"
_stream_fields: "logconfig,namespace,podname,containername"
- 直接使用的Elasticsearch類型的sink,因?yàn)閂ictoriaLogs兼容bulk接口
- 這里將hosts改成了VictoriaLogs的url,請(qǐng)注意后面加了固定的path: /insert/elasticsearch/
- 新增了parameters字段,兼容一下VictoriaLogs所需日志的格式,同時(shí)配置了stream labels字段
- _msg_field:表示使用哪個(gè)日志字段當(dāng)作msg內(nèi)容字段,Loggie默認(rèn)的日志內(nèi)容字段為body,如果你已經(jīng)在用Loggie并且修改成了其他字段,請(qǐng)對(duì)應(yīng)修改。
- _time_field:表示使用哪個(gè)字段作為時(shí)間字段。
- _stream_fields:表示使用哪些字段作為log stream的唯一標(biāo)識(shí)label。
在本示例中,我們?cè)趕ink端發(fā)送的日志格式大概如下所示:
{
"body": "2023-07-04 02:58:18.014 INF cmd/subcmd/genfiles/genfiles.go:57 > 1000 TqrccSCPzRUYRP PJ MlvgdAluEpIoRIRyzjZoNk",
"containername": "genfiles",
"namespace": "default",
"podname": "genfiles-66f5c86fdb-tjpzr",
"@timestamp": "2023-07-04T02:58:21.905Z",
"offset": 1092798,
"cluster": "test",
"logconfig": "genfiles",
"nodename": "kind-control-plane",
"filename": "/var/lib/kubelet/pods/c7b2da94-b152-414e-a7d8-1951e9d4f09a/volumes/kubernetes.io~empty-dir/logs/loggie.log"
}
可以看到,這里將log stream的粒度定為了Pod容器級(jí)別,所以_stream_fields設(shè)置為了cluster,logconfig,namespace,podname,containername。
現(xiàn)在我們模擬產(chǎn)生一點(diǎn)日志:
# 進(jìn)入到genfiles容器中
kubectl exec -it $(kubectl get po -l app=genfiles -o jsnotallow="{.items[0].metadata.name}") bash
# 產(chǎn)生一點(diǎn)日志
./loggie genfiles -totalCount=1000 -lineBytes=1024 -qps=0 \
-log.maxBackups=1 -log.maxSize=1000 -log.directory=/tmp/log -log.noColor=true \
-log.enableStdout=false -log.enableFile=true -log.timeFormat="2006-01-02 15:04:05.000"
關(guān)于loggie生成日志的genfiles子命令,更多的使用方式可以參考[這里]: https://github.com/loggie-io/catalog/tree/main/common/genfiles。
正常情況下,Loggie會(huì)很快采集這些日志,然后發(fā)送至VictoriaLogs。
當(dāng)然我們也可以進(jìn)入Loggie terminal控制臺(tái)確認(rèn)一下采集進(jìn)度:
kubectl -nloggie -it exec $(kubectl -nloggie get po -l app=loggie -o jsnotallow="{.items[0].metadata.name}") -- ./loggie inspect
如上圖所示,文件采集進(jìn)度為100%,表示已經(jīng)采集完畢,并且發(fā)送日志到了VictoriaLogs中。
Loggie terminal具體的操作方式,也可以參考我們的[日志采集快速排障指南]: https://loggie-io.github.io/docs/main/user-guide/troubleshot/log-collection/。
接下來(lái),我們就可以使用VictoriaLogs內(nèi)置的UI查看采集的日志了。
LogsQL和日志查詢
由于本地和Kubernetes集群內(nèi)部網(wǎng)絡(luò)不通,簡(jiǎn)單起見,我們直接port-forward一下:
export POD_NAME=$(kubectl get pods --namespace victoria-logs -l "app=server" -o jsnotallow="{.items[0].metadata.name}")
kubectl --namespace victoria-logs port-forward $POD_NAME 9428
然后本地訪問以下頁(yè)面:[http://localhost:9428/select/vmui/](http://localhost:9428/select/vmui/)。
VictoriaLogs當(dāng)前提供了一個(gè)簡(jiǎn)單的UI頁(yè)面,可用于查詢?nèi)罩?。為了演示如何查詢剛才采集的日志,我們先快速了解一下查詢語(yǔ)法。
考慮到最大化查詢的性能,建議一般寫LogsQL規(guī)范性套路為:
1、確定log stream
_stream這里的過濾字段,就是剛才在sink上parameters._stream_fields配置的,比如查詢哪個(gè)日志采集任務(wù),哪個(gè)Pod等。示例中我們根據(jù)log stream中的logconfig label查詢了剛才創(chuàng)建的日志采集任務(wù)下的所有日志,LogsQL如下:
_stream:{logcnotallow=genfiles}
如果logconfig匹配了很多的Pod,這里還可以加上對(duì)應(yīng)的podname等字段來(lái)進(jìn)一步過濾。比如:_stream:{logcnotallow=genfiles, podname="genfiles-66f5c86fdb-mrfzc"}。
2、加上時(shí)間區(qū)間
接著我們還可以增加時(shí)間區(qū)間,進(jìn)一步縮減返回的日志條數(shù)。
LogsQL: _stream:{logcnotallow=genfiles} _time:[now-1h,now]
請(qǐng)注意,這里通過空格來(lái)間隔,另外_stream和_time為內(nèi)置的字段,無(wú)先后順序區(qū)分。
3、進(jìn)一步的過濾
上面我們讓Victoria先快速確定一個(gè)log stream的日志范圍,然后在此基礎(chǔ)上,進(jìn)行關(guān)鍵字匹配,字段過濾等其他復(fù)雜的日志檢索。
比如:
- 關(guān)鍵字檢索:_stream:{logcnotallow=genfiles} _time:[now-1h,now] <關(guān)鍵字>。
- 根據(jù)普通的label字段來(lái)過濾:_stream:{logcnotallow=genfiles} _time:[now-1h,now] nodename:kind-control-plane。
- 還可以加上邏輯條件:AND, OR, NOT。
LogsQL的功能還是比較多的,更詳細(xì)的LogsQL使用姿勢(shì),可以參考[官方文檔]: https://docs.victoriametrics.com/VictoriaLogs/LogsQL.html。
總結(jié)
雖然 VictoriaLogs 只發(fā)布了一個(gè)預(yù)覽版,但是從當(dāng)前的設(shè)計(jì)和體驗(yàn)來(lái)看,還是要優(yōu)于 Loki 的,畢竟站在了 Loki 的肩膀上,有后發(fā)優(yōu)勢(shì)。
但是軟件設(shè)計(jì)沒有銀彈,真實(shí)的世界里,是否選擇使用某個(gè)項(xiàng)目,最重要的還是適不適合,而不在與項(xiàng)目本身功能是否強(qiáng)大。
可以預(yù)料到的是,在很長(zhǎng)的一段時(shí)間內(nèi),Elasticsearch這些老牌們還是會(huì)占據(jù)大部分的市場(chǎng),因?yàn)樵谄髽I(yè)中,很多都有已經(jīng)長(zhǎng)期穩(wěn)定運(yùn)行的Elasticsearch或者Clickhouse,同時(shí)還有相應(yīng)的運(yùn)維人員和配套支撐。
那什么情況適合VictoriaLogs呢?
如果你們正在從頭開始搭建自己的日志系統(tǒng),愿意接受新事物的潛在風(fēng)險(xiǎn),對(duì)VictoriaLogs的未來(lái)充滿信心,那么還是值得一試的。
正是由于VictoriaLogs這些新星們進(jìn)場(chǎng),讓日志領(lǐng)域更加內(nèi)卷的同時(shí),也讓廣大的人民群眾受益。畢竟我們多了一個(gè)不錯(cuò)的選擇,國(guó)內(nèi)的「開源定制化開發(fā)」市場(chǎng)又有更多的活可以干了。