日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

大規(guī)模日志收集處理項目的技術(shù)總結(jié)

 WindySky 2016-06-24

 以下是2012年一個公司內(nèi)部項目的技術(shù)總結(jié),涉及到的方面比較多比較雜,拿出來和大家分享下。如果有更好的方案或者想法請聯(lián)系我,謝謝~!
注:文章中提到的其他系統(tǒng)(如哈勃Agent、EagleEye)是公司內(nèi)部的其他系統(tǒng),這里就不詳細介紹了。

簡介

TLog是一個分布式的,可靠的,對大量數(shù)據(jù)進行收集、分析、展現(xiàn)的的系統(tǒng)。主要應用場景是收集大量的運行時日志,分析并結(jié)構(gòu)化存儲,提供數(shù)據(jù)查詢和展現(xiàn)。

服務能力

  • 收集淘寶線上8000+臺機器的日志,每天日志量5T+。
  • 一般情況下,數(shù)據(jù)從產(chǎn)生到TLog最終入庫有10秒以下的延遲。
  • 整個TLog集群有12臺機器(虛擬機,5核,8G內(nèi)存),10臺負責日志的收集和解析,2臺提供數(shù)據(jù)的查詢和展現(xiàn)。

技術(shù)選型

一個海量數(shù)據(jù)收集的系統(tǒng),首先需要考慮的就是收集模型:推送(push),還是拉取(pull)。兩種模式都有各自的優(yōu)缺點。業(yè)界的很多系統(tǒng)都是push模型,比如facebook的scribe,而我們主要選擇的是pull模型(push模型后續(xù)支持),這個決策和我們所處的環(huán)境有關(guān):

TLog集群可用資源非常有限

選用push模型,就需要要求日志收集器的容量需要大于高峰期數(shù)據(jù)的生成量,否則主動推送過來的數(shù)據(jù)不能及時處理會帶來更多更復雜的問題:比如信息在收集器端如何先暫存慢慢處理,這又牽扯到收集器端是否有這么多的緩存空間(比如硬盤是否夠大來臨時保存洶涌而至的數(shù)據(jù),或者轉(zhuǎn)移到其他地方的網(wǎng)絡開銷等);如果在日志生成端臨時保存,則需要有一系列狀態(tài)的變化,比如收集器正常則直接發(fā)數(shù)據(jù),否則則保存本地硬盤,等到收集器恢復了再把硬盤數(shù)據(jù)發(fā)送,然后在恢復到直接發(fā)送模式等。

最初TLog集群只有6臺虛擬機,后期擴展到12臺。硬件處理能力的限制,決定了我們處理海量數(shù)據(jù)時壓力非常大,如果還選用push模型,在數(shù)據(jù)生成的高峰期,必然無法處理瞬間大量的日志。而選擇pull模型,控制權(quán)掌握在自己手里,收集器可以根據(jù)自己的節(jié)奏游刃有余的拉取日志,高峰期產(chǎn)生的日志會在接下來的時間慢慢的被消化(當然收集器的能力需要高于日志產(chǎn)生的平均值)。當然,這樣的缺陷是處理延遲增加了。

信息的時效性

push模型能帶來很高的信息時效性,可以最快的收集、整理,并查詢出來。而我們的先期定位并不是特別在意這樣的實時性,因為接入的應用主要是使用這些數(shù)據(jù)做日報、周報等,能夠接受5~10分鐘甚至更張的數(shù)據(jù)延遲。而且有些環(huán)境的約束導致做到秒級別的準實時也沒有意義,比如HSF的哈勃日志,一個數(shù)據(jù)單元每2分鐘才輸出一次,從日志的輸出端就已經(jīng)造成了2分鐘的延遲了,后面在快也意義不大。所以選用pull模型,在數(shù)據(jù)高峰期,大量數(shù)據(jù)臨時擠壓,后期慢慢處理對我們來說是可以接受的。

可靠性

可靠是必須的。眾多push模型的產(chǎn)品在保證可靠性做了很多事情,使得事情變得非常的復雜,比如:

  • 收集器出現(xiàn)異常:正常情況下直接推送消息,如果收集器異常則本地先緩存,待收集器恢復后再把緩存的信息發(fā)送,然后再恢復為正常模式
  • 收集器的選擇:當有多個收集器時,消息推送給誰?是否要負載均衡,是否要對收集器上下線很快的感知,勢必需要引入ConfigServer或者ZK這樣的產(chǎn)品
  • 需要嵌入應用:如果要做到運行時信息不落盤直接發(fā)送,需要發(fā)送的邏輯嵌入應用,涉及到應用的大面積升級,而且上面提到了發(fā)送的邏輯在收集器的問題上變得不是那么簡單,所以這對應用是很重的負擔。

而選擇pull模型,再借助哈勃Agent這個基礎(chǔ)設施,事情會變得非常簡單!這里不得不提一下:哈勃Agent是個很不錯的產(chǎn)品,簡單而有效!而且它的存在使得TLog設計和部署變得簡單很多:

  • 收集器無狀態(tài):這一點很重要,保證了TLog的可靠性和簡單的設計。試想如果收集器需要記錄每一個日志收集的狀態(tài)(目標機器地址、日志文件、日志抓取偏移量),則收集器在重啟或者掛掉時需要做很多狀態(tài)持久化的工作,有時甚至沒有時間來做而直接掛掉,所以又需要又更復雜的方式來近乎實時的記錄狀態(tài);如果任務分配不均,或者其他原因向調(diào)動一些任務到其他的機器,又涉及到任務狀態(tài)的遷移等等。而狀態(tài)記錄在哈勃Agent,收集器只需要通過相關(guān)標識請求哈勃Agent,即可獲取增量日志,如果讓任務調(diào)動或者某個收集器掛掉,別的收集器接替其工作,只需要使用同樣的標識即可獲取后續(xù)的增量日志,這樣的結(jié)構(gòu)使得對單個收集器的穩(wěn)定性要求大大降低,只要整個集群持續(xù)有足夠的資源,即可保證系統(tǒng)的可靠性。而且哈勃Agent足夠的簡單,使其很容易做到非常穩(wěn)定。所以,不存在push模型的的問題一和問題二。
  • 天然的分布式存儲:開玩笑的說,TLog有個強大的分布式存儲,即目標服務器本身的硬盤空間,每個服務器生成的日志直接落盤,而且硬盤空間又足夠保持一定時間內(nèi)的日志,收集器在之后的某個時刻讀取這些信息,如果處理失敗還可以根據(jù)上次日志抓取的偏移量再抓取一次或者保存再某處做特殊處理。這比所有日志都堆積到十幾臺收集器的硬盤上要可靠的多,也簡單的多。
  • 部署和依賴簡單:幾乎淘寶所有服務器都有部署哈勃Agent,即使沒有也很方便的能安裝。應用不需要嵌入發(fā)送日志信息的邏輯,只需要簡單的記錄日志即可,對應用幾乎零侵入。所以,對push模型的問題三解決了。

當然,選擇pull模型也是有自己的問題:

  • 日志收集任務的管理:因為信息不會主動推送過來,所以需要自己記得去哪里取。收集任務的管理是個不小的問題:比如有些任務鏈接會失?。ū热绻狝gent沒有部署,需要找PE解決);有些任務會忙不過來,需要增加處理器節(jié)點(如某個任務的收集器負荷重導致收集頻率降低,長時間沒有抓取動作);新的應用接入需要配置相關(guān)的抓取任務,應用的服務器變更后相關(guān)的任務也需要變更等,雖然很多都做了自動化處理(比如定時同步Armory來獲取應用和ip的映射關(guān)系等),但不得不承認任務的管理是個不小的負擔。

技術(shù)挑戰(zhàn)

TLog做的事情非常簡單,但是再海量數(shù)據(jù)的沖擊下,系統(tǒng)很容易變得千瘡百孔。

JVM內(nèi)存溢出

TLog首先遇到的問題就是OOM。收集器所在的虛擬機,15MB/秒的數(shù)據(jù)流入10MB/秒的數(shù)據(jù)流出(這還是平常業(yè)務壓力不大的時候)。很容易想象,10+MB的數(shù)據(jù)解析成大量的對象,稍微處理不好就會導致大量的JVM堆內(nèi)存被占用,很容易OOM。結(jié)合應用自身的狀況,經(jīng)過很多嘗試,最終找到了解決辦法,這也讓我對很多東西有了新的認識:

線程池的大小

線程池的大小對于TLog來說不是性能的問題,而是會不會死人的問題。線程池在TLog內(nèi)部主要是任務調(diào)度使用(Quarz),每一個日志收集任務啟動會占用一個線程,后續(xù)的所有動作都在這個線程完成:收集一批增量日志;使用不同的解析器把日志解析成結(jié)構(gòu)化對象;持久化(入HBase或者云梯或者消息中間件)。這樣的劃分方式使得線程之間沒有任何通信(也就沒有鎖的競爭),有因為整個處理任務的兩頭有大量的IO動作(拉取日志和持久化),中間過程是純CPU運算(解析),所以多個線程大家互補忙閑能做到很高的效率(CPU和IO雙忙……)。

但是線程池開多少?當初拍腦袋定了200,結(jié)果只要日志有積壓(業(yè)務高峰,或者TLog下線一段時間)TLog直接OOM。中間甚至使用過“延遲啟動任務”的方式,即收集器把任務以一定間隔(比如2秒)一個一個啟動,有一定效果,但還是很容易掛,而且一個收集器一般會有5k+個任務,兩秒啟動一個的話……這很顯然不靠譜。分析了狀況后,發(fā)現(xiàn)事情是這樣的:

  1. 收集器開啟一個任務抓取日志,返回的量很大(比如10MB),拿到內(nèi)存里開始解析,解析完開始保存。
  2. 于此同時,其他的任務也啟動起來,做同樣的動作,拉日志,解析,保存。
  3. 因為線程池有200個線程,意味著同時允許200個任務在運行,而我后續(xù)dump內(nèi)存發(fā)現(xiàn),一個線程運行的時候,會占用20~40MB不等的JVM內(nèi)存。而總共JVM堆有5G,還沒到200個線程運行內(nèi)存就不夠了,然后開始GC,但是GC掉的內(nèi)存不多,因為很多線程剛剛處于數(shù)據(jù)保存階段,數(shù)據(jù)在最終入庫前是不可能GC的,所以港GC完內(nèi)存又瞬間用光然后再次GC,或者就干脆OOM了。

原本很簡單的事情(拉日志,解析,入庫)變得無法穩(wěn)定運行,經(jīng)過一步步測試,最終把線程池大小控制在30(后續(xù)因為邏輯更加復雜,但任務占用內(nèi)存量又增加,而調(diào)整到25),之所以調(diào)整到這么小是因為如果再大,比如35個任務同時處理,就會導致內(nèi)存占用非常緊張(雖說有5G的堆內(nèi)存,old、eden、s1和s0分分就沒多少了),導致Full GC,但又沒有成果,GC完內(nèi)存一樣不夠用,就再Full GC,結(jié)果導致90%以上的時間都在做無用的GC。那還不如把內(nèi)存控制的留點余量,不至于頻繁觸發(fā)FGC,而留下大量的時間專心干活呢。當然除此之外還有很多其他的優(yōu)化,比如把先批量解析再批量保存改為邊解析邊保存,保存過后的對象就可以被GC了,降低對象的存活時間。另外一個很重要的點:通過哈勃Agent拉取的一批增量日志一下都被加載到內(nèi)存中,隨后慢慢的解析處理。在極端情況下只要這批日志沒有處理完,就會有10MB(哈勃Agent單次拉取日志的上限)的字節(jié)無法釋放。應該改為流式的處理,讀一部分處理一部分,然后再讀取下一部分。但因為這個改動對整個解析結(jié)構(gòu)會有很大的調(diào)整,所以就放到了后面遷移Storm時統(tǒng)一做了修改,整個jvm內(nèi)存占用量減少一半左右,不再成為系統(tǒng)的瓶頸。

經(jīng)過了一番改動后,TLog變得“壓不死”了,即使積壓了大量的數(shù)據(jù),啟動后網(wǎng)絡流量涌入30MB/每秒,cpu會穩(wěn)定再85%,系統(tǒng)load 40(夸張的時候有80),但是很穩(wěn)定,不到2秒一次YGC,10分鐘一次FGC,系統(tǒng)可以保持這樣的壓力運行6個小時,當積壓的所有數(shù)據(jù)都處理完后,機器的負載,cpu及內(nèi)存的占用自動恢復到正常水平。

JVM GC參數(shù)

最初TLog使用的GC方式是CMS GC,花了不少經(jīng)歷調(diào)整eden和old的比例,以及觸發(fā)CMS GC的比率。但后來覺得這樣做沒有必要。因為CMS GC是為高相應系統(tǒng)設計的,使Stop-the-world時間盡量短,使得系統(tǒng)持續(xù)保持較高的相應速度,但付出的代價就是GC效率低。而TLog選用的是pull模型,不會有系統(tǒng)主動請求,所以不需要保證高相應,應該更加看中GC效率,所以后續(xù)改成了并行GC,提高GC效率,從而獲得更多的“工作時間”。

另外eden和old的比例對收集器也非常重要,從工作方式可以看到,收集器必定會大量的產(chǎn)生對象,和大量的銷毀對象,而且這些對象還是會在內(nèi)存中保留一定的時間,所以要求eden區(qū)稍微大些,以保證這些臨時對象在晉升到old之前就被回收掉,而相對穩(wěn)定的數(shù)據(jù)在收集器中比較少。所以eden空間設置的比old要大。

HBase寫效率

隨著業(yè)務量的增長,馬上遇到了一個之前從沒有想象過的問題:HBase寫速度不夠。當初之所以選擇HBase為后端存儲,就是因為其寫入速度很高,能保證大量的數(shù)據(jù)快速的入庫。先前的測試也驗證了這一點:HBase單機扛住了我們每秒5萬條記錄的沖擊。所以我們樂觀的估計,有著30臺機器的集群抗100萬的量應該小case,但是隨著越來越多的應用使用HBase集群,以及整個集群數(shù)據(jù)量的增加及region數(shù)量的增多,HBase寫效率不斷下降,同樣保存1k條記錄的耗時從原來的不到100毫秒變成了將近1秒,有時甚至超過2秒。直到一個周六的晚上,整個集群寫入耗時忽然急劇上升,導致整個集群所有應用的寫入量被迫下降到10萬/秒左右,最后無奈關(guān)閉了Eagleeye的數(shù)據(jù)表,整個集群才恢復,原因很簡單:Eagleeye數(shù)據(jù)表的region數(shù)量將近1萬個,占整個集群region數(shù)量的80%,region server壓力過大。至此Eagleeye實時數(shù)據(jù)就暫停下來,全部轉(zhuǎn)為離線處理。

Eagleeye是TLog最大的一個接入方,其數(shù)據(jù)量占TLog所有業(yè)務的80%,每天日志量5T左右。HBase上的數(shù)據(jù)表被關(guān)閉,一部分原因是數(shù)據(jù)量的確太大,另外我覺得應該是我們使用HBase的方式不夠得當,還有優(yōu)化的空間。所以我開始尋找業(yè)界的解決方案,發(fā)現(xiàn)了OpenTSDB。

OpenTSDB

"OpenTSDB is a distributed, scalable Time Series Database (TSDB) written on top of HBase."(官方說明)。學習了OpenTSDB的Schema設計,發(fā)現(xiàn)很多東西都值得學習和借鑒,根據(jù)多面對的場景,OpenTSDB對Schema的精巧設計,使得其記錄體積非常小,而且row的數(shù)量很少,這都能降低HBase和region server的壓力,從而提高數(shù)據(jù)庫的寫和讀的效率。將HSF的數(shù)據(jù)改為OpenTSDB的方式后,同樣的信息量,數(shù)據(jù)體積減少了80%以上(rowkey體積減少50%,value體積減少80%,數(shù)據(jù)條數(shù)減少66%),rowkey數(shù)量減少97%。直接效果就是寫入速度更快,吞吐量更高,而且HBase服務器的壓力更??!但這只適用于Time Series類型的數(shù)據(jù),比如HSF、精衛(wèi)等數(shù)值統(tǒng)計型的場景。對于Eagleeye和TAE這種日志記錄類型的不適用,但仍然又很多可以借鑒和改進之處。

流式處理的代價

下半年,TLog的收集器遷移到Storm流式處理平臺。日志收集器兼顧了收集、解析、入庫的職責,而且解析期間經(jīng)常需要對信息進行分類,過濾,匯總等,非常適合使用流式處理框架完成這些工作。但遷移到Storm后一樣遇到了各式各樣的挑戰(zhàn):

額外的消耗

在Storm中,每個處理節(jié)點可以認為是一個運算單元,數(shù)據(jù)在這些單元中流轉(zhuǎn),一級的輸出作為另一級的輸入。對于TLog的解析器來說,感覺理想的方式應該是這樣的:

  1. Spout節(jié)點(Storm中的數(shù)據(jù)源節(jié)點)拉取日志內(nèi)容,然后發(fā)射出去
  2. 下游節(jié)點接收日志內(nèi)容,進行解紛并結(jié)構(gòu)化成對象,然后發(fā)射出去
    1. 下游節(jié)點接收結(jié)構(gòu)化對象,進行相關(guān)存儲(HBase或者云梯)
    2. 另一類下游節(jié)點接收結(jié)構(gòu)化對象進行相關(guān)的聚合,比如根據(jù)某種類型進行累加

上面的處理方式感覺非常清晰明了,但是卻產(chǎn)生了大量的“額外消耗------對象的序列化和網(wǎng)絡傳輸。數(shù)據(jù)在每個節(jié)點流轉(zhuǎn)都需要經(jīng)過序列化和反序列化操作(消耗CPU),還有網(wǎng)絡傳輸(消耗IO),而且根據(jù)上面的設計,幾乎從spout流出的數(shù)據(jù)會100%的跳轉(zhuǎn)多個節(jié)點,也就使得一份數(shù)據(jù)造成N倍的網(wǎng)絡傳輸,網(wǎng)絡消耗非常嚴重。所以我們制定了一個簡單的原則:只要沒有聚合需求,就在一個節(jié)點完成。因為集群數(shù)據(jù)的聚合使用普通方式比較難解決,而使用storm非常天然的處理掉。

對避免不了的數(shù)據(jù)流轉(zhuǎn),storm還是有辦法降低額外的消耗,比如:

  • 優(yōu)化序列化方式:storm可以使用kryo的序列化方式,cpu消耗和序列化后的體積會比java自身的序列化好很多,可以參考這里的比較。
  • 進程內(nèi)流轉(zhuǎn)不做序列化和網(wǎng)絡傳輸處理:storm 0.7.2版本做了優(yōu)化,如果數(shù)據(jù)是在一個進程內(nèi)流轉(zhuǎn),則跳過序列化和網(wǎng)絡傳輸步驟,這樣能極大的減輕額外的消耗。但是這需要使得多個節(jié)點在一個進程,會使得進程的龐大,導致機器storm worker進程數(shù)減少,可能造成負載不均衡的情況,所以一臺機器開多少個worker需要根據(jù)機器的配置,以及任務的復雜度,以及任務數(shù)量來權(quán)衡。

可靠消息和非可靠消息的選擇

Storm為了保證流轉(zhuǎn)消息的可靠性,引入第三視角的節(jié)點Acker,來跟蹤每一條消息,當下游處理失敗后能通知上游,上游可以有自己的策略進行處理(例如重發(fā)消息)。但是Acker的引入也必然有開銷(大量的Ack消息),導致業(yè)務可用的資源減少,而且會降低消息處理的性能。TLog處理器未啟用可靠消息時,每個節(jié)點處理消息的速度是11k/s,打開可靠消息后只能有3~4k/s,下降非常明顯。因為TLog處理的是大量的日志信息,處于從數(shù)據(jù)可靠的敏感程度,和資源限制的情況下,我們選擇了非可靠消息。

但事情并沒有這樣簡單的結(jié)束,我們的集群經(jīng)常出現(xiàn)個別進程內(nèi)存狂漲,消耗掉所有的內(nèi)存甚至swap分區(qū),然后操作系統(tǒng)啟動自我保護性的隨機kill進程,導致這個“異?!边M程被殺死;或者整個虛擬機掛掉。出現(xiàn)這個問題的原因是我們生產(chǎn)消息(Strom的spout端)的速度大于消費消息(Strom的bolt端)的速度,導致消息積壓在spout端的出口處,使得spout所在的進程內(nèi)存占用上升(順便提一下,Storm使用的消息組件是?MQ,非Java組件,所以消息的堆積無法從jvm堆體積中體現(xiàn)出來)。而Storm可以通過設置“topology.max.spout.pending”來設置積壓消息的最大值,但是這個特性只有在“可靠消息”時才有意義。所以對于非可靠消息,只能提高后續(xù)節(jié)點的處理能力(比如增加節(jié)點數(shù)量)來解決。

實時和離線相結(jié)合

對于運行時數(shù)據(jù),一般情況下我們的場景如下:

  • 近期的實時數(shù)據(jù):對于這部分數(shù)據(jù),我們的需求是查詢時間跨度?。ń?小時或近10分鐘),時間粒度細(每分鐘甚至幾十秒一個數(shù)據(jù)單元),能夠準實時的展現(xiàn)(數(shù)據(jù)從產(chǎn)生到最終展現(xiàn)的延遲可能只有幾秒或十幾秒)。
  • 過往的歷史數(shù)據(jù):對于歷史數(shù)據(jù),我們的查詢的時間跨度一般比較大(一周、一個月等),但時間粒度較粗(一小時甚至一天一個數(shù)據(jù)單元),不在乎實時性。

所以對數(shù)據(jù)粒度的需求會隨著時間的流式而變粗(ps:你應該不會需要查看上個月3號上午10點~10點半,以分鐘為粒度展現(xiàn)一個服務的調(diào)用量。如果真的需要,這應該是一個特殊情況,相關(guān)的報警系統(tǒng)應該會沉淀該信息)。所以從“如何“打敗”CAP定理”一文得到的思路,我們使用實時和離線相結(jié)合的方法來解決一下需求:

實時部分

準實時的處理最新的數(shù)據(jù),以小粒度保存(甚至可以直接緩存起來),方便查詢和檢索。但實時處理數(shù)據(jù)有一些問題:

  • 易錯:實時處理一般使用流式處理,大量數(shù)據(jù)批量涌入又快速的處理輸出,很容易出現(xiàn)不確定性或錯誤。如數(shù)據(jù)因為收集的不同步,導致加和時上一分鐘的日志被加和到下一分鐘;或者因為短暫的暫停服務導致數(shù)據(jù)出現(xiàn)缺口;或者一個新上的算法有缺陷導致計算錯誤等。
  • 無法重復計算:因為數(shù)據(jù)快速的流動,如果有消息重發(fā)機制就意味著一定有個池子來緩存,以保證下游處理失敗而重發(fā)。緩存池的存在又增加了資源、性能、復雜度等的極大提高。
  • 數(shù)據(jù)量太大:因為數(shù)據(jù)的時間粒度太細,使得數(shù)據(jù)量非常大,存儲和查詢代價很高。

所以我們的做法是在實時部分允許有這樣細小的問題,問題的修復由離線批量計算解決。

離線批量處理部分

使用MapReduce來計算一段時間(前一小時或一天)匯總的數(shù)據(jù),很容易解決實時計算是出現(xiàn)的問題:

  • 大時間跨度的合并:單條數(shù)據(jù)匯總時間跨度較大,極大減小了數(shù)據(jù)的體積,對存儲和大時間跨度查詢友好。
  • 替代“過時”的實時數(shù)據(jù):實時計算的結(jié)果會被批量計算覆蓋或替代,當時產(chǎn)生的細小錯誤也自然消失。
  • 容錯性高:因為原始數(shù)據(jù)已經(jīng)保存,使用MR可以重復計算,而且計算結(jié)果穩(wěn)定。即使出現(xiàn)算法錯誤,修復后仍然可以重新計算。

而離線批量處理的唯一問題-----實時性-----也被實時計算彌補。

數(shù)據(jù)說話

前面提到了很多系統(tǒng)優(yōu)化和調(diào)整的方式,但一定要記得“要進行優(yōu)化,先得找到性能瓶頸!”,根據(jù)Profiler的結(jié)果來確定優(yōu)化的方向。對于TLog收集器,使用了Java自帶的VisualVM,很快定位到幾個最大的cpu消耗點:

  • 反射構(gòu)造對象:為了方便構(gòu)造存儲HBase的結(jié)構(gòu)化對象,我們開發(fā)了一套注解,通過在Model對象屬性上標記注解,可以自動轉(zhuǎn)換成需要的HBase對象,使用起來非常方便,但是轉(zhuǎn)換過程沒有緩存Model的類結(jié)構(gòu),導致大量的使用反射。這樣生成對象的速度比直接代碼構(gòu)造要慢了一個數(shù)量級。
  • 正則表達式匹配:收集器中有大量的日志匹配和解析,所以當時用了很多正則表達式,雖然緩存了pattern,但是還是非常的消耗cpu,最后把一些非常規(guī)范的日志都使用StringUtils.split()方法進行分割然后處理,也能提大幅度提高解析速度。
  • 切分字符串:Java String的split方法內(nèi)部使用了曾則表達式,如果切分字符不需要正則匹配,建議使用Apache commons lang的StringUtils。當然,這個的調(diào)整帶來的提高遠不如前兩個大。

經(jīng)過一次次Profile和調(diào)整,最終基本只剩下無法避開的消耗,處理器容量提高4倍以上!遺憾的是當時前后的詳細對比數(shù)據(jù)沒有保留,無法列在這里提供參考。

其他

下面是一些零碎的小心得。

HBase rowkey的唯一

TLog收集到的一些信息不是Time Series類型的,不能做加和等處理,而是要根據(jù)日志內(nèi)容生成唯一的個體,比如操作日志,需要能根據(jù)時間和操作類型查詢操作的具體情況。對于這類需求有個細節(jié):HBase rowkey的生成該如何保證唯一。因為rowkey會由索引條件構(gòu)成,如日志類型、時間,但僅僅這樣的rowkey很容易重復,導致之前的記錄被覆蓋。當然可以在rowkey后面增加一個唯一后綴進行區(qū)分,比如下面幾種方式:

  • 增加相關(guān)區(qū)別標識:比如增加日志生成機器ip,或者其他什么比較容易區(qū)別的業(yè)務字段信息來進行去重,但是會發(fā)現(xiàn)后綴元素加的少很難達到效果,加的多又使得rowkey變得很龐大,甚至只有把所有日志內(nèi)容都放在rowkey里才能達到去重目的。
  • 增加遞增量:增加一個自增的變量,但是這樣的缺陷是數(shù)據(jù)無法補救,即如果因為某種原因,昨天一天的數(shù)據(jù)想重新導入一邊,昨天已有的覆蓋掉,沒有的補上,你會發(fā)現(xiàn)自增量的存在導致你沒辦法做這個事情。

我們的處理方式:將日志原文進行CRC-32編碼,生成8位16進制的值,附加在rowkey的末尾,即保證了rowkey不會過度的膨脹(最多8個字符的長度),又保證了低重復率(CRC-32碰撞幾率相對較低),而且可以支持數(shù)據(jù)的重復導入(相同記錄計算的編碼一樣)。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多