精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

還在用ELK?是時(shí)候了解一下輕量化日志服務(wù)Loki了

開發(fā) 前端 開發(fā)工具
Loki 作為一個(gè)新興的日志解決方案,現(xiàn)在越來越受到關(guān)注。經(jīng)過調(diào)研比較,我們正在將日志服務(wù)底層逐步從 ES 替換為 Loki 。

[[359207]]

圖片來自 Pexels

本文基于我們對 Loki 的使用和理解,從它產(chǎn)生的背景、解決的問題、采用的方案、系統(tǒng)架構(gòu)、實(shí)現(xiàn)邏輯等做一些剖析,希望對關(guān)注 Loki 的小伙伴們提供一些幫助。

在日常的系統(tǒng)可視化監(jiān)控過程中,當(dāng)監(jiān)控探知到指標(biāo)異常時(shí),我們往往需要對問題的根因做出定位。

但監(jiān)控?cái)?shù)據(jù)所暴露的信息是提前預(yù)設(shè)、高度提煉的,在信息量上存在著很大的不足,它需要結(jié)合能夠承載豐富信息的日志系統(tǒng)一起使用。

當(dāng)監(jiān)控系統(tǒng)探知到異常告警,我們通常在 Dashboard 上根據(jù)異常指標(biāo)所屬的集群、主機(jī)、實(shí)例、應(yīng)用、時(shí)間等信息圈定問題的大致方向,然后跳轉(zhuǎn)到日志系統(tǒng)做更精細(xì)的查詢,獲取更豐富的信息來最終判斷問題根因。

在如上流程中,監(jiān)控系統(tǒng)和日志系統(tǒng)往往是獨(dú)立的,使用方式具有很大差異。比如監(jiān)控系統(tǒng) Prometheus 比較受歡迎,日志系統(tǒng)多采用 ES+Kibana 。

他們具有完全不同的概念、不同的搜索語法和界面,這不僅給使用者增加了學(xué)習(xí)成本,也使得在使用時(shí)需在兩套系統(tǒng)中頻繁做上下文切換,對問題的定位遲滯。

此外,日志系統(tǒng)多采用全文索引來支撐搜索服務(wù),它需要為日志的原文建立反向索引,這會導(dǎo)致最終存儲數(shù)據(jù)相較原始內(nèi)容成倍增長,產(chǎn)生不可小覷的存儲成本。

并且,不管數(shù)據(jù)將來是否會被搜索,都會在寫入時(shí)因?yàn)樗饕僮鞫加么罅康挠?jì)算資源,這對于日志這種寫多讀少的服務(wù)無疑也是一種計(jì)算資源的浪費(fèi)。

Loki 則是為了應(yīng)對上述問題而產(chǎn)生的解決方案,它的目標(biāo)是打造能夠與監(jiān)控深度集成、成本極度低廉的日志系統(tǒng)。

Loki 日志方案

低使用成本

①數(shù)據(jù)模型

在數(shù)據(jù)模型上,Loki 參考了 Prometheus ,數(shù)據(jù)由標(biāo)簽、時(shí)間戳、內(nèi)容組成,所有標(biāo)簽相同的數(shù)據(jù)屬于同一日志流:

  • 標(biāo)簽,描述日志所屬集群、服務(wù)、主機(jī)、應(yīng)用、類型等元信息, 用于后期搜索服務(wù)。
  • 時(shí)間戳,日志的產(chǎn)生時(shí)間。
  • 內(nèi)容,日志的原始內(nèi)容。

具有如下結(jié)構(gòu):

  1.   "stream": {  
  2.     "label1""value1"
  3.     "label1""value2" 
  4.   }, # 標(biāo)簽 
  5.   "values": [ 
  6.     ["<timestamp nanoseconds>","log content"], # 時(shí)間戳,內(nèi)容 
  7.     ["<timestamp nanoseconds>","log content"
  8.   ] 

Loki 還支持多租戶,同一租戶下具有完全相同標(biāo)簽的日志所組成的集合稱為一個(gè)日志流。

在日志的采集端使用和監(jiān)控時(shí)序數(shù)據(jù)一致的標(biāo)簽,這樣在可以后續(xù)與監(jiān)控系統(tǒng)結(jié)合時(shí)使用相同的標(biāo)簽,也為在 UI 界面中與監(jiān)控結(jié)合使用做快速上下文切換提供數(shù)據(jù)基礎(chǔ)。

LogQL:Loki 使用類似 Prometheus 的 PromQL 的查詢語句 logQL ,語法簡單并貼近社區(qū)使用習(xí)慣,降低用戶學(xué)習(xí)和使用成本。

語法例子如下:

  1. {file="debug.log""} |= "err" 

流選擇器:{label1="value1", label2="value2"}, 通過標(biāo)簽選擇日志流, 支持等、不等、匹配、不匹配等選擇方式。過濾器:|= "err",過濾日志內(nèi)容,支持包含、不包含、匹配、不匹配等過濾方式。

這種工作方式類似于 find+grep,find 找出文件,grep 從文件中逐行匹配:

  1. find . -name "debug.log" | grep err 

logQL 除支持日志內(nèi)容查詢外,還支持對日志總量、頻率等聚合計(jì)算。

Grafana:在 Grafana 中原生支持 Loki 插件,將監(jiān)控和日志查詢集成在一起,在同一 UI 界面中可以對監(jiān)控?cái)?shù)據(jù)和日志進(jìn)行 side-by-side 的下鉆查詢探索,比使用不同系統(tǒng)反復(fù)進(jìn)行切換更直觀、更便捷。

此外,在 Dashboard 中可以將監(jiān)控和日志查詢配置在一起,這樣可同時(shí)查看監(jiān)控?cái)?shù)據(jù)走勢和日志內(nèi)容,為捕捉可能存在的問題提供更直觀的途徑。

低存儲成本

只索引與日志相關(guān)的元數(shù)據(jù)標(biāo)簽,而日志內(nèi)容則以壓縮方式存儲于對象存儲中, 不做任何索引。

相較于 ES 這種全文索引的系統(tǒng),數(shù)據(jù)可在十倍量級上降低,加上使用對象存儲,最終存儲成本可降低數(shù)十倍甚至更低。

方案不解決復(fù)雜的存儲系統(tǒng)問題,而是直接應(yīng)用現(xiàn)有成熟的分布式存儲系統(tǒng),比如 S3、GCS、Cassandra、BigTable 。

Loki 架構(gòu)

整體上 Loki 采用了讀寫分離的架構(gòu),由多個(gè)模塊組成:

  • Promtail、Fluent-bit、Fluentd、Rsyslog 等開源客戶端負(fù)責(zé)采集并上報(bào)日志。
  • Distributor:日志寫入入口,將數(shù)據(jù)轉(zhuǎn)發(fā)到 Ingester。
  • Ingester:日志的寫入服務(wù),緩存并寫入日志內(nèi)容和索引到底層存儲。
  • Querier:日志讀取服務(wù),執(zhí)行搜索請求。
  • QueryFrontend:日志讀取入口,分發(fā)讀取請求到 Querier 并返回結(jié)果。
  • Cassandra/BigTable/DnyamoDB/S3/GCS:索引、日志內(nèi)容底層存儲。
  • Cache:緩存,支持 Redis/Memcache/本地 Cache。

其主體結(jié)構(gòu)如下圖所示:

Distributor:作為日志寫入的入口服務(wù),其負(fù)責(zé)對上報(bào)數(shù)據(jù)進(jìn)行解析、校驗(yàn)與轉(zhuǎn)發(fā)。

它將接收到的上報(bào)數(shù)解析完成后會進(jìn)行大小、條目、頻率、標(biāo)簽、租戶等參數(shù)校驗(yàn),然后將合法數(shù)據(jù)轉(zhuǎn)發(fā)到 Ingester 服務(wù),其在轉(zhuǎn)發(fā)之前最重要的任務(wù)是確保同一日志流的數(shù)據(jù)必須轉(zhuǎn)發(fā)到相同 Ingester 上,以確保數(shù)據(jù)的順序性。

Hash 環(huán):Distributor 采用一致性哈希與副本因子相結(jié)合的辦法來決定數(shù)據(jù)轉(zhuǎn)發(fā)到哪些 Ingester 上。

Ingester 在啟動后,會生成一系列的 32 位隨機(jī)數(shù)作為自己的 Token ,然后與這一組 Token 一起將自己注冊到 Hash 環(huán)中。

在選擇數(shù)據(jù)轉(zhuǎn)發(fā)目的地時(shí),Distributor 根據(jù)日志的標(biāo)簽和租戶 ID 生成 Hash,然后在 Hash 環(huán)中按 Token 的升序查找第一個(gè)大于這個(gè) Hash 的 Token ,這個(gè) Token 所對應(yīng)的 Ingester 即為這條日志需要轉(zhuǎn)發(fā)的目的地。

如果設(shè)置了副本因子,順序的在之后的 Token 中查找不同的 Ingester 做為副本的目的地。

Hash 環(huán)可存儲于 etcd、consul 中。另外 Loki 使用 Memberlist 實(shí)現(xiàn)了集群內(nèi)部的 KV 存儲,如不想依賴 etcd 或 consul ,可采用此方案。

輸入輸出:Distributor 的輸入主要是以 HTTP 協(xié)議批量的方式接受上報(bào)日志,日志封裝格式支持 JSON 和 PB ,數(shù)據(jù)封裝結(jié)構(gòu):

  1.   { 
  2.    "stream": {  
  3.      "label1""value1"
  4.      "label1""value2" 
  5.    }, 
  6.    "values": [ 
  7.      ["<timestamp nanoseconds>","log content"], 
  8.      ["<timestamp nanoseconds>","log content"
  9.    ] 
  10.   }, 
  11.   ...... 

Distributor 以 grpc 方式向 ingester 發(fā)送數(shù)據(jù),數(shù)據(jù)封裝結(jié)構(gòu):

  1.   "streams": [ 
  2.     { 
  3.       "labels""{label1=value1, label2=value2}"
  4.       "entries": [ 
  5.           {"ts": <unix epoch in nanoseconds>, "line:":"<log line>" }, 
  6.           {"ts": <unix epoch in nanoseconds>, "line:":"<log line>" }, 
  7.       ] 
  8.     } 
  9.     .... 
  10.    ] 

①Ingester

作為 Loki 的寫入模塊,Ingester 主要任務(wù)是緩存并寫入數(shù)據(jù)到底層存儲。根據(jù)寫入數(shù)據(jù)在模塊中的生命周期,ingester 大體上分為校驗(yàn)、緩存、存儲適配三層結(jié)構(gòu)。

②校驗(yàn)

Loki 有個(gè)重要的特性是它不整理數(shù)據(jù)亂序,要求同一日志流的數(shù)據(jù)必須嚴(yán)格遵守時(shí)間戳單調(diào)遞增順序?qū)懭搿?/p>

所以除對數(shù)據(jù)的長度、頻率等做校驗(yàn)外,至關(guān)重要的是日志順序檢查。

Ingester 對每個(gè)日志流里每一條日志都會和上一條進(jìn)行時(shí)間戳和內(nèi)容的對比,策略如下:

  • 與上一條日志相比,本條日志時(shí)間戳更新,接收本條日志。
  • 與上一條日志相比,時(shí)間戳相同內(nèi)容不同,接收本條日志。
  • 與上一條日志相比,時(shí)間戳和內(nèi)容都相同,忽略本條日志。
  • 與上一條日志相比,本條日志時(shí)間戳更老,返回亂序錯(cuò)誤。

③緩存

日志在內(nèi)存中的緩存采用多層樹形結(jié)構(gòu)對不同租戶、日志流做出隔離。同一日志流采用順序追加方式寫入分塊:

  • Instances:以租戶的 userID 為鍵 Instance 為值的 Map 結(jié)構(gòu)。
  • Instance:一個(gè)租戶下所有日志流(stream)的容器。
  • Streams:以日志流的指紋(streamFP)為鍵,Stream 為值的 Map 結(jié)構(gòu)。
  • Stream:一個(gè)日志流所有 Chunk 的容器。
  • Chunks:Chunk 的列表。
  • Chunk:持久存儲讀寫最小單元在內(nèi)存態(tài)的結(jié)構(gòu)。
  • Block:Chunk 的分塊,為已壓縮歸檔的數(shù)據(jù)。
  • HeadBlock:尚在開放寫入的分塊。
  • Entry:單條日志單元,包含時(shí)間戳(timestamp)和日志內(nèi)容(line)

整體結(jié)構(gòu)如下:

 

Chunks:在向內(nèi)存寫入數(shù)據(jù)前,ingester 首先會根據(jù)租戶ID(userID)和由標(biāo)簽計(jì)算的指紋(streamPF)定位到日志流(stream)及 Chunks。

Chunks 由按時(shí)間升序排列的 chunk 組成,最后一個(gè) chunk 接收最新寫入的數(shù)據(jù),其他則等刷寫到底層存儲。

當(dāng)最后一個(gè) chunk 的存活時(shí)間或數(shù)據(jù)大小超過指定閾值時(shí),Chunks 尾部追加新的 chunk 。

Chunk:Chunk 為 Loki 在底層存儲上讀寫的最小單元在內(nèi)存態(tài)下的結(jié)構(gòu)。其由若干 block 組成,其中 headBlock 為正在開放寫入的 block ,而其他 Block 則已經(jīng)歸檔壓縮的數(shù)據(jù)。

Block:Block 為數(shù)據(jù)的壓縮單元,目的是為了在讀取操作那里避免因?yàn)槊看谓鈮赫麄€(gè) Chunk 而浪費(fèi)計(jì)算資源,因?yàn)楹芏嗲闆r下是讀取一個(gè) chunk 的部分?jǐn)?shù)據(jù)就滿足所需數(shù)據(jù)量而返回結(jié)果了。

Block 存儲的是日志的壓縮數(shù)據(jù),其結(jié)構(gòu)為按時(shí)間順序的日志時(shí)間戳和原始內(nèi)容,壓縮可采用 gzip、snappy 、lz4 等方式。

HeadBlock:正在接收寫入的特殊 block ,它在滿足一定大小后會被壓縮歸檔為 Block ,然后新 headBlock 會被創(chuàng)建。

存儲適配:由于底層存儲要支持 S3、Cassandra、BigTable、DnyamoDB 等系統(tǒng),適配層將各種系統(tǒng)的讀寫操作抽象成統(tǒng)一接口,負(fù)責(zé)與他們進(jìn)行數(shù)據(jù)交互。

④輸出

Loki 以 Chunk 為單位在存儲系統(tǒng)中讀寫數(shù)據(jù)。在持久存儲態(tài)下的 Chunk 具有如下結(jié)構(gòu):

  • meta:封裝 chunk 所屬 stream 的指紋、租戶 ID,開始截止時(shí)間等元信息。
  • data:封裝日志內(nèi)容,其中一些重要字段。
  • encode 保存數(shù)據(jù)的壓縮方式。
  • block-N bytes 保存一個(gè) block 的日志數(shù)據(jù)。
  • #blocks section byte offset 單元記錄 #block 單元的偏移量。
  • #block 單元記錄一共有多少個(gè) block。
  • #entries 和 block-N bytes 一一對應(yīng),記錄每個(gè) block 里有日式行數(shù)、時(shí)間起始點(diǎn),blokc-N bytes 的開始位置和長度等元信息。

Chunk 數(shù)據(jù)的解析順序:

  • 根據(jù)尾部的 #blocks section byte offset 單元得到 #block 單元的位置。
  • 根據(jù) #block 單元記錄得出 chunk 里 block 數(shù)量。
  • 從 #block 單元所在位置開始讀取所有 block 的 entries、mint、maxt、offset、len 等元信息。
  • 順序的根據(jù)每個(gè) block 元信息解析出 block 的數(shù)據(jù)。

⑤索引

Loki 只索引了標(biāo)簽數(shù)據(jù),用于實(shí)現(xiàn)標(biāo)簽→日志流→Chunk 的索引映射, 以分表形式在存儲層存儲。

表結(jié)構(gòu)如下:

  1. CREATE TABLE IF NOT EXISTS Table_N ( 
  2.     hash text, 
  3.     range blob, 
  4.     value blob, 
  5.     PRIMARY KEY (hash, range) 
  6.  ) 

Table_N,根據(jù)時(shí)間周期分表名;hash, 不同查詢類型時(shí)使用的索引;range,范圍查詢字段;value,日志標(biāo)簽的值。

數(shù)據(jù)類型:Loki 保存了不同類型的索引數(shù)據(jù)用以實(shí)現(xiàn)不同映射場景,對于每種類型的映射數(shù)據(jù),Hash/Range/Value 三個(gè)字段的數(shù)據(jù)組成如下圖所示:

seriesID 為日志流 ID,shard 為分片,userID 為租戶 ID,labelName 為標(biāo)簽名,labelValueHash 為標(biāo)簽值 hash,chunkID 為 chunk 的 ID,chunkThrough 為 chunk 里最后一條數(shù)據(jù)的時(shí)間這些數(shù)據(jù)元素在映射過程中的作用在 Querier 環(huán)節(jié)的[查詢流程]((null))做詳細(xì)介紹。

上圖中三種顏色標(biāo)識的索引類型從上到下分別為:

  • 數(shù)據(jù)類型 1:用于根據(jù)用戶 ID 搜索查詢所有日志流的 ID。
  • 數(shù)據(jù)類型 2:用于根據(jù)用戶 ID 和標(biāo)簽查詢?nèi)罩玖鞯?ID。
  • 數(shù)據(jù)類型 3:用于根據(jù)日志流 ID 查詢底層存儲 Chunk 的 ID。

除了采用分表外,Loki 還采用分桶、分片的方式優(yōu)化索引查詢速度。

分桶:

以天分割:bucketID = timestamp / secondsInDay。

以小時(shí)分割:bucketID = timestamp / secondsInHour。

分片:將不同日志流的索引分散到不同分片,shard = seriesID% 分片數(shù)。

Chunk 狀態(tài):Chunk 作為在 Ingester 中重要的數(shù)據(jù)單元,其在內(nèi)存中的生命周期內(nèi)分如下四種狀態(tài):

  • Writing:正在寫入新數(shù)據(jù)。
  • Waiting flush:停止寫入新數(shù)據(jù),等待寫入到存儲。
  • Retain:已經(jīng)寫入存儲,等待銷毀。
  • Destroy:已經(jīng)銷毀。

四種狀態(tài)之間的轉(zhuǎn)換以 writing→waiting flush→retain→destroy 順序進(jìn)行。

狀態(tài)轉(zhuǎn)換時(shí)機(jī):

  • 協(xié)作觸發(fā):有新的數(shù)據(jù)寫入請求。
  • 定時(shí)觸發(fā):刷寫周期觸發(fā)將 chunk 寫入存儲,回收周期觸發(fā)將 chunk 銷毀。

writing 轉(zhuǎn)為 waiting flush:chunk 初始狀態(tài)為 writing,標(biāo)識正在接受數(shù)據(jù)的寫入,滿足如下條件則進(jìn)入到等待刷寫狀態(tài):

  • chunk 空間滿(協(xié)作觸發(fā))。
  • chunk 的存活時(shí)間(首末兩條數(shù)據(jù)時(shí)間差)超過閾值 (定時(shí)觸發(fā))。
  • chunk 的空閑時(shí)間(連續(xù)未寫入數(shù)據(jù)時(shí)長)超過設(shè)置 (定時(shí)觸發(fā))。

waiting flush 轉(zhuǎn)為 etain:Ingester 會定時(shí)的將等待刷寫的 chunk 寫到底層存儲,之后這些 chunk 會處于”retain“狀態(tài),這是因?yàn)?ingester 提供了對最新數(shù)據(jù)的搜索服務(wù),需要在內(nèi)存里保留一段時(shí)間,retain 狀態(tài)則解耦了數(shù)據(jù)的刷寫時(shí)間以及在內(nèi)存中的保留時(shí)間,方便視不同選項(xiàng)優(yōu)化內(nèi)存配置。

destroy,被回收等待 GC 銷毀:總體上,Loki 由于針對日志的使用場景,采用了順序追加方式寫入,只索引元信息,極大程度上簡化了它的數(shù)據(jù)結(jié)構(gòu)和處理邏輯,這也為 Ingester 能夠應(yīng)對高速寫入提供了基礎(chǔ)。

Querier:查詢服務(wù)的執(zhí)行組件,其負(fù)責(zé)從底層存儲拉取數(shù)據(jù)并按照 LogQL 語言所描述的篩選條件過濾。它可以直接通過 API 提供查詢服務(wù),也可以與 queryFrontend 結(jié)合使用實(shí)現(xiàn)分布式并發(fā)查詢。

⑥查詢類型

查詢類型如下:

  • 范圍日志查詢
  • 單日志查詢
  • 統(tǒng)計(jì)查詢
  • 元信息查詢

在這些查詢類型中,范圍日志查詢應(yīng)用最為廣泛,所以下文只對范圍日志查詢做詳細(xì)介紹。

并發(fā)查詢:對于單個(gè)查詢請求,雖然可以直接調(diào)用 Querier 的 API 進(jìn)行查詢,但很容易會由于大查詢導(dǎo)致 OOM,為應(yīng)對此種問題 querier 與 queryFrontend 結(jié)合一起實(shí)現(xiàn)查詢分解與多 querier 并發(fā)執(zhí)行。

每個(gè) querier 都與所有 queryFrontend 建立 grpc 雙向流式連接,實(shí)時(shí)從 queryFrontend 中獲取已經(jīng)分割的子查詢求,執(zhí)行后將結(jié)果發(fā)送回 queryFrontend。

具體如何分割查詢及在 querier 間調(diào)度子查詢將在 queryFrontend 環(huán)節(jié)介紹。

⑧查詢流程

先解析 logQL 指令,然后查詢?nèi)罩玖?ID 列表。

Loki 根據(jù)不同的標(biāo)簽選擇器語法使用了不同的索引查詢邏輯,大體分為兩種:

=,或多值的正則匹配=~,工作過程如下:

以類似下 SQL 所描述的語義查詢出標(biāo)簽選擇器里引用的每個(gè)標(biāo)簽鍵值對所對應(yīng)的日志流 ID(seriesID)的集合。

  1. SELECT * FROM Table_N WHERE hash=? AND range>=?    AND value=labelValue 

hash 為租戶 ID(userID)、分桶(bucketID)、標(biāo)簽名(labelName)組合計(jì)算的哈希值;range 為標(biāo)簽值(labelValue)計(jì)算的哈希值。

將根據(jù)標(biāo)簽鍵值對所查詢的多個(gè) seriesID 集合取并集或交集求最終集合。

比如,標(biāo)簽選擇器{file="app.log", level=~"debug|error"}的工作過程如下:

  • 查詢出 file="app.log",level="debug", level="error" 三個(gè)標(biāo)簽鍵值所對應(yīng)的 seriesID 集合,S1 、S2、S3。
  • 根據(jù)三個(gè)集合計(jì)算最終 seriesID 集合 S = S1∩cap (S2∪S3)。

!=,=~,!~,工作過程如下:

以如下 SQL 所描述的語義查詢出標(biāo)簽選擇器里引用的每個(gè)標(biāo)簽所對應(yīng) seriesID 集合。

  1. SELECT * FROM Table_N WHERE hash = ? 

hash 為租戶 ID(userID)、分桶(bucketID)、標(biāo)簽名(labelName)。

根據(jù)標(biāo)簽選擇語法對每個(gè) seriesID 集合進(jìn)行過濾。

將過濾后的集合進(jìn)行并集、交集等操作求最終集合。

比如,{file~="mysql*", level!="error"} 的工作過程如下:

  • 查詢出標(biāo)簽“file”和標(biāo)簽"level"對應(yīng)的 seriesID 的集合,S1、S2。
  • 求出 S1 中 file 的值匹配 mysql*的子集 SS1,S2 中 level 的值!="error"的子集 SS2。
  • 計(jì)算最終 seriesID 集合 S = SS1∩SS2。

以如下 SQL 所描述的語義查詢出所有日志流所包含的 chunk 的 ID:

  1. SELECT * FROM Table_N Where hash = ? 

hash 為分桶(bucketID)和日志流(seriesID)計(jì)算的哈希值。

根據(jù) chunkID 列表生成遍歷器來順序讀取日志行:遍歷器作為數(shù)據(jù)讀取的組件,其主要功能為從存儲系統(tǒng)中拉取 chunk 并從中讀取日志行。其采用多層樹形結(jié)構(gòu),自頂向下逐層遞歸觸發(fā)方式彈出數(shù)據(jù)。

具體結(jié)構(gòu)如上圖所示:

  • batch Iterator:以批量的方式從存儲中下載 chunk 原始數(shù)據(jù),并生成 iterator 樹。
  • stream Iterator:多個(gè) stream 數(shù)據(jù)的遍歷器,其采用堆排序確保多個(gè) stream 之間數(shù)據(jù)的保序;
  • chunks Iterator:多個(gè) chunk 數(shù)據(jù)的遍歷器,同樣采用堆排序確保多個(gè) chunk 之間保序及多副本之間的去重。
  • blocks Iterator:多個(gè) block 數(shù)據(jù)的遍歷器。
  • block bytes Iterator:block 里日志行的遍歷器。

從 Ingester 查詢在內(nèi)存中尚未寫入到存儲中的數(shù)據(jù):由于 Ingester 是定時(shí)的將緩存數(shù)據(jù)寫入到存儲中,所以 Querier 在查詢時(shí)間范圍較新的數(shù)據(jù)時(shí),還會通過 grpc 協(xié)議從每個(gè) ingester 中查詢出內(nèi)存數(shù)據(jù)。

需要在 ingester 中查詢的時(shí)間范圍是可配置的,視 ingester 緩存數(shù)據(jù)時(shí)長而定。

上面是日志內(nèi)容查詢的主要流程。至于指標(biāo)查詢的流程與其大同小異,只是增加了指標(biāo)計(jì)算的遍歷器層用于從查詢出的日志計(jì)算指標(biāo)數(shù)據(jù)。其他兩種則更為簡單,這里不再詳細(xì)展開。

QueryFrontend:Loki 對查詢采用了計(jì)算后置的方式,類似于在大量原始數(shù)據(jù)上做 grep,所以查詢勢必會消耗比較多的計(jì)算和內(nèi)存資源。

如果以單節(jié)點(diǎn)執(zhí)行一個(gè)查詢請求的話很容易因?yàn)榇蟛樵冊斐?OOM、速度慢等性能瓶頸。

為解決此問題,Loki 采用了將單個(gè)查詢分解在多個(gè) querier 上并發(fā)執(zhí)行方式,其中查詢請求的分解和調(diào)度則由 queryFrontend 完成。

queryFrontend 在 Loki 的整體架構(gòu)上處于 querier 的前端,它作為數(shù)據(jù)讀取操作的入口服務(wù),其主要的組件及工作流程如上圖所示:

  • 分割 Request:將單個(gè)查詢分割成子查詢 subReq 的列表。
  • Feeder:將子查詢順序注入到緩存隊(duì)列 Buf Queue。
  • Runner:多個(gè)并發(fā)的運(yùn)行器將 Buf Queue 中的查詢并注入到子查詢隊(duì)列,并等待返回查詢結(jié)果。
  • Querier 通過 grpc 協(xié)議實(shí)時(shí)從子查詢隊(duì)列彈出子查詢,執(zhí)行后將結(jié)果返回給相應(yīng)的 Runner。
  • 所有子請求在 Runner 執(zhí)行完畢后匯總結(jié)果返回 API 響應(yīng)。

⑨查詢分割

queryFrontend 按照固定時(shí)間跨度將查詢請求分割成多個(gè)子查詢。比如,一個(gè)查詢的時(shí)間范圍是 6 小時(shí),分割跨度為 15 分鐘,則查詢會被分為 6*60/15=24 個(gè)子查詢。

⑩查詢調(diào)度

Feeder:Feeder 負(fù)責(zé)將分割好的子查詢逐一的寫入到緩存隊(duì)列 Buf Queue,以生產(chǎn)者/消費(fèi)者模式與下游的 Runner 實(shí)現(xiàn)可控的子查詢并發(fā)。

Runner:從 Buf Queue 中競爭方式讀取子查詢并寫入到下游的請求隊(duì)列中,并處理來自 Querier 的返回結(jié)果。

Runner 的并發(fā)個(gè)數(shù)通過全局配置控制,避免因?yàn)橐淮畏纸膺^多子查詢而對 Querier 造成巨大的徒流量,影響其穩(wěn)定性。

子查詢隊(duì)列:隊(duì)列是一個(gè)二維結(jié)構(gòu),第一維存儲的是不同租戶的隊(duì)列,第二維存儲同一租戶子查詢列表,它們都是以 FIFO 的順序組織里面的元素的入隊(duì)出隊(duì)。

分配請求:queryFrontend 是以被動方式分配查詢請求,后端 Querier 與 queryFrontend 實(shí)時(shí)的通過 grpc 監(jiān)聽子查詢隊(duì)列,當(dāng)有新請求時(shí)以如下順序在隊(duì)列中彈出下一個(gè)請求:

  • 以循環(huán)的方式遍歷隊(duì)列中的租戶列表,尋找下一個(gè)有數(shù)據(jù)的租戶隊(duì)列。
  • 彈出該租戶隊(duì)列中的最老的請求。

總結(jié)

Loki 作為一個(gè)正在快速發(fā)展的項(xiàng)目,最新版本已到 2.0,相較 1.6 增強(qiáng)了諸如日志解析、Ruler、Boltdb-shipper 等新功能,不過基本的模塊、架構(gòu)、數(shù)據(jù)模型、工作原理上已處于穩(wěn)定狀態(tài)。

希望本文的這些嘗試性的剖析能夠能夠?yàn)榇蠹姨峁┮恍椭缥闹杏欣斫忮e(cuò)誤之處,歡迎批評指正。

作者:張海軍

編輯:陶家龍

出處:轉(zhuǎn)載自公眾號京東智聯(lián)云開發(fā)者(ID:JDC_Developers)

 

責(zé)任編輯:武曉燕 來源: 京東智聯(lián)云開發(fā)者
相關(guān)推薦

2024-04-16 13:34:26

JSONMsgpack存儲

2020-08-27 15:35:01

存儲

2025-11-10 09:21:24

2019-09-19 17:07:05

戴爾

2021-08-30 07:01:19

HTTP網(wǎng)絡(luò)應(yīng)用

2022-01-17 14:25:14

索引數(shù)據(jù)庫搜索

2019-01-15 13:14:03

機(jī)器人算法SAC

2021-03-18 11:41:04

影子IT影子IoT物聯(lián)網(wǎng)安全

2021-09-13 08:20:13

Loki日志系統(tǒng)

2018-08-08 09:30:29

服務(wù)器知識Linux系統(tǒng)

2024-04-11 09:17:51

ArraysJava安全

2020-12-10 08:44:35

WebSocket輪詢Comet

2022-03-24 13:36:18

Java悲觀鎖樂觀鎖

2025-09-08 04:00:00

2019-03-03 15:52:39

阿里云宕機(jī)云災(zāi)備

2019-02-20 14:16:43

2020-02-10 14:26:10

GitHub代碼倉庫

2024-04-11 12:19:01

Rust數(shù)據(jù)類型

2018-06-05 17:40:36

人工智能語音識別
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

国产精品99久久久久久董美香| 国产精品成人aaaa在线| 最新在线中文字幕| 手机在线电影一区| 日韩精品一区二区三区三区免费| 无码专区aaaaaa免费视频| 国产在线超碰| 国产乱码字幕精品高清av | 3p视频在线观看| 国产成人小视频| 国产精品999| 国产亚洲精品久久久优势| 亚洲一区二区| 亚洲精品性视频| 精品国产福利视频| 亚洲香蕉视频| 久久草av在线| 欧美激情视频在线| 成都免费高清电影| 99热这里只有精品首页 | 国产亚洲a∨片在线观看| 午夜激情视频网| 中文字幕在线免费观看视频| 一区二区三区在线免费播放| 久久99久久久久久久噜噜| 极品粉嫩小仙女高潮喷水久久 | 日韩深夜福利| 欧美一级在线免费| 国产精品一区二区小说| xx欧美xxx| 午夜在线成人av| 日韩中文字幕在线不卡| 一级毛片视频在线| 久久久久久黄色| 久久久久久久久一区| 五月天婷婷综合网| 久久a级毛片毛片免费观看| 欧美日韩一区二区三区免费看| 亚洲电影免费| 欧美偷拍视频| aaa国产一区| 国产乱码精品一区二区三区卡 | 亚洲视频自拍偷拍| 视频免费在线观看| 日本三级一区| 久久久一区二区三区捆绑**| 国产精品日韩高清| 亚洲欧美黄色片| 高清视频一区二区| av激情久久| 亚洲精品一级片| 国产激情精品久久久第一区二区 | 伊人久久av导航| 欧美人体大胆444www| 99久久免费视频.com| 国产精品xxx在线观看www| 亚洲AV无码成人片在线观看| 国产91丝袜在线观看| 99在线观看视频网站| 成人激情四射网| 国产激情偷乱视频一区二区三区 | 美女亚洲一区| 在线日韩精品视频| 亚洲色图 激情小说| 国产精品久久久久久久久久齐齐| 色综合天天天天做夜夜夜夜做| 国产最新免费视频| 亚洲成人看片| 欧美无砖砖区免费| 日本福利视频在线观看| 午夜影院免费在线| 国产日韩欧美在线一区| 亚洲在线免费看| 久久免费激情视频| 乱码第一页成人| 国产精品99久久久久久www| 亚洲无码精品一区二区三区| 久久66热偷产精品| 99电影在线观看| 色天堂在线视频| 国产女人18水真多18精品一级做| 91社在线播放| heyzo中文字幕在线| 日韩欧美亚洲国产一区| 亚洲免费一级视频| 伊人久久影院| 亚洲午夜激情免费视频| 紧身裙女教师波多野结衣| 亚洲国产国产亚洲一二三| 国产福利成人在线| va婷婷在线免费观看| 黄页网站大全在线免费观看| 日本中文一区二区三区| 91精品视频一区| 人人妻人人澡人人爽精品日本| 久久精品这里都是精品| 超碰10000| 国产成人免费9x9x人网站视频| 欧美疯狂做受xxxx富婆| 国产精品成人99一区无码| sdde在线播放一区二区| 欧美激情免费观看| 亚洲天堂aaa| 91原创在线视频| 在线一区日本视频| 蜜桃视频在线观看www社区| 欧美日韩国产在线播放| 国产精品igao网网址不卡| 先锋影音国产精品| 欧美成人精品三级在线观看| 少妇太紧太爽又黄又硬又爽| 精品一区在线看| 欧美日韩精品一区| 在线黄色网页| 欧美日韩精品一区二区三区四区 | 亚洲人妖av一区二区| 97在线播放视频| 日韩在线成人| 久久亚洲国产精品| 中文字幕精品在线观看| 亚洲黄色免费| 国产精品十八以下禁看| 日韩大胆视频| 亚洲一区二区三区在线播放| 香蕉视频999| 欧美一二区在线观看| 亚洲欧美一区二区三区在线| 免费中文字幕视频| 狠狠色丁香久久婷婷综合丁香| 欧美日韩国产一二| 欧亚av在线| 亚洲第一av网站| 国产 福利 在线| 11024精品一区二区三区日韩| 99精品1区2区| 国产精品www在线观看| 国产精品一区二区三区www| 在线视频欧美日韩精品| 久久精品偷拍视频| 久久精品欧美一区二区三区麻豆| 99热在线这里只有精品| 欧美中文一区| 777精品视频| 亚洲 欧美 自拍偷拍| 亚洲大片在线观看| 精品无码国产一区二区三区51安| 亚洲精品九九| 久久久com| 日韩成人影音| 亚洲图片在线综合| 中文永久免费观看| 国产精品国产三级国产aⅴ中文| 欧美一级裸体视频| 日韩电影一区| 成人激情视频在线播放| 午夜精品久久久久久久91蜜桃| 成人欧美一区二区三区黑人麻豆| 国产精品视频一二三四区| 久久中文字幕一区二区| 欧美成人精品一区二区| 亚洲av永久无码国产精品久久| 一区二区三区91| 一级黄色片毛片| 一本久道综合久久精品| 免费国产一区二区| 国产精品一区二区三区视频网站| 欧美日韩成人高清| 成人涩涩小片视频日本| 国产精品系列在线播放| 久久成人福利视频| 日韩欧美黄色| 国产精品久久久久秋霞鲁丝| 欧美a在线看| 欧美mv日韩mv| 中文字幕超碰在线| 国产精品三级在线观看| japan高清日本乱xxxxx| 99热免费精品在线观看| 日韩高清av| 久久国际精品| 91精品国产乱码久久久久久蜜臀| 精品毛片久久久久久| 午夜伦理在线视频| 亚洲精品国产综合久久| 国产情侣小视频| 亚洲日本va午夜在线影院| 国产精品成人99一区无码| 日本成人超碰在线观看| 日本天堂免费a| 亚洲精品亚洲人成在线| 成人免费观看网址| 欧美亚洲日本精品| 理论片在线不卡免费观看| 亚洲欧美丝袜中文综合| 在线不卡免费欧美| 国产专区第一页| 亚洲欧美另类小说| 毛茸茸多毛bbb毛多视频| 精久久久久久久久久久| heyzo亚洲| 中文字幕一区二区三区在线视频| 久久精品人人做人人爽电影| 成人av在线播放| 日韩69视频在线观看| 成年人黄视频在线观看| 亚洲视频axxx| 人妻无码中文字幕| 欧美一区二区在线免费观看| 一二三区免费视频| 亚洲午夜视频在线观看| 特黄一区二区三区| 26uuu成人网一区二区三区| 999热精品视频| 麻豆中文一区二区| 人妻精品无码一区二区三区 | 男女激情免费视频| 日韩aaaa| 色综合视频二区偷拍在线| 成人资源在线播放| 91久久久久久久久久久| 欧美日韩在线精品一区二区三区激情综合 | 国产欧美精品久久久| 樱桃视频成人在线观看| 久久久久久国产精品美女| 久操视频在线| 丝袜情趣国产精品| 国产在线黄色| 精品中文字幕久久久久久| 好吊视频一区二区三区| 欧美日韩五码| 丝袜情趣国产精品| aⅴ在线视频男人的天堂 | 91caoporn在线| 亚洲女成人图区| 香蕉久久国产av一区二区| 精品女同一区二区| 亚洲成a人片77777精品| 777久久久精品| 国产精品久久久久久在线| 欧美三级韩国三级日本一级| 337p粉嫩色噜噜噜大肥臀| 色老综合老女人久久久| 少妇久久久久久久久久| 91老师国产黑色丝袜在线| 粉嫩av懂色av蜜臀av分享| www.亚洲在线| 最新在线黄色网址| 26uuu国产日韩综合| 成人免费网站黄| 久久精品视频网| 国产伦理片在线观看| 中文字幕免费观看一区| 亚洲激情图片网| 日韩一区欧美小说| 欧美成人手机视频| 亚洲五码中文字幕| 日本三级免费看| 国产精品毛片无遮挡高清| 在线观看免费黄色网址| 国产精品久久久久久久久果冻传媒| 伊人影院综合网| 中文字幕字幕中文在线中不卡视频| 欧美三级日本三级| 亚洲国产精品一区二区www| 日韩少妇高潮抽搐| 一本大道av一区二区在线播放| 亚洲精品一区二三区| 666欧美在线视频| 丰满人妻一区二区三区免费视频| 亚洲国产精品人人爽夜夜爽| 免费观看成年在线视频网站| 中文字幕亚洲激情| 91国内在线| 777国产偷窥盗摄精品视频| 国产极品一区| 91丝袜脚交足在线播放| 欧美一区 二区| 亚洲亚洲精品三区日韩精品在线视频 | 美女任你摸久久| 乱码一区二区三区| 久久在线免费观看| 国产人与禽zoz0性伦| 香蕉久久久久久| 亚洲美女av在线播放| 久久日韩视频| 51精品在线观看| 日本不卡在线| 欧美激情免费视频| 亚洲四虎影院| 成人av蜜桃| 欧洲杯什么时候开赛| 亚洲国产一二三精品无码| 久久av在线| 日本女人黄色片| 国产亚洲一区字幕| 波多野结衣在线网址| 黄色一区二区三区| 国产乱叫456在线| 亚洲午夜久久久影院| 久久www人成免费看片中文| 国产精品激情av电影在线观看| 在线人成日本视频| 91理论片午午论夜理片久久| 亚洲午夜久久| 欧美又粗又长又爽做受| 免费观看在线色综合| 在线免费观看污视频| 亚洲婷婷综合色高清在线| 波多野结衣一二区| 亚洲国产成人一区| 黄色网页在线观看| 日韩美女免费观看| 精品淫伦v久久水蜜桃| 中国人体摄影一区二区三区| 六月天综合网| 久久福利小视频| 一区二区三区四区激情 | 欧美情侣在线播放| 毛片在线播放网站| 97视频在线观看视频免费视频 | 亚洲先锋成人| 亚洲网中文字幕| 国产女人水真多18毛片18精品视频| 自拍偷拍欧美亚洲| 日韩免费一区二区| av香蕉成人| 91精品在线看| 99精品视频在线观看播放| 大桥未久一区二区三区| 日本欧美在线观看| 中文字幕国产专区| 色综合中文字幕| 视频在线不卡| 搡老女人一区二区三区视频tv| 小视频免费在线观看| 国产精品区一区| 亚洲网站视频| 97中文字幕在线观看| 亚洲精品久久嫩草网站秘色| www.xxx亚洲| 欧美9999| 超碰97免费观看| 国产综合久久久久久久久久久久| 欧美自拍偷拍网| 欧美日韩免费观看一区三区| www亚洲人| 国产中文字幕91| 亚洲精品午夜av福利久久蜜桃| 国内外成人免费在线视频| 国产精品久久二区二区| 中文字幕你懂的| yellow中文字幕久久| 粉嫩一区二区三区在线观看| 亚洲激情免费视频| 国产成人免费av在线| 亚洲国产精品午夜在线观看| 亚洲精品福利在线| 黑人巨大精品| 亚洲欧美国产精品桃花| 国产一区二区三区黄视频| 欧美三级在线免费观看| 亚洲成人网在线观看| 在线看的毛片| 亚洲午夜久久久影院伊人| 国产一区二区电影| 日本少妇性生活| 亚洲视频在线看| 国产精品日本一区二区不卡视频 | 日韩av电影免费观看高清完整版| 国产一区二区三区四区在线| 91精品国产一区二区三区| 国产盗摄精品一区二区酒店| 久久综合色一本| 久久精品免费看| 久久婷婷一区二区| 亚洲欧美另类中文字幕| 亚洲一区二区三区久久久| 久久国产精品网| 亚洲国产高清不卡| www.黄色小说.com| 日本视频久久久| 亚洲在线久久| 久久精品一区二区免费播放| 欧美日韩三级一区| 国产蜜臀在线| 亚洲国产精品一区在线观看不卡| 国产精品一区二区免费不卡| 黄色片免费观看视频| 久久精品视频在线| 欧美巨大xxxx| 韩国一区二区在线播放| 精品福利一区二区| 成人在线免费看黄| 免费电影一区| 大尺度一区二区| 在线观看毛片网站| 欧美在线视频免费| 重囗味另类老妇506070| 三区四区在线观看| 日韩av在线免费|