亚洲先锋影音人AV成_免费A级毛片一分钟_人人爽人人爽人人插_日韩少妇极品熟妇人妻潮喷

沃卡惠移動(dòng)端logo

讀時(shí)建模技術(shù)在異構(gòu)數(shù)據(jù)分析平臺(tái)的應(yīng)用

2023-05-22 10:21:004636

一、日志分析場(chǎng)景的需求和技術(shù)挑戰(zhàn)

1、日志分析

(1)什么是日志

廣義來(lái)講,日志記錄的是一個(gè)不可變的信息,它是一個(gè)事實(shí),也就是在某個(gè)時(shí)點(diǎn),發(fā)生了某一件事情。如果狹義地去理解,日志就是系統(tǒng)后臺(tái)的 log。通常,log 都會(huì)有一個(gè)時(shí)間戳,記錄了這個(gè)時(shí)間戳上發(fā)生的事,比如 server 啟動(dòng),或者是產(chǎn)生了錯(cuò)誤等等。

(2)日志分析的價(jià)值

日志分析有著很大的價(jià)值。在 To C 場(chǎng)景中,比如淘寶、拼多多這樣的電商系統(tǒng),會(huì)記錄用戶(hù)的瀏覽行為,并推薦商品。這些推薦系統(tǒng)就是依賴(lài)于日志的。常見(jiàn)的內(nèi)容優(yōu)化、用戶(hù)畫(huà)像、AI 算法等也都依賴(lài)于日志。

To B 場(chǎng)景下,對(duì)于一個(gè)企業(yè)來(lái)說(shuō),分析日志主要有兩個(gè)目的,第一是希望利用這些數(shù)據(jù)去更好地賺錢(qián)(開(kāi)源);第二是利用這些數(shù)據(jù)提高企業(yè)的運(yùn)行效率,幫助企業(yè)去省錢(qián)(節(jié)流)。從開(kāi)源的角度來(lái)講,比如近幾年非?;鸨牧鞒掏诰?,就是把企業(yè)在生產(chǎn)中產(chǎn)生的各種日志數(shù)據(jù)收集起來(lái),基于這些事實(shí)做統(tǒng)計(jì)或者機(jī)器學(xué)習(xí),幫企業(yè)進(jìn)行各種挖掘分析,找到一些規(guī)律,比如優(yōu)化制造工藝、提高流水線的生產(chǎn)效率、精簡(jiǎn)流程、讓業(yè)務(wù)跑得更快等,這些都能夠幫助企業(yè)去更好地賺錢(qián)。從節(jié)流角度來(lái)講,比如 IT 運(yùn)維,如果故障率低、故障響應(yīng)速度快,那么就可以為公司省很多錢(qián),避免潛在損失。

(3)日志分析的技術(shù)挑戰(zhàn)

第一是日志的寫(xiě)入速率快,存儲(chǔ)成本高。日志都是由機(jī)器產(chǎn)生的,機(jī)器生成的一大特點(diǎn)就是數(shù)據(jù)量非常大,這就要求系統(tǒng)在數(shù)據(jù)攝入的時(shí)候,速率必須要非常高,同時(shí)面對(duì)大量的文本數(shù)據(jù)存儲(chǔ),壓縮比必須要做得比較好,才能夠節(jié)省存儲(chǔ)成本。

第二是日志格式很難統(tǒng)一,并且格式經(jīng)常變化。因?yàn)槿罩咎幚硐到y(tǒng)通常是存在于業(yè)務(wù)系統(tǒng)的下游,很難去規(guī)定讓所有業(yè)務(wù)系統(tǒng)都符合統(tǒng)一的日志的格式,尤其是在那些 IT 建設(shè)尚不成熟的公司。只有在一些 IT Infra 建得特別好的互聯(lián)網(wǎng)公司,做日志的團(tuán)隊(duì)才有可能去推動(dòng)業(yè)務(wù)團(tuán)隊(duì)去統(tǒng)一日志格式。即便如此,日志里面的 schema 也是經(jīng)常會(huì)變化的。隨著系統(tǒng)迭代,會(huì)有新的功能和業(yè)務(wù),日志信息也會(huì)越來(lái)越多。如何能夠讓下游日志處理系統(tǒng)更好地去響應(yīng)這些日志格式、日志字段的變化,是一個(gè)非常大的挑戰(zhàn),在后文中將著重分享。

第三是批量查詢(xún)分析和即席交互式查詢(xún)分析(Ad Hoc)需求并存,數(shù)據(jù)進(jìn)入系統(tǒng)之后需要盡快可以查詢(xún)。比如在 IT 運(yùn)維、網(wǎng)絡(luò)安全監(jiān)控等常見(jiàn)的日志處理場(chǎng)景中,當(dāng)要去排障或者尋找安全入侵的時(shí)候,或者要去做我們稱(chēng)之為安全專(zhuān)家的 sweat hunting 的過(guò)程,都會(huì)有大量的即席交互查詢(xún),所以會(huì)需要查詢(xún)?nèi)罩鞠到y(tǒng)的快速響應(yīng)。在做交互式查詢(xún)的時(shí)候,數(shù)據(jù)寫(xiě)入系統(tǒng)之后,要保證能夠快速地查到。同時(shí)日志也會(huì)有很多跑批的要求,比如運(yùn)維監(jiān)控,需要跑批的去做一些告警,可能是每分鐘、每 5 分鐘、每一個(gè)小時(shí)。所以查詢(xún)會(huì)是一個(gè)比較復(fù)雜的需求。

2、日志處理技術(shù)流派

圖片

接下來(lái)看一看日志處理的技術(shù)流派。讀時(shí)建模的英文叫做 Schema on read,可能有一些同學(xué)了解過(guò)數(shù)據(jù)湖或者 ELT 技術(shù),對(duì) Schema on read 不太陌生。Schema on read 和 Schema on write 這兩個(gè)概念并不是一個(gè)特定的系統(tǒng)或者算法,可以稱(chēng)之為技術(shù)流派。

(1)寫(xiě)時(shí)建模(Scheme On Write)

上圖的右側(cè)(藍(lán)色)部分就是寫(xiě)時(shí)建模(scheme on write)。常用的關(guān)系型數(shù)據(jù)庫(kù),以及一些數(shù)據(jù)倉(cāng)庫(kù)類(lèi)的產(chǎn)品,都是寫(xiě)時(shí)建模的工作模式。在用數(shù)據(jù)庫(kù)的時(shí)候,需要先定義數(shù)據(jù)的表結(jié)構(gòu),比如在上圖的例子里面,有一個(gè) 4 列的表,需要定義好每一列數(shù)據(jù)的屬性,比如 code 列是整數(shù)型、client 列是字符串類(lèi)型、time 列是 datetime 類(lèi)型。這些定義好之后,后續(xù)所有的數(shù)據(jù)進(jìn)入到系統(tǒng),必須要符合之前定義的 schema 標(biāo)準(zhǔn),否則就不能寫(xiě)入了,這就是一個(gè)典型的 schema on write 的系統(tǒng)。

如果我們有這樣 3 種類(lèi)型的日志,一個(gè)是 Nginx access log、一個(gè)是 Apache 的 access log、一個(gè)是 windows IIS 的 access log。大家可以看到這些 log 很相像,但格式又不太一樣。但是如果要把這些日志都采集到寫(xiě)時(shí)建模的數(shù)據(jù)庫(kù)里面(藍(lán)色的這條通路),就要去做 ETL 了。針對(duì)三個(gè)不同的日志就需要維護(hù)三個(gè)不同的 ETL 任務(wù)。

(2)讀時(shí)建模(Schema On Read)

讀時(shí)建模的理念是先把原始數(shù)據(jù)存儲(chǔ)下來(lái),即我們把這三份不同產(chǎn)品的原始的日志,直接存儲(chǔ)到我的系統(tǒng)里。比如這里有查詢(xún) 1、查詢(xún) 2 和查詢(xún) 3,大家會(huì)看到針對(duì)每一個(gè)查詢(xún)用的字段不一樣。我們會(huì)在查詢(xún)運(yùn)行的時(shí)候去指定一些字段提取的規(guī)則。比如查詢(xún) 1,要用 method 字段、time 字段和 client 字段,要定義這三個(gè)字段提取的計(jì)算規(guī)則是什么,在查詢(xún)運(yùn)行的時(shí)候,去把這些規(guī)則動(dòng)態(tài)地應(yīng)用到所有的原始日志上面,從中提取出需要的信息。

這個(gè)過(guò)程有一個(gè)專(zhuān)業(yè)的術(shù)語(yǔ),叫做字段提取,英文叫 field extraction。圖中跑 3 次查詢(xún),橙色的箭頭就是一次 field extraction,這樣會(huì)生成一個(gè)預(yù)期的 schema 格式。再針對(duì) schema 格式進(jìn)一步做比如統(tǒng)計(jì)分析、過(guò)濾、轉(zhuǎn)換或者 pivotal 透視等。右邊藍(lán)色的寫(xiě)時(shí)建模是不需要去動(dòng)態(tài)算 schema 的,因?yàn)?schema 已經(jīng)寫(xiě)在這里了,所以每次查的時(shí)候,只要從存儲(chǔ)好的表里面查數(shù)據(jù)就行了。

讀時(shí)建模和寫(xiě)時(shí)建模的共性是它們都是有 schema 的,只不過(guò)讀時(shí)建模的 schema 是動(dòng)態(tài)的。讀時(shí)建模是用硬件的 CPU 算力去換取查詢(xún)的靈活性。假設(shè)要分析一個(gè) user agent,如果使用讀時(shí)建模,那么只需要去定義好 user agent 字段怎么來(lái)的,field extraction 的規(guī)則是什么就可以了。但如果是寫(xiě)時(shí)建模,就要多算一個(gè) user agent 的字段,要做 schema 更改,修改數(shù)據(jù)庫(kù)的表結(jié)構(gòu)。其次,還要把所有的數(shù)據(jù)再定義一個(gè) ETL 的任務(wù)去抽取 user agent 這個(gè)字段,通過(guò)跑批任務(wù)把數(shù)據(jù)重新填入到表中。從解決問(wèn)題的角度來(lái)講都是 OK 的,但是如果經(jīng)常有 schema 變更,或者稱(chēng)之為 schema 的 evolvement,那么用寫(xiě)時(shí)建模代價(jià)是比較高的,因?yàn)槊看握{(diào)整后,還有歷史數(shù)據(jù)需要進(jìn)行重新回填等這樣很繁雜的操作。

任何一個(gè)技術(shù)都不可能是具有全面優(yōu)勢(shì)的,有好處,也會(huì)有缺陷。寫(xiě)時(shí)建模最大的好處就是用空間去換時(shí)間,可以提前做很多優(yōu)化,比如可以針對(duì)字段去做一些索引,讓查詢(xún)跑得更快。甚至可以像現(xiàn)在的 MPP 數(shù)倉(cāng)一樣提前做很多預(yù)計(jì)算、pre-aggregation 等加速后續(xù)的查詢(xún)。

二、讀時(shí)建模技術(shù)的特點(diǎn)

1、讀時(shí)建模和寫(xiě)時(shí)建模的對(duì)比

圖片

大家其實(shí)不難發(fā)現(xiàn)這兩個(gè)流派的區(qū)別,如果我們要查詢(xún)靈活敏捷,就應(yīng)該選讀時(shí)建模。但是如果要求極致的性能和極致的快,而且查詢(xún)不太變化,那么就選擇寫(xiě)時(shí)建模。

讀時(shí)建模有三個(gè)比較明顯的優(yōu)勢(shì),第一個(gè)是查詢(xún)靈活敏捷;第二個(gè)優(yōu)勢(shì)是存儲(chǔ)空間比較小,因?yàn)閷?xiě)時(shí)建模是用存儲(chǔ)空間去換查詢(xún)的時(shí)間,而讀時(shí)建模只存原始數(shù)據(jù),不會(huì)去建索引,也不會(huì)把抽取好的字段再次做存儲(chǔ),所以能夠節(jié)省存儲(chǔ)的成本;第三個(gè)優(yōu)勢(shì)是寫(xiě)入速度快,因?yàn)樽x時(shí)建模只存原始數(shù)據(jù)不建索引,也不做很多預(yù)處理的工作,數(shù)據(jù)進(jìn)入系統(tǒng)的過(guò)程是比較輕量化的。對(duì)于寫(xiě)時(shí)建模來(lái)說(shuō),數(shù)據(jù)要進(jìn)入系統(tǒng),需要做很多工作,首先要整理成合適的 schema,還要保證寫(xiě)進(jìn)來(lái)的時(shí)候可能會(huì)針對(duì)性地去建一些索引、做預(yù)計(jì)算等工作。所以數(shù)據(jù)寫(xiě)入的速度肯定是不如讀時(shí)建??臁?/p>

寫(xiě)時(shí)建模也有自身優(yōu)勢(shì),比如查詢(xún)速度很快。最典型的就是 BI 場(chǎng)景,由于 BI 分析的指標(biāo)都是固定的,查詢(xún)不會(huì)經(jīng)常變化,而且每天要看很多次,每次都希望能查詢(xún)很快。那么通過(guò)寫(xiě)時(shí)建模去做好預(yù)計(jì)算,帶來(lái)的收益是非常大的。

2、讀時(shí)建模的優(yōu)勢(shì)場(chǎng)景

對(duì)比完讀時(shí)建模和寫(xiě)時(shí)建模,讀時(shí)建模的理念是與日志日處理這個(gè)場(chǎng)景天然契合的。前文中提到日志處理的第一個(gè)問(wèn)題是日志量大、存儲(chǔ)成本高,讀時(shí)建模就正好能發(fā)揮其優(yōu)勢(shì)。另外,日志格式很繁雜,不清楚接入的日志到底有多少種格式、多少個(gè) pattern,讀時(shí)建模只要把日志先接入進(jìn)來(lái),之后在使用中發(fā)現(xiàn)有新的 pattern 出現(xiàn)時(shí),只需要定義新的字段提取規(guī)則,就能夠響應(yīng)各種各樣的數(shù)據(jù)格式變化需求。甚至已經(jīng)接入的日志格式有變化的時(shí)候,依舊可以通過(guò)調(diào)整讀時(shí)建模的字段提取規(guī)則,很好地去處理 schema evolvement 的情況。日志查詢(xún)的時(shí)候,有很多 Ad hoc 查詢(xún)的情況。這種查詢(xún)很多時(shí)候都是沒(méi)有出現(xiàn)在常規(guī)的業(yè)務(wù)報(bào)表查詢(xún)里面,經(jīng)常會(huì)利用一些想要用的動(dòng)態(tài)字段來(lái)做過(guò)濾和加工。這種場(chǎng)景用讀時(shí)建模也是有天然的優(yōu)勢(shì)的,能夠節(jié)省很多的成本。

所以總結(jié)下來(lái),讀時(shí)建模技術(shù)流派用相對(duì)廉價(jià)的硬件的 CPU、內(nèi)存這些算力,去換取了更快速的數(shù)據(jù)處理的需求落地時(shí)間,可以讓整個(gè)端到端的處理變得更加快速和便捷。

三、鴻鵠-免費(fèi)的?站式異構(gòu)數(shù)據(jù)即時(shí)分析平臺(tái)

圖片

介紹完技術(shù)流派,再來(lái)回顧一下這兩個(gè)流派的日志處理產(chǎn)品。Splunk 是 schema on read 流派的開(kāi)山鼻祖。但是 Splunk 整個(gè)架構(gòu)其實(shí)相對(duì)來(lái)講還是比較經(jīng)典的 MPP(Shared Nothing)架構(gòu),隨著云的 Infra 越來(lái)越成熟之后,無(wú)法滿(mǎn)足異構(gòu)數(shù)據(jù)處理的需求。有很長(zhǎng)一段時(shí)間的產(chǎn)品都是以寫(xiě)時(shí)建模為主,比如 ES、ClickHouse 等。到 2018 年以后,出現(xiàn)了 Grafana 的 Loki 這樣一個(gè)產(chǎn)品,它是偏向于讀時(shí)建模的。2020 年,炎凰數(shù)據(jù)推出了主打讀時(shí)建模的鴻鵠。

這里要明確一點(diǎn),所有的產(chǎn)品在這里劃分的流派,只是它偏向于哪一個(gè),不代表這個(gè)產(chǎn)品只能做這一個(gè)。比如炎凰數(shù)據(jù)平臺(tái),雖然是主打 schema on read,但同時(shí)也有 schema on write 的能力。當(dāng)一個(gè)分析任務(wù)固化之后,schema 已經(jīng)確定了,很少改動(dòng),就可以把這些字段提取的邏輯固化下來(lái),讓這些字段提取先預(yù)計(jì)算,并把預(yù)計(jì)算的結(jié)果先存好,用空間換時(shí)間。再比如 ClickHouse 的寫(xiě)時(shí)建模很強(qiáng)大,它能夠讓查詢(xún)變得很快。但是 ClickHouse 最近的版本里面也提供了動(dòng)態(tài)解析 JSON,即動(dòng)態(tài)地去解析一個(gè) JSON 的 column 字段,也是某種最簡(jiǎn)單直白的 schema on read 的實(shí)現(xiàn)方法。所以總的來(lái)說(shuō),schema on read 和 schema on write 兩個(gè)手段都會(huì)需要用到。

四、鴻鵠 SQL 和鴻鵠的讀時(shí)建模引擎

1、讀時(shí)建模在炎凰的實(shí)踐

圖片

接下來(lái)就來(lái)介紹炎凰數(shù)據(jù)平臺(tái)——鴻鵠。它定位為一個(gè)一站式的異構(gòu)數(shù)據(jù)即時(shí)分析平臺(tái)。這里有三個(gè)關(guān)鍵詞:一站式、異構(gòu)和即時(shí)。

一站式指的是,整個(gè)炎凰數(shù)據(jù)平臺(tái)會(huì)像 ELK 那樣,有一個(gè)讀時(shí)建模的存儲(chǔ)計(jì)算的核心引擎。在這個(gè)之上有一些基礎(chǔ)的服務(wù),比如數(shù)據(jù)可視化的儀表盤(pán)服務(wù)、數(shù)據(jù)接入服務(wù)、權(quán)限管理服務(wù)、用戶(hù)認(rèn)證的告警管理服務(wù)等。它像是一個(gè)中間層的服務(wù),我們希望提供一個(gè)一站式的日志處理的開(kāi)箱即用體驗(yàn),把系統(tǒng)裝好之后,就可以通過(guò) UI 快速導(dǎo)入數(shù)據(jù),接入數(shù)據(jù)在 UI 上面就進(jìn)行查詢(xún)分析了,甚至是做一些可視化。一站式最大的好處就是降低用戶(hù)的運(yùn)維成本。

第二個(gè)關(guān)鍵詞是異構(gòu),是鴻鵠很重要的一個(gè)屬性,也是讀時(shí)建模引擎來(lái)保證的。

第三個(gè)關(guān)鍵詞是即時(shí)分析,系統(tǒng)能夠很好地響應(yīng) Ad hoc 需求。并且鴻鵠上面有很多接口的擴(kuò)展,我們從一開(kāi)始設(shè)計(jì)系統(tǒng)的時(shí)候,就希望系統(tǒng)能夠盡可能地開(kāi)放,所以我們會(huì)提供一些標(biāo)準(zhǔn)的 API,比如所有服務(wù)都有 REST API,還有一些 Java script SDK,能夠讓用戶(hù)非常方便地去把鴻鵠當(dāng)成一個(gè)底層的數(shù)據(jù)庫(kù)來(lái)使用。

2、鴻鵠中的數(shù)據(jù)存儲(chǔ)

圖片

下面介紹如何在鴻鵠當(dāng)中去設(shè)計(jì)讀時(shí)建模。要討論讀時(shí)建模,分為存儲(chǔ)和計(jì)算兩部分。

首先來(lái)介紹存儲(chǔ)。鴻鵠的數(shù)據(jù)存儲(chǔ)沒(méi)有表結(jié)構(gòu)的概念,也就是數(shù)據(jù)進(jìn)入到鴻鵠的時(shí)候,不需要定義有幾個(gè)字段,以及這些字段是整型還是字符串。所以總的來(lái)說(shuō),我們定義了數(shù)據(jù)集,大家可以把它理解為是一個(gè)數(shù)據(jù)的容器??梢园迅鞣N各樣不同格式的日志,簡(jiǎn)單、快速地放到容器中。

我們將容器里存儲(chǔ)的對(duì)象抽象成了 event 事件這樣一個(gè)概念,每個(gè)日志就是一個(gè)事件,日志上包含一個(gè)時(shí)間戳,記錄了某個(gè)時(shí)點(diǎn)發(fā)生了什么事情。同時(shí)我們的存儲(chǔ)模型抽象上還做了一些元信息字段的定義,它標(biāo)識(shí)了日志是什么系統(tǒng)生成的、可能是什么格式等。

這里的時(shí)間戳字段是整數(shù)型,之所以不用存字符串形式是因?yàn)樗械牟樵?xún)都會(huì)有一個(gè)時(shí)間窗口的概念,在日志分析里面時(shí)間窗是一個(gè)天然用來(lái)做過(guò)濾的條件。所以我們把時(shí)間戳提取出來(lái),變成整數(shù),并且對(duì)時(shí)間戳的字段做一個(gè)索引,這樣能夠提供更快的查詢(xún)效率。

假設(shè)一開(kāi)始數(shù)據(jù)集是空的,現(xiàn)在放了一條日志進(jìn)來(lái),這條日志有五個(gè)字段或者列。接下來(lái)又來(lái)了兩條不同的日志,而且第二條日志除了有數(shù)據(jù)類(lèi)型、主機(jī)和數(shù)據(jù)源的這幾個(gè)字段之外,還多了一個(gè)叫環(huán)境的字段,那么鴻鵠提供的可自定義擴(kuò)展的元信息字段就能很好地幫你解決這個(gè)問(wèn)題。后面有更多的元字段信息進(jìn)來(lái)的時(shí)候,鴻鵠平臺(tái)也是能夠支持存儲(chǔ)的,并且不需要在定義數(shù)據(jù)集的時(shí)候聲明。在鴻鵠平臺(tái)上,數(shù)據(jù)集的 schema 具有支持橫向擴(kuò)展的特性。而且整個(gè) schema 的變化,對(duì)用戶(hù)是無(wú)感的。因?yàn)槟銊?chuàng)建數(shù)據(jù)集和導(dǎo)入數(shù)據(jù)的時(shí)候,都不需要關(guān)心 schema 是什么。查詢(xún)的時(shí)候,比如有新的 environment 字段,就可以針對(duì) environment 元信息字段去做過(guò)濾,這也是存儲(chǔ)引擎和計(jì)算引擎自動(dòng)去保證的。對(duì)用戶(hù)來(lái)講,不需要做任何數(shù)據(jù)庫(kù) DDL。

圖片

在存儲(chǔ)的邏輯模型清楚之后,再來(lái)介紹一下存儲(chǔ)中用到的一些技術(shù)的選型和大概的思路。

(1)按時(shí)間分片

首先面對(duì)大量的日志數(shù)據(jù),其實(shí)我們沒(méi)有辦法把所有的日志數(shù)據(jù)全存到一個(gè)文件,而是需要對(duì)數(shù)據(jù)去做分片。默認(rèn)的分片就是按照時(shí)間戳來(lái)分,因?yàn)樗械牟樵?xún)都會(huì)要有時(shí)間戳過(guò)濾,這樣能夠達(dá)到比較好的查詢(xún)效率。

(2)每片數(shù)據(jù)采用列式存儲(chǔ)

列式存儲(chǔ)往往是和寫(xiě)時(shí)建模系統(tǒng)一起配合使用的,為什么讀時(shí)建模也會(huì)有列式存儲(chǔ)呢?其實(shí)如果我們把數(shù)據(jù)集抽象成是只有這五個(gè)字段的一張表,那么每一個(gè)字段也都是按列存儲(chǔ)的。所以底層存的時(shí)候是把每一列都按照列式存儲(chǔ)下來(lái),只不過(guò)每一個(gè)數(shù)據(jù)分片上面的列數(shù)可能不一樣。因?yàn)橛?schema evolvement,所以相當(dāng)于每一個(gè)數(shù)據(jù)分片里的列式可能不同,但是每一列還是按照列式存儲(chǔ)。用列式存儲(chǔ)的初衷其實(shí)也很簡(jiǎn)單,因?yàn)榈谝晃覀冎惶峁┓治鲂头?wù),用列存能夠很好地去配合向量計(jì)算,做到數(shù)據(jù)處理的提速。這也是當(dāng)前 OLAP 系統(tǒng)的一個(gè)標(biāo)配。第二原因是使用列式存儲(chǔ)可以提高數(shù)據(jù)的壓縮比,數(shù)據(jù)壓縮比越高存儲(chǔ)成本越低。

圖片

為了支持 Ad hoc 查詢(xún)和一些快速的檢索查詢(xún),系統(tǒng)默認(rèn)只做兩個(gè)索引。這里也是為了平衡存儲(chǔ)膨脹的開(kāi)銷(xiāo)和查詢(xún)的效率所做的一個(gè)折中。因?yàn)樗饕龅迷蕉嗖樵?xún)?cè)娇?,但存?chǔ)成本也越高。但如果不建任何索引,查詢(xún)速度又會(huì)較低。所以我們綜合了日志場(chǎng)景中最常用的兩類(lèi)查詢(xún),創(chuàng)建了時(shí)間戳索引和倒排索引。

(3)時(shí)間戳索引

第一類(lèi)時(shí)間戳索引是帶上時(shí)間范圍的,比如運(yùn)維場(chǎng)景中,基本都是查過(guò)去 5 分鐘、半小時(shí)或者其它時(shí)間范圍內(nèi)的日志,所以我們會(huì)針對(duì)日志的時(shí)間做一個(gè)索引,每次查詢(xún)的時(shí)候,都會(huì)用到時(shí)間戳的索引來(lái)加速查詢(xún)。

(4)倒排索引

第二類(lèi)是會(huì)比較輕量化的倒排索引(inverted index)。之所以叫輕量化是為了和 search engine 區(qū)分開(kāi)來(lái),搜索引擎不僅有倒排索引,還會(huì)有 scoring 和 ranking 的問(wèn)題。但是在我們的系統(tǒng)里面不做 scoring 和 ranking,只是去做關(guān)鍵詞到日志的倒排。比如在上圖查詢(xún)包含了 evaluation 單詞的日志有哪些,這個(gè)時(shí)候會(huì)命中到橙色的第 1 條和第 2 條。如果查詢(xún)包含了 login 是哪一個(gè),可以命中到第三條。在倒排索引上面,有一些簡(jiǎn)單的與或邏輯,能夠讓查詢(xún)變得更加快速。比如要查既包含 evaluation 又包含 login,那么很快就可以回答出來(lái)是個(gè)空集,就不需要讀任何數(shù)據(jù)。之所以要做這樣的索引,是因?yàn)橥笞鲎x時(shí)建模的從原始數(shù)據(jù)去提取字段的時(shí)候,都是要消耗 CPU 去計(jì)算,如果能在更早時(shí)候就排除掉一些完全沒(méi)有必要命中的數(shù)據(jù),就能夠節(jié)省掉這些不必要的 CPU 開(kāi)銷(xiāo),查詢(xún)也會(huì)非常快速。

所以在我們的系統(tǒng)里,所有圍繞優(yōu)化的思路都會(huì)把數(shù)據(jù)的過(guò)濾盡可能地推到讀時(shí)建模、字段提取這件事情之前。比如包含關(guān)鍵字在有的時(shí)候可以推斷出來(lái)它可以隱含關(guān)鍵字過(guò)濾。比如要看某一個(gè)字段是不是等于 evaluation,首先也可以翻譯成先查詢(xún)包含 evaluation 關(guān)鍵詞的日志再去做過(guò)濾,這樣能夠盡可能更早地把這些數(shù)據(jù)過(guò)濾掉,平臺(tái)內(nèi)部會(huì)有很多的這樣的優(yōu)化手段。

3、鴻鵠里的計(jì)算引擎

接下來(lái)介紹計(jì)算部分。

圖片

(1)Schemaless SQL

采用了 SQL 接口來(lái)做計(jì)算。上圖中可以看到 From 子句后面是一個(gè)數(shù)據(jù)集,它能查詢(xún)出不同格式的日志。綠色框中是一個(gè) key-value 結(jié)構(gòu)的日志、紅色框中是一個(gè) JSON 結(jié)構(gòu)的日志。鴻鵠讀時(shí)建模引擎可以自動(dòng)解析 key-value 和 JSON 格式的數(shù)據(jù),并且不需要做任何配置。

圖片

比如在上圖中,可以直接引用到 http.url 和 http.method,這些字段是從 JSON body(上一個(gè)圖)里面解析出來(lái)的,系統(tǒng)會(huì)自動(dòng)幫你完成。同時(shí)這些 key-value 里面也會(huì)有解析出來(lái)的字段,就是我們這里拿到的 url 和 method。上圖中有兩個(gè)不同的 data type,一個(gè)是 audit 格式的審計(jì)日志,一個(gè)是 JSON 格式的 access log。自然而然會(huì)產(chǎn)生一個(gè)需求,url 和 http.url 應(yīng)該是同一個(gè)意思,我們希望它們合并到同一個(gè)列;method 和 http.method 也是同一個(gè)語(yǔ)義,也合并成同一個(gè)列。這在鴻鵠的讀時(shí)建模引擎中很簡(jiǎn)單,它提供了大量的標(biāo)量函數(shù),做字段的轉(zhuǎn)換和變換。

圖片

比如上圖中這個(gè)簡(jiǎn)單的例子,可以用 coalesce() 函數(shù)把 URL 字段和 HTTP 的 URL 字段歸一化成一個(gè) URL 字段。大家會(huì)發(fā)現(xiàn),其實(shí) SQL 表達(dá)的就是一個(gè)讀時(shí)建模,它建立的模型是把剛才 audit log 和 access log 中的 URL 字段和 method 字段整理成一個(gè)表的結(jié)構(gòu),一旦成表結(jié)構(gòu)之后,這個(gè)表就是一個(gè)所謂的模型。它們的理念其實(shí)特別相似,編程里面有個(gè) Duck typing(鴨子類(lèi)型)的問(wèn)題,就是建完模型之后不必關(guān)心底層數(shù)據(jù)到底是從哪里來(lái)的,有 URL 就可以用 URL 這個(gè)字段。就像鴨子類(lèi)型一樣,反正看起來(lái)像鴨子,就把它當(dāng)鴨子用就好了。就是這樣一個(gè)理念,只不過(guò)在 ETL 的世界里面,我們要先在數(shù)據(jù)庫(kù)里定義一個(gè)表結(jié)構(gòu),并把 SQL 的邏輯寫(xiě)成 ETL 流水線,然后再把數(shù)據(jù)插入進(jìn)來(lái)。

圖片

(2)標(biāo)量函數(shù)+表函數(shù)

我們?cè)賮?lái)看一些更復(fù)雜有趣的事情。日志外層是 key-value 的結(jié)構(gòu),但是在 header 字段里面,其實(shí)是一個(gè) JSON 的結(jié)構(gòu)。在分析日志的時(shí)候往往很難在第一次就定義好需要哪些字段。除了用 header 字段之外,隨著業(yè)務(wù)的演進(jìn)或者問(wèn)題排查的深入之后,還要用 header 里面的字段。鴻鵠讀時(shí)建模引擎提供了標(biāo)量函數(shù)和表函數(shù)這樣的概念,幫助大家使用 SQL 來(lái)做字段的變換和提取。

圖片

(3)用 SQL 做字段提取

具體的做法很簡(jiǎn)單,大家可以看到其實(shí)很簡(jiǎn)單的一些 SQL 就是 parse_json 這樣的一個(gè)功能。parse_json 的核心就是把 JSON 的 header 字符串 flatten 開(kāi)來(lái),展開(kāi)成我們要的字段。在展開(kāi)之后,我們可以很容易地去對(duì)這些字段進(jìn)行過(guò)濾。因?yàn)橐坏┧纬勺侄沃?,就跟?shù)據(jù)庫(kù)里表的字段沒(méi)有任何區(qū)別了。

另外值得一提的是,第一行數(shù)據(jù)的 JSON 其實(shí)是沒(méi)有 accept、encoding、Referer 這些的,因?yàn)?JSON 字段相對(duì)比較少。但是在第二行的 JSON 里面字段是很多的,在用 parse_json() 函數(shù)展開(kāi)之后,讀時(shí)建模引擎會(huì)自動(dòng)去做兩個(gè)展開(kāi)表的 Schema 統(tǒng)合,我們稱(chēng)之為 union 的工作。而且會(huì)把這一行上不存在的字段變成 null 值,我們就可以很快地做出一張大寬表了,而做這個(gè)表的時(shí)候也不需要特別定義很多的表結(jié)構(gòu),這一切都是 schema 的 involvement,都由讀時(shí)建模引擎來(lái)處理。

(4)SQL函數(shù)

大量的函數(shù)在讀時(shí)建模時(shí)都要經(jīng)常被調(diào)用,所以這些函數(shù)的性能是非常重要的。為了保證這些函數(shù)具備比較好的性能,我們一方面會(huì)盡可能地用向量計(jì)算,還有一些函數(shù)會(huì)去做 JIT 加速,把它編譯成一些更快的可執(zhí)行字節(jié)碼,而不是用編譯執(zhí)行單元的方式來(lái)做。這些都是一些很細(xì)節(jié)的優(yōu)化。

圖片

(5)SQL CTE

還有一個(gè)概念是數(shù)據(jù)處理的流水線(pipeline)。很多小伙伴可能感覺(jué) SQL 很難寫(xiě),因此我們?cè)谧x時(shí)建模引擎里面支持了一個(gè)叫 CTE 的語(yǔ)法,上圖中的 SQL 語(yǔ)句就是個(gè)典型的 CTE 語(yǔ)法。如果查詢(xún)復(fù)雜,比如三步四步,我們就把每一步寫(xiě)在這個(gè) common table expression 里面就可以了,會(huì)串行執(zhí)行,依次執(zhí)行第一步、第二步、第三步等等。

這樣書(shū)寫(xiě)的一個(gè)好處是邏輯上代碼更可讀,第二是調(diào)試的時(shí)候也更簡(jiǎn)單。

圖片

(6)復(fù)用建模邏輯

讀時(shí)建模的模型是一段 SQL,要將其固化和存儲(chǔ)下來(lái)也是一個(gè)必須要解決的問(wèn)題。我們?cè)?SQL 引擎里也有創(chuàng)建視圖這樣的功能,可以把一個(gè)模型的封裝邏輯寫(xiě)在視圖中。這樣就可以把建模的邏輯和后續(xù)基于模型的分析的邏輯做一個(gè)比較好的解耦,當(dāng)建模的邏輯有變化時(shí),只需要去調(diào)整視圖的邏輯即可,不需要去更改后續(xù)的分析邏輯。

(7)查詢(xún)加速

鴻鵠平臺(tái)也會(huì)去想辦法在寫(xiě)時(shí)建模的理念下去做一些查詢(xún)加速,其中最典型的一個(gè)做法就是物化視圖。比如我們把 url、method 這樣的一個(gè)視圖變成物化視圖,這些 url 和 method 就會(huì)被實(shí)際存在物理磁盤(pán)上。下次再查詢(xún)的時(shí)候,就不需要再計(jì)算了,是用空間去換時(shí)間。

這里的物化視圖與一些數(shù)據(jù)庫(kù)的物化視圖有一點(diǎn)不一樣。我們的物化視圖自帶時(shí)序?qū)傩?,?dāng)發(fā)現(xiàn)有新的數(shù)據(jù)進(jìn)入 my_eventset 的時(shí)候就會(huì)去調(diào)用相應(yīng)的物化視圖邏輯去把最新的數(shù)據(jù)物化。這對(duì)于終端用戶(hù)是透明的,所以對(duì)于用戶(hù)來(lái)說(shuō)只是定義了一個(gè)物化視圖的模型,后續(xù)會(huì)發(fā)現(xiàn)查詢(xún)這個(gè)模型的速度比普通視圖要更加快捷。