數(shù)據(jù)收集工具的設(shè)計(jì)與最佳實(shí)踐

大數(shù)據(jù)

作者:孫健波

數(shù)據(jù)收集工具對(duì)比

目前社區(qū)已經(jīng)不乏大量?jī)?yōu)秀的數(shù)據(jù)收集工具,如有名的 Elastic Stack(Elasticsearch、Logstash、Kibana)中的 Logstash;CNCF 基金會(huì)里面有名的 Fluentd;InfluxData 公司 TICK Stack 中的 Telegraf;Google 出品為 Kubernetes 定制的 cAdvisor;Apache 基金會(huì)中的頂級(jí)項(xiàng)目 Flume。除了早期誕生的諸如 Fluentd、Flume 等項(xiàng)目,其他項(xiàng)目都是為特定的平臺(tái)業(yè)務(wù)定制而成,然后在隨后的開(kāi)源中不斷進(jìn)化,變得更為通用。所以針對(duì)特定業(yè)務(wù)量身定制一款數(shù)據(jù)收集工具,是一個(gè)較為普遍的需求,也是出現(xiàn)如此多“輪子”的主要原因。

讓我們先來(lái)看看這幾種知名開(kāi)源數(shù)據(jù)收集工具有哪些特點(diǎn)。

Flume: 毋庸置疑,在流式數(shù)據(jù)處理的場(chǎng)景中,F(xiàn)lume 絕對(duì)是開(kāi)源產(chǎn)品中的不二選擇。其架構(gòu)分為 Source、Channel、Sink 三部分,分別負(fù)責(zé)從上游服務(wù)端獲取數(shù)據(jù)、暫存數(shù)據(jù)以及解析并發(fā)送到下游。Flume 尤以靈活的擴(kuò)展性和強(qiáng)大的容錯(cuò)處理能力著稱,非常適合在大數(shù)據(jù)量的情況下做數(shù)據(jù)解析、中轉(zhuǎn)以及上下游適配的工作。另一方面,F(xiàn)lume 也有一些缺陷,如解析與發(fā)送都耦合在 Sink 模塊,用戶在編寫(xiě) Sink 插件時(shí)不得不編寫(xiě)解析的邏輯,無(wú)法復(fù)用一些常規(guī)的解析方式;依賴 JVM 運(yùn)行環(huán)境,作為服務(wù)端程序可以接受,但是部署和運(yùn)行一個(gè)數(shù)據(jù)收集客戶端程序則變得相對(duì)笨重;Flume 的配置融合了 Channel 部分,基本配置并不簡(jiǎn)單,用戶想用起來(lái)需要的前置知識(shí)較多。Logstash: 隨著 Elastic Stack 廣受熱捧,Logstash 自然也成為了技術(shù)圈家喻戶曉的工具,而 Logstash 本身的強(qiáng)大功能也確實(shí)名副其實(shí),其架構(gòu)分為 Inputs、Filters 以及 Outputs 三部分。Inputs 作為所有輸入端的集合,包含了各類數(shù)據(jù)輸入插件;Filters 包括解析與數(shù)據(jù)轉(zhuǎn)換兩部分的插件集合,其中就包含了大名鼎鼎的 Grok 解析方式,幾乎可以解析所有類型的數(shù)據(jù);Outputs 則是輸出端的集合。毫無(wú)疑問(wèn),Logstash 幾乎是使用 Elastic Stack 方案時(shí)作為數(shù)據(jù)收集的唯一選擇。但是同樣的,Logstash 也是基于 JVM 運(yùn)行的,作為一個(gè)客戶端程序相對(duì)較重;當(dāng)你希望把它作為一個(gè) agent 收集一些機(jī)器的基本信息時(shí),它也無(wú)能為力。于是除了 Logstash 之外 Elastic Stack 家族中又增加了 beats 這個(gè)成員,但是如果僅僅選擇 beats,其功能又太過(guò)單薄。Fluentd: Fluentd 也是數(shù)據(jù)收集界的老牌重量級(jí)選手,如果你玩容器、玩 Kubernetes,那么就一定聽(tīng)說(shuō)過(guò) CNCF(Cloud Native Computing Foundation),而 Fluentd 就是其中的一員,成為了容器圈里多數(shù)人日志收集處理的首選。Fluentd 的架構(gòu)與 Logstash 相似,也大致分為輸入、輸出以及中間的處理層,但與之不同的是,其中間的處理層除了包括常規(guī)的 filter(解析) 以及 buffer(數(shù)據(jù)暫存) 以外,還包含了一個(gè) routing(路由) 功能,這是 Fluentd 的一大特色。routing 功能使得 Fluentd 能夠?qū)⒆约悍Q為一個(gè)統(tǒng)一的日志管理中間層,將所有的數(shù)據(jù)輸入和輸出管理起來(lái),按照需求將輸入的數(shù)據(jù)路由到一個(gè)或多個(gè)輸出端。這是一個(gè)非常先進(jìn)的設(shè)計(jì),其他類似的開(kāi)源軟件往往要寫(xiě)多份配置文件才能達(dá)到這個(gè)效果。Fluentd 由 CRuby 實(shí)現(xiàn),性能表現(xiàn)優(yōu)良但依賴 Ruby 環(huán)境;相較于前面兩者,F(xiàn)luentd 插件支持相對(duì)較少;其配置也過(guò)于復(fù)雜,使用門檻較高。Telegraf/cAdvisor: 這兩款均是 Go 語(yǔ)言編寫(xiě)的針對(duì)系統(tǒng)信息數(shù)據(jù)收集的開(kāi)源工具,其側(cè)重點(diǎn)在 metric 收集,相較于通用的日志收集和處理,其功能面較窄,但是性能方面均表現(xiàn)優(yōu)異。Telegraf 配合 influxdb,可以讓你對(duì)機(jī)器各個(gè)維度的信息了如指掌;而 cAdvisor 更是 Kubernetes 的親兒子,處理容器資源信息幾無(wú)敵手。但是這兩款工具并無(wú)意于發(fā)力通用數(shù)據(jù)收集的功能,功能上可能無(wú)法滿足一些日志收集的場(chǎng)景。

了解了以上這些開(kāi)源軟件的特點(diǎn)后,下面我們開(kāi)始深入介紹構(gòu)建一款數(shù)據(jù)收集工具會(huì)遇到哪些設(shè)計(jì)與挑戰(zhàn),以此為你的業(yè)務(wù)量身定制。

數(shù)據(jù)收集工具設(shè)計(jì)

架構(gòu)設(shè)計(jì)

主流數(shù)據(jù)收集工具的主架構(gòu)基本分為 reader、parser,以及 sender 三部分,如圖 1 所示。除了這三個(gè)日志收集常規(guī)組成部分,還應(yīng)該包含可選模塊,如基于解析過(guò)后的數(shù)據(jù)轉(zhuǎn)換 (filter/transformer) 以及數(shù)據(jù)暫存管道 (Channel/Buffer)。為了盡可能復(fù)用,每個(gè)組成部分都應(yīng)該是插件式的,可以編寫(xiě)不同類型插件并且靈活地組裝。Channel/Buffer 部分也應(yīng)該提供基于內(nèi)存或者基于磁盤(pán)的選擇。

大數(shù)據(jù)

圖 1 數(shù)據(jù)收集架構(gòu)設(shè)計(jì)

對(duì)于 Reader、Parser、Sender 等插件共同組裝的業(yè)務(wù)數(shù)據(jù)收集單元,我們稱之為一個(gè)運(yùn)行單元 (Runner),數(shù)據(jù)收集工具必須可以同時(shí)運(yùn)行多個(gè) Runner,且每個(gè) Runner 可以支持更新。

更新可以通過(guò)多種方式實(shí)現(xiàn),最常規(guī)的是手動(dòng)更新配置然后重啟;更好的設(shè)計(jì)是支持熱更新,不需要重啟,自動(dòng)識(shí)別配置文件的變化;還可以設(shè)計(jì)一個(gè)漂亮的 web 界面做配置的變更,以此引導(dǎo)用戶使用并解決數(shù)據(jù)收集配置復(fù)雜、用戶使用門檻高的難題。所以在整體架構(gòu)之上還應(yīng)該構(gòu)建一個(gè)簡(jiǎn)單的 API 層,支持 web 界面的功能。

語(yǔ)言選擇

數(shù)據(jù)收集屬于輕量級(jí)的 agent 服務(wù),一般選擇的語(yǔ)言為 C/C++ 或者近年來(lái)特別火熱的 Go,而 Go 語(yǔ)言已經(jīng)成為這類數(shù)據(jù)收集工具編寫(xiě)的大眾選擇,如 Logstash 新開(kāi)發(fā)的 beats 工具、Telegraf、cAdvisor 等等,均使用 Go 語(yǔ)言開(kāi)發(fā)。

社區(qū)已經(jīng)有很多文章描述使用 Go 語(yǔ)言的好處,在此就不再贅述。總體而言用 Go 語(yǔ)言開(kāi)發(fā)門檻較低,性能優(yōu)良,支持跨多種操作系統(tǒng)平臺(tái),部署也極為簡(jiǎn)便。

分模塊設(shè)計(jì)

數(shù)據(jù)讀取模塊(Reader)

顧名思義,數(shù)據(jù)讀取模塊負(fù)責(zé)從不同數(shù)據(jù)源中讀取數(shù)據(jù),設(shè)計(jì) Reader 模塊的時(shí)候,需要支持插件式數(shù)據(jù)源接入,且將接口設(shè)計(jì)得足夠簡(jiǎn)單,方便大家一同貢獻(xiàn)更多的讀取數(shù)據(jù)源驅(qū)動(dòng)。

自定義數(shù)據(jù)源,最基本的只需要實(shí)現(xiàn)如下兩個(gè)方法即可。

ReadLine() stringSyncMeta() error

從數(shù)據(jù)來(lái)源上分類,數(shù)據(jù)讀取大致可分為從文件讀取、從數(shù)據(jù)存儲(chǔ)服務(wù)端讀取以及從消息隊(duì)列中讀取三類。

每一類 Reader 均在發(fā)送成功后通過(guò) SyncMeta() 函數(shù)記錄讀取的位置,保證數(shù)據(jù)不會(huì)因?yàn)?runner 意外中斷而丟失。

從文件讀取數(shù)據(jù)?最為常見(jiàn),針對(duì)文件的不同 rotate 方式,有不同的讀取模式,主要分為三類:

file 模式:使用 file 模式的經(jīng)典日志存儲(chǔ)方式類似于 nginx 的日志 rotate 方式,日志名稱是固定的,如access.log,rotate 時(shí)直接 move 成新的文件如access.log.1,新的數(shù)據(jù)仍然寫(xiě)入到access.log。即我們永遠(yuǎn)只針對(duì)access.log這一個(gè)固定名稱的文件進(jìn)行收集。而檢測(cè)文件是否 rotate 的標(biāo)志是文件的 inode 號(hào),在 windows 下則是 fd 的屬性編號(hào)。當(dāng)文件 rotate 后,則從文件頭開(kāi)始讀取。dir 模式:使用 dir 模式的經(jīng)典日志存儲(chǔ)方式為整個(gè)文件夾下存儲(chǔ)單個(gè)服務(wù)的業(yè)務(wù)日志,文件夾下的日志通常有統(tǒng)一前綴,后綴為時(shí)間戳,根據(jù)日志的大小 rotate 到新的文件。如配置的文件夾為 logdir,下面的文件為?logdir/a.log.20170621,?logdir/a.log.20170622,?logdir/a.log.20170623, …。每次分割后新命名文件并以時(shí)間戳為后綴,并且該文件夾下只有這一個(gè)服務(wù)。dir 模式首先會(huì)對(duì)文件夾下文件整體排序,依次讀取各個(gè)文件,讀完最后一個(gè)文件后會(huì)查找時(shí)間 (文件 ctime) 更新文件并重新排序,依次循環(huán)。dir 模式應(yīng)該將多個(gè)文件數(shù)據(jù)串聯(lián)起來(lái),即數(shù)據(jù)讀取過(guò)程中 a.log.20170621 中最后一行的下一行就是 a.log.20170622 的第一行。該模式下自然還包括諸如文件前綴匹配、特定后綴忽略等功能。tailx 模式:以通配的路徑模式讀取,讀取所有被通配符匹配上的日志文件,對(duì)于單個(gè)日志文件使用 file 模式不斷追蹤日志更新,例如匹配路徑的模式串為?/home/*/path/*/logdir/*.log*, 此時(shí)會(huì)展開(kāi)并匹配所有符合該表達(dá)式的文件,并持續(xù)讀取所有有數(shù)據(jù)追加的文件。每隔一定時(shí)間,重新獲取一遍模式串,添加新增的文件。

除此之外,還應(yīng)支持包括多文件編碼格式支持、讀取限速等多種功能。

從數(shù)據(jù)存儲(chǔ)服務(wù)中讀取數(shù)據(jù),可以采用時(shí)間戳策略,在諸如 MongoDB、MySQL 中記錄的數(shù)據(jù),包含一個(gè)時(shí)間戳字段,每次讀取數(shù)據(jù)均按這個(gè)時(shí)間戳字段排序,以此獲得新增的數(shù)據(jù)或者數(shù)據(jù)更新。另一方面,需要為用戶設(shè)計(jì)類似定時(shí)器等策略,方便用戶多次運(yùn)行,不斷同步收集服務(wù)器中的數(shù)據(jù)。

從消息隊(duì)列中讀取數(shù)據(jù),這個(gè)最為簡(jiǎn)單,直接從消息隊(duì)列中消費(fèi)數(shù)據(jù)即可。注意記錄讀取的 Offset,防止數(shù)據(jù)丟失。

解析模塊 (Parser)

解析模塊負(fù)責(zé)將數(shù)據(jù)源中讀取的數(shù)據(jù)解析到對(duì)應(yīng)的字段及類型,目前常見(jiàn)的解析器包括:

csv parser: 按照分隔符解析成對(duì)應(yīng)字段和類型,分隔符可以自定義,如常見(jiàn)的制表符 (\t)、空格 (?)、逗號(hào) (,) 等等。json parser: 解析 json 格式的數(shù)據(jù),json 是一種自帶字段名稱及類型的序列化協(xié)議,解析 json 格式僅需反序列化即可?;谡齽t表達(dá)式 (grok) parser: Logstash grok 解析非常強(qiáng)大,但是它并不指定類型,而 Telegraf 做了一個(gè)增強(qiáng)版的 grok 解析器,除了基本的正則表達(dá)式和字段名稱,還能標(biāo)志數(shù)據(jù)類型,基本上能標(biāo)志數(shù)據(jù)類型的 grok 解析器已經(jīng)是一個(gè)完備的數(shù)據(jù)解析器了,可以解析幾乎所有數(shù)據(jù)。當(dāng)然,類型解析是相對(duì)復(fù)雜的功能,可能涉及到具體業(yè)務(wù),如時(shí)間類型等。raw parser: 將讀取到的一行數(shù)據(jù)作為一個(gè)字段返回,簡(jiǎn)單實(shí)用。nginx/apache parser: 讀取 nginx/apache 等常見(jiàn)配置文件,自動(dòng)生成解析的正則表達(dá)式,解析 nginx/apache 日志。

除了以上幾種內(nèi)置的解析器,同 Reader 一樣,你也需要實(shí)現(xiàn)自定義解析器的插件功能,而 Parser 極為簡(jiǎn)單,只需要實(shí)現(xiàn)最基本的 Parse 方法即可。

Parse(lines []string) (datas []sender.Data, err error)

每一種 Parser 都是插件式結(jié)構(gòu),可以復(fù)用并任意選擇。在不考慮解析性能的情況下,上述幾種解析器基本可以滿足所有數(shù)據(jù)解析的需求,將一行行數(shù)據(jù)解析為帶有 Schema(具備字段名稱及類型)的數(shù)據(jù)。但是當(dāng)你希望對(duì)某個(gè)字段做操作時(shí),純粹的解析器可能不夠用。于是作為補(bǔ)充,數(shù)據(jù)收集工具還需要提供 Transformer/Filter 的功能。

Transformer

Transformer 是 Parser 的補(bǔ)充,針對(duì)字段進(jìn)行數(shù)據(jù)變化。

舉例來(lái)說(shuō),如果你有個(gè)字段想做字符串替換,比如將所有字段名稱為”name”的數(shù)據(jù)中,值為”Tom”的數(shù)據(jù)改為”Tim”,那么可以添加一個(gè)字符串替換的 Transformer,針對(duì)”name”這個(gè)字段做替換。

又比如說(shuō),你的字段中有個(gè)”IP”,你希望將這個(gè) IP 解析成運(yùn)營(yíng)商、城市等信息,那么你就可以添加一個(gè) Transformer 做這個(gè) IP 信息的轉(zhuǎn)換。

當(dāng)然,Transformer 應(yīng)該可以多個(gè)連接到一起連動(dòng)合作。

設(shè)計(jì) Transformer 模塊是一件有趣而富有挑戰(zhàn)的事情,這涉及到 Tranformer 功能多樣性帶來(lái)的 3 個(gè)問(wèn)題:

多樣的功能必然涉及到多樣的配置,如何將不同的配置以優(yōu)雅而統(tǒng)一的方式傳達(dá)到插件中?多樣的功能也涉及到不同功能的描述,如何將功能描述以統(tǒng)一的形式表達(dá)給用戶,讓用戶選擇相應(yīng)的配置?如何將上述兩個(gè)問(wèn)題盡可能簡(jiǎn)單地解決,讓用戶編寫(xiě) Transformer 插件時(shí)關(guān)注盡可能少的問(wèn)題?

這里我們留個(gè)懸念,感興趣的朋友可以閱讀 logkit Transformer 相關(guān) (https://github.com/qiniu/logkit/tree/develop/transforms) 的源碼尋求答案,筆者后續(xù)也會(huì)在 logkit 的 wiki 頁(yè)面中描述。

Channel

經(jīng)過(guò)解析和變換后的數(shù)據(jù)可以認(rèn)為已經(jīng)處理好了,此時(shí)數(shù)據(jù)會(huì)進(jìn)入待發(fā)送隊(duì)列,即 Channel 部分。Channel 的好壞決定了一個(gè)數(shù)據(jù)收集發(fā)送工具的性能及可靠程度,是數(shù)據(jù)收集工具中最具技術(shù)含量的一環(huán)。

數(shù)據(jù)收集工具,顧名思義,就是將數(shù)據(jù)收集起來(lái),再發(fā)送到指定位置,而為了將性能最優(yōu)化,我們必須把收集和發(fā)送解耦,中間提供一個(gè)緩沖帶,而 Channel 就是負(fù)責(zé)數(shù)據(jù)暫存的地方。有了 Channel,讀取和發(fā)送就解耦了,可以利用多核優(yōu)勢(shì),多線程發(fā)送數(shù)據(jù),提高數(shù)據(jù)吞吐量。

大數(shù)據(jù)

圖 2 ft sender

一種設(shè)計(jì)思路是把整個(gè) Channel,包括多線程發(fā)送做成一個(gè)框架,封裝成一個(gè)特殊的 sender,我們稱這個(gè)特殊的 sender 為”ft sender”。其架構(gòu)如圖 2 所示,ft sender 與其他 sender 一樣也提供了 Send() 方法,解析完畢后的數(shù)據(jù)調(diào)用 Send 方法實(shí)際上就是將數(shù)據(jù)傳入到 Channel 中,然后再由 ft sender 處理多線程發(fā)送邏輯,將從隊(duì)列中取出的數(shù)據(jù)交由實(shí)際的 sender 多線程發(fā)送。

同時(shí)需要為用戶提供磁盤(pán)和內(nèi)存兩大隊(duì)列方式選擇。

如果追求最高的可靠性,就使用磁盤(pán)隊(duì)列,數(shù)據(jù)會(huì)暫存到本地磁盤(pán)中,發(fā)送后自動(dòng)刪除,即使突然宕機(jī)也不怕丟失數(shù)據(jù)。

如果追求更高的性能,可以使用內(nèi)存隊(duì)列,其實(shí)現(xiàn)方式就是 Go 語(yǔ)言的 Channel 機(jī)制,穩(wěn)定而簡(jiǎn)單,在關(guān)停過(guò)程中也需要將 Channel 中的數(shù)據(jù)落地到磁盤(pán),在隨后重新啟動(dòng)時(shí)載入,正常使用過(guò)程中也沒(méi)有數(shù)據(jù)丟失的風(fēng)險(xiǎn)。得益于 Go 語(yǔ)言的同步 Channel 機(jī)制,甚至可以把內(nèi)存隊(duì)列的大小設(shè)置為 0,以此實(shí)現(xiàn)多線程發(fā)送,這樣使用內(nèi)存隊(duì)列即使宕機(jī),也沒(méi)有了數(shù)據(jù)丟失的風(fēng)險(xiǎn)。

除了正常地作為待發(fā)送數(shù)據(jù)的等待隊(duì)列以外,Channel 還可以具有如下一些非常有趣而實(shí)用的功能:

錯(cuò)誤數(shù)據(jù)篩選

并不是所有解析完畢的數(shù)據(jù)發(fā)送到服務(wù)端就一定是正確的,有時(shí)服務(wù)端指定的數(shù)據(jù)格式和解析完畢的格式存在出入,或者數(shù)據(jù)中含有一些非法字符等情況,則數(shù)據(jù)不能發(fā)送成功。此時(shí),如果一批數(shù)據(jù)中只有一條這樣錯(cuò)誤的數(shù)據(jù),就很容易導(dǎo)致這一整批都失敗。

錯(cuò)誤數(shù)據(jù)篩選的作用就在于,把這一整批數(shù)據(jù)中對(duì)的數(shù)據(jù)篩選出來(lái),留下錯(cuò)誤的數(shù)據(jù),將正確的發(fā)送出去。

做法很簡(jiǎn)單,當(dāng)發(fā)送時(shí)遇到服務(wù)端返回存在格式錯(cuò)誤的數(shù)據(jù)時(shí),將這一批數(shù)據(jù)平均拆分為兩批(二分),再放入隊(duì)列,等待下次發(fā)送。再遇到錯(cuò)誤時(shí)則再拆分,這樣不斷二分,直到一個(gè)批次中只有一條數(shù)據(jù),且發(fā)送失敗,那我們就找到了這個(gè)錯(cuò)誤數(shù)據(jù),可以選擇丟棄或記錄。

借助隊(duì)列,我們很容易就能將錯(cuò)誤數(shù)據(jù)篩選出來(lái)。

包拆分(大包拆小包)

包拆分的由來(lái)是服務(wù)端不可能無(wú)限制開(kāi)放每個(gè)批次數(shù)據(jù)傳輸?shù)拇笮?,出于服?wù)器性能、傳輸性能等原因,總有會(huì)有一些限制。

當(dāng)一個(gè)批次的數(shù)據(jù)過(guò)大時(shí),就會(huì)導(dǎo)致傳輸失敗。此時(shí)的做法與錯(cuò)誤篩選的方法相似,只要將包二分即可,如果還是太大就再次二分,以此類推。

限速

限速的功能最容易理解,數(shù)據(jù)統(tǒng)統(tǒng)經(jīng)過(guò) Channel,那么只要限制這個(gè) Channel 傳輸介質(zhì)的速度即可。例如磁盤(pán)隊(duì)列,只需要限制磁盤(pán)的 IO 讀寫(xiě)速度;內(nèi)存隊(duì)列則限制隊(duì)列大小以此達(dá)到限速的目的。

常見(jiàn)的流量控制的算法有漏桶算法(Leaky bucket)(https://en.wikipedia.org/wiki/Leaky_bucket)和令牌桶算法(Token bucket)(https://en.wikipedia.org/wiki/Token_bucket) 兩種,比較推薦采用令牌桶算法實(shí)現(xiàn)該功能,感興趣的朋友可以閱讀一下 logkit 的 rateio 包 (https://github.com/qiniu/logkit/tree/develop/rateio)。

Sender

Sender 的主要作用是將隊(duì)列中的數(shù)據(jù)發(fā)送至 Sender 支持的各類服務(wù),一個(gè)最基本的實(shí)現(xiàn)同樣應(yīng)該設(shè)計(jì)得盡可能簡(jiǎn)單,理論上僅需實(shí)現(xiàn)一個(gè) Send 接口即可。

Send([]Data) error

那么實(shí)現(xiàn)一個(gè)發(fā)送端有哪些注意事項(xiàng)呢?

多線程發(fā)送:多線程發(fā)送可以充分利用 CPU 的多核能力,提升發(fā)送效率,這一點(diǎn)我們?cè)诩軜?gòu)設(shè)計(jì)中通過(guò)設(shè)計(jì) ft sender 作為框架解決了該問(wèn)題。錯(cuò)誤處理與等待:服務(wù)端偶爾出現(xiàn)一些異常是很正常的事情,此時(shí)就要做好不同錯(cuò)誤情況的處理,不會(huì)因?yàn)槟硞€(gè)錯(cuò)誤而導(dǎo)致程序出錯(cuò),另外一方面,一旦發(fā)現(xiàn)出錯(cuò)應(yīng)該讓 sender 等待一定時(shí)間再發(fā)送,設(shè)定一個(gè)對(duì)后端友好的變長(zhǎng)錯(cuò)誤等待機(jī)制也非常重要。一般情況下,可以采用隨著連續(xù)錯(cuò)誤出現(xiàn)遞增等待時(shí)間的方法,直到一個(gè)最頂峰(如10s),就不再增加,當(dāng)服務(wù)端恢復(fù)后再取消等待。數(shù)據(jù)壓縮發(fā)送:帶寬是非常珍貴的資源,通常服務(wù)端都會(huì)提供 gzip 壓縮的數(shù)據(jù)接收接口,而 sender 利用這些接口,將數(shù)據(jù)壓縮后發(fā)送,能節(jié)省大量帶寬成本。帶寬限流:通常情況下數(shù)據(jù)收集工具只是機(jī)器上的一個(gè)附屬程序,主要資源如帶寬還是要預(yù)留給主服務(wù),所以限制 sender 的帶寬用量也是非常重要的功能,限流的方法可以采用前面 Channel 一節(jié)提到的令牌桶算法。字段填充 (UUID/timestamp):通常情況下收集的數(shù)據(jù)信息可能不是完備的,需要填充一些信息進(jìn)去,如全局唯一的 UUID、代表收集時(shí)間的 timestamp 等字段,提供這些字段自動(dòng)填充的功能,有利于用戶對(duì)其數(shù)據(jù)做唯一性、時(shí)效性等方面的判斷。字段別名:解析后的字段名稱中經(jīng)常會(huì)出現(xiàn)一些特殊字符,如”$”、”@”等符號(hào),如果發(fā)送的服務(wù)端不支持這些特殊字符,就需要提供重命名功能,將這些字段映射到一個(gè)別的名稱。字段篩選:解析后的字段數(shù)據(jù)未必都需要發(fā)送,這時(shí)如果能提供一個(gè)字段篩選的功能,就可以方便用戶選擇去掉一些無(wú)用字段,并節(jié)省傳輸?shù)某杀尽R部梢栽?Transformer 中提供類似?discard transformer?的功能,將某個(gè)字段去掉。類型轉(zhuǎn)換:類型轉(zhuǎn)換是一個(gè)說(shuō)來(lái)簡(jiǎn)單但是做起來(lái)非常繁瑣的事情,不只是純粹的整型轉(zhuǎn)換成浮點(diǎn)型,或者字符串轉(zhuǎn)成整型這么簡(jiǎn)單,還涉及發(fā)送到的服務(wù)端支持的一些特殊類型,如date時(shí)間類型等,更多的類型轉(zhuǎn)換實(shí)際上相當(dāng)于最佳實(shí)踐,能夠做好這些類型轉(zhuǎn)換,就會(huì)讓用戶體驗(yàn)得到極大提升。簡(jiǎn)單、簡(jiǎn)單、簡(jiǎn)單:除了上述這些,剩下的就是盡可能的讓用戶使用簡(jiǎn)單。假設(shè)我們要寫(xiě)一個(gè) mysql sender,mysql 的數(shù)據(jù)庫(kù)和表如果不存在,可能數(shù)據(jù)會(huì)發(fā)送失敗,那就可以考慮提前創(chuàng)建;又比如數(shù)據(jù)如果有更新,那么就需要將針對(duì)這些更新的字段去更新服務(wù)的 Schema 等等。

Metrics

除了基本的自定義的數(shù)據(jù)收集,數(shù)據(jù)收集工具作為一個(gè)機(jī)器的 agent,還可以采集機(jī)器的基本數(shù)據(jù),例如 CPU、內(nèi)存、網(wǎng)絡(luò)等信息,通過(guò)這些信息,可以全面掌控機(jī)器的狀態(tài)。

具體的內(nèi)容可以參考 logkit 文檔:Runner 之系統(tǒng)信息采集配置。

至此,一個(gè)完整的數(shù)據(jù)收集工具的設(shè)計(jì)要點(diǎn)已經(jīng)介紹完畢。

我們已經(jīng)開(kāi)源的 logkit 正是按照這樣的設(shè)計(jì)實(shí)現(xiàn)的,logkit 集合了多種開(kāi)源數(shù)據(jù)收集工具的優(yōu)點(diǎn),聚焦易用性,致力于打造產(chǎn)品級(jí)別的開(kāi)源軟件。

數(shù)據(jù)收集工具 logkit

logkit(https://github.com/qiniu/logkit) 是七牛大數(shù)據(jù)團(tuán)隊(duì)開(kāi)源的一個(gè)通用的日志收集工具,可以從多種不同的數(shù)據(jù)源中采集數(shù)據(jù),并對(duì)數(shù)據(jù)進(jìn)行一系列的解析、變換、裁減,最終發(fā)送到多種不同的數(shù)據(jù)下游,其中就包括了 七牛的大數(shù)據(jù)平臺(tái) Pandora。除了基本的數(shù)據(jù)收集、解析以及發(fā)送功能之外,logkit 集合了多種同類開(kāi)源軟件的優(yōu)勢(shì),涵蓋了容錯(cuò)、并發(fā)、熱加載、斷點(diǎn)續(xù)傳等高級(jí)功能,更提供了頁(yè)面方便用戶配置、監(jiān)控以及管理自己的數(shù)據(jù)收集業(yè)務(wù),是一款產(chǎn)品級(jí)別的開(kāi)源軟件。

目前支持的數(shù)據(jù)源包括:

File Reader: 讀取文件中的日志數(shù)據(jù),如 nginx/apache 服務(wù)日志文件、業(yè)務(wù)日志等。Elasticsearch Reader: 全量導(dǎo)出 Elasticsearch 中的數(shù)據(jù)。MongoDB Reader: 同步 MongoDB 中的數(shù)據(jù)。MySQL Reader: 同步 MySQL 中的數(shù)據(jù)。MicroSoft SQL Server Reader: 同步 Microsoft SQL Server 中的數(shù)據(jù)。Kafka Reader: 導(dǎo)出 Kafka 中的數(shù)據(jù)。Redis Reader: 導(dǎo)出 Redis 中的數(shù)據(jù)。

目前支持發(fā)送到的服務(wù)包括 Pandora、ElasticSearch、InfluxDB、MongoDB 以及本地文件五種,近期還會(huì)支持發(fā)送到 Kafka 以及發(fā)送到某個(gè) HTTP 地址。

Pandora Sender: 發(fā)送到 Pandora(七牛大數(shù)據(jù)處理平臺(tái)) 服務(wù)端。Elasticsearch Sender: 發(fā)送到 Elasticsearch 服務(wù)端。File Sender: 發(fā)送到本地文件。InfluxDB Sender: 發(fā)送到 InfluxDB 服務(wù)端。MongoDB Sender: 后發(fā)送到 MongoDB 服務(wù)端。

而在這已經(jīng)實(shí)現(xiàn)的有限的幾個(gè)發(fā)送端中,我們是這么設(shè)計(jì)的使用場(chǎng)景:

如果收集數(shù)據(jù)是為了監(jiān)控,那么可以使用 InfluxDB Sender,發(fā)送到開(kāi)源的 InfluxDB 服務(wù)端,實(shí)現(xiàn)實(shí)時(shí)數(shù)據(jù)監(jiān)控。如果收集數(shù)據(jù)是為了搜索查看,那么可以使用 Elasticsearch Sender,發(fā)送到開(kāi)源的 Elasticsearch 服務(wù)端,進(jìn)行日志查詢。如果收集數(shù)據(jù)是為了計(jì)量統(tǒng)計(jì)或者其他一些涵蓋復(fù)雜的增刪改查需求的場(chǎng)景,那么就可以使用 MongoDB Sender,在本地對(duì)數(shù)據(jù)進(jìn)行聚合,再發(fā)送到開(kāi)源的 MongoDB 服務(wù)中。

而發(fā)送到 七牛的 Pandora 服務(wù) 中,不僅能涵蓋上述全部場(chǎng)景,還提供了大量可以快速發(fā)掘數(shù)據(jù)價(jià)值的實(shí)際應(yīng)用場(chǎng)景的使用模板,同時(shí)還可以利用七牛成本較低的云存儲(chǔ)服務(wù)對(duì)數(shù)據(jù)進(jìn)行持久備份。

目前 logkit 支持的收集端和發(fā)送端并不多,非常歡迎大家來(lái)貢獻(xiàn)更多的收集 / 發(fā)送端。

量身定制

再回過(guò)頭來(lái)聊聊量身定制的話題,本文描述了一個(gè)數(shù)據(jù)收集工具打造的完整過(guò)程,我們深知量身定制一個(gè)數(shù)據(jù)收集工具有多么重要,而量身定制也是 logkit 的一大特點(diǎn)。logkit 架構(gòu)中的每個(gè)組成部分(Reader、Parser、Sender、Transformer、Channel 等)都是一個(gè) GO 語(yǔ)言的 package,你完全可以用 logkit 中的包,自己寫(xiě)主函數(shù),從而定制一個(gè)專屬的收集工具。我們提供了代碼案例 (https://github.com/qiniu/logkit/tree/develop/samples) ,方便你親自實(shí)踐。

優(yōu)勢(shì)

總體而言,logkit 有如下優(yōu)勢(shì):

GO 語(yǔ)言編寫(xiě),性能優(yōu)良,資源消耗低,跨平臺(tái)支持。Web 支持,提供?頁(yè)面?對(duì)數(shù)據(jù)收集、解析、發(fā)送過(guò)程可視化插件式架構(gòu),擴(kuò)展性強(qiáng),使用靈活,易于復(fù)用。定制化能力強(qiáng),可以僅使用部分 logkit 包,以此定制專屬收集工具。配置簡(jiǎn)單,易于上手,可通過(guò)?頁(yè)面?進(jìn)行操作管理原生中文支持,沒(méi)有漢化煩惱功能全面,涵蓋了包括 grok 解析、metric 收集、字段變化 (transform) 在內(nèi)的多種開(kāi)源軟件特點(diǎn)生態(tài)全面,數(shù)據(jù)發(fā)送到七牛的 Pandora 大數(shù)據(jù)平臺(tái)支持包括時(shí)序數(shù)據(jù)庫(kù)、日志檢索以及壓縮永久存儲(chǔ)等多種數(shù)據(jù)落地方案。

下面讓我們來(lái)實(shí)踐一下,看看 logkit 在實(shí)戰(zhàn)中是什么樣子。

logkit 實(shí)戰(zhàn)

下載

編譯完后的 logkit 是一個(gè) Go 的二進(jìn)制包,你可以在 logkit 的 Download 頁(yè)面 (https://github.com/qiniu/logkit/wiki/Download) 找到對(duì)應(yīng)操作系統(tǒng)的 Release 版本。

也可以參照 logkit 源碼編譯指南,從代碼層面定制自己的專屬 logkit。

啟動(dòng)

logkit 部署非常簡(jiǎn)單,將這個(gè) binary 放在系統(tǒng) PATH 路徑中就算部署完成了,推薦使用諸如 supervisor 等進(jìn)程管理工具進(jìn)行管理。

啟動(dòng) logkit 工具,可以使用默認(rèn)的配置文件,執(zhí)行如下命令即可。

logkit -f logkit.conf

配置文件中默認(rèn)開(kāi)啟了 3000 端口,初次使用可以通過(guò)瀏覽器打開(kāi) logkit 配置頁(yè)面,配置 runner 并調(diào)試讀取、解析和發(fā)送方式,瀏覽器訪問(wèn)的地址是 http://127.0.0.1:3000 。

配置

大數(shù)據(jù)

圖 3 logkit 首頁(yè)

打開(kāi)網(wǎng)址后看到如圖 3 所示的 logkit 配置助手首頁(yè),這個(gè)頁(yè)面會(huì)清晰地展示目前所有的 logkit Runner 運(yùn)行狀態(tài),包括讀取速率、發(fā)送速率、成功 / 失敗數(shù)據(jù)條數(shù),以及一些錯(cuò)誤日志。還可以在這里修改和刪除 Runner。

點(diǎn)擊左上角【增加 Runner】按鈕,可以添加新的 logkit Runner。

大數(shù)據(jù)

圖 4 數(shù)據(jù)源 Reader 配置

如圖 4 所示,新增 Runner 的第一步就是配置數(shù)據(jù)源,為了盡可能方便用戶,logkit 將絕大多數(shù)選項(xiàng)都預(yù)設(shè)了默認(rèn)值,用戶只需要根據(jù)頁(yè)面提示填寫(xiě)黃色的必填項(xiàng)即可。

按頁(yè)面步驟依次配置數(shù)據(jù)源、解析方式、以及發(fā)送方式。

大數(shù)據(jù)

圖 5 解析數(shù)據(jù)

如圖 5 所示,在配置解析方式的頁(yè)面還可以根據(jù)配置嘗試解析樣例數(shù)據(jù),這個(gè)頁(yè)面可以根據(jù)你的實(shí)際數(shù)據(jù)非常方便地調(diào)試解析方式。

大數(shù)據(jù)

圖 6 字段變化 Transformer

如圖 6 所示,除了解析以外,還可以針對(duì)解析出來(lái)的某個(gè)字段內(nèi)容做數(shù)據(jù)變換(Transform),即上一章中描述的 Transformer??梢韵窆艿酪粯悠唇佣鄠€(gè) Transformer,做多重字段變化。

最后配置完發(fā)送方式,可以在如圖 7 所示的頁(yè)面做二次確認(rèn)。

大數(shù)據(jù)

圖 7 確認(rèn)并添加頁(yè)

在二次確認(rèn)的頁(yè)面中,可以直接修改表達(dá)內(nèi)容也可以返回上一步修改,最終點(diǎn)擊添加 Runner 即可生效。

到這里,一個(gè)復(fù)雜的數(shù)據(jù)收集工作就完成了,怎么樣,就是這么簡(jiǎn)單,快來(lái)實(shí)際體驗(yàn)一下吧!

極客網(wǎng)企業(yè)會(huì)員

免責(zé)聲明:本網(wǎng)站內(nèi)容主要來(lái)自原創(chuàng)、合作伙伴供稿和第三方自媒體作者投稿,凡在本網(wǎng)站出現(xiàn)的信息,均僅供參考。本網(wǎng)站將盡力確保所提供信息的準(zhǔn)確性及可靠性,但不保證有關(guān)資料的準(zhǔn)確性及可靠性,讀者在使用前請(qǐng)進(jìn)一步核實(shí),并對(duì)任何自主決定的行為負(fù)責(zé)。本網(wǎng)站對(duì)有關(guān)資料所引致的錯(cuò)誤、不確或遺漏,概不負(fù)任何法律責(zé)任。任何單位或個(gè)人認(rèn)為本網(wǎng)站中的網(wǎng)頁(yè)或鏈接內(nèi)容可能涉嫌侵犯其知識(shí)產(chǎn)權(quán)或存在不實(shí)內(nèi)容時(shí),應(yīng)及時(shí)向本網(wǎng)站提出書(shū)面權(quán)利通知或不實(shí)情況說(shuō)明,并提供身份證明、權(quán)屬證明及詳細(xì)侵權(quán)或不實(shí)情況證明。本網(wǎng)站在收到上述法律文件后,將會(huì)依法盡快聯(lián)系相關(guān)文章源頭核實(shí),溝通刪除相關(guān)內(nèi)容或斷開(kāi)相關(guān)鏈接。

2017-10-18
數(shù)據(jù)收集工具的設(shè)計(jì)與最佳實(shí)踐
作者:孫健波 數(shù)據(jù)收集工具對(duì)比 目前社區(qū)已經(jīng)不乏大量?jī)?yōu)秀的數(shù)據(jù)收集工具,如有名的 Elastic Stack(Elasticsearch、Logstash、Ki

長(zhǎng)按掃碼 閱讀全文