日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

背景

在日常工作中,我們通常需要存儲一些日志,譬如用戶請求的出入參、系統運行時打印的一些info、error之類的日志,從而對系統在運行時出現的問題有排查的依據。

日志存儲和檢索是個很常見且簡單的工作,市面也有很多關于日志搜集、存儲、檢索的框架可供使用。

譬如我們只有個位數機器時,可以通過登錄服務器,查看log4j之類的框架打印到本地文件的日志。當日志多起來后,可以用elk三劍客處理日志。

當日志量進一步增多,我們可以上消息隊列,譬如kafka之類來承接,然后消費入庫。或者寫本地文件,再采用filebeat之類上報再入庫。

以上都是較為常見的日志傳輸和存儲的方案,成本可控的情況下,可適用于絕大多數場景。

我們可以簡單總結一下日志框架的功能,大概是暫存、傳輸、入庫保存、快速檢索。

量級上升,成本高昂

技術方案的設計和取舍,往往強受限于成本。當成本高企到難以承受時,將必須導致技術方案的升級換代。那么問題來了,我就是存個日志而已,怎么就成本難以承受了呢?

我們以一個常見的日志傳輸及存儲方案來舉例,入下圖,暫存就是采用客戶端寫本地文件存日志,傳輸即是采用MQ,消費入庫常見的如ES。下圖方案,為了減少部分存儲成本,將日志詳情存儲于壓縮更好的Hbase,僅將查詢時需要的一些索引字段放在了ES。

京東App秒級百G日志傳輸存儲架構設計與實戰

 

以上作為一個常用的方案,為什么會成本高昂呢。

我們來簡單計算一下,京東App某個模塊(是一個模塊,非整個App累計),單次用戶請求,用戶的入參+返回值+流程中打印的日志占用的大小在40k-2M之間,中位數在60k左右。該模塊日常每秒約2-5萬次訪問,高峰時會翻10倍,極高峰可達百萬。

以3萬每秒來算,產生的日志大小為1.8G,也就是說即便是低負載時,這個日志框架要吞下1.8G的傳輸與存儲。但這是遠遠不夠的,因為我們即便放棄極高峰,僅僅支撐偶現的高峰,也需要該系統能支撐秒級15G以上的吞吐。但是這僅僅才是一個模塊而已,算上前中臺這樣的模塊還有很多。

那么我們就可以來算一算了,一秒1.5G,一個小時就是5.4TB。小高峰是肯定要支撐的,也就是秒級30萬是要保的,那么我們的系統就要能支撐秒級15G單模塊,算上各模塊,200G秒級是跑不了了。

這只是各個機器所打印在各自本地的原始日志文件占用的大小,然后要發到MQ集群,大家都知道,MQ也是寫磁盤的,這200G一點不少的在MQ機器上做了保存,并且MQ還有備份機制,就以最簡陋的單備份來說,MQ每秒要承接400G的磁盤,并且離刪除后釋放磁盤還有挺長一段時間,哪怕只存1個小時,也是一個巨大的數字。

我們知道,一般服務器在磁盤還不錯的情況下,單機秒級寫入量200多M算比較不錯的情況,通過上面的了解,我們僅僅做到日志的暫存和傳輸就需要2千臺以上的服務器資源。

然后就到了worker消費集群,該集群只是純粹的內存數據交換,不占磁盤,worker消費后寫入數據庫。大家基本可以想象到,數據庫的占用是如何。OK,我們終于把數據存了進去,查詢問題就成了另外一個必須面對的事情,如何快速從無數億中找到你要查詢的那個用戶的鏈路日志。

到了此時,成本就成了非常要命的事情,尤其方案的設計,會導致原本就很龐大的數據,在鏈路上再次放大多倍,那么巨大的硬件成本如何解決。

縮短流程,縮減流量

通過上面的分析,我們已經發現,即便是市面上最通用的日志方案,在如此巨大的流量面前,也難以持續下去,高昂的硬件成本,將迫使我們去尋找更合適的技術方案。

世界上有一個著名的法則叫"奧卡姆剃刀定律",講的是程序員該如何選擇合適的剃刀,來讓自己的秀發光滑柔順有光澤。

其實不是的,該定律主要就是八個字"如無必要,勿增實體"。當一個流程難以支撐當前的業務時,我們就該審視一下,哪些步驟是不必要的。

京東App秒級百G日志傳輸存儲架構設計與實戰

 

從這個通用流程中,其實我們很容易就能發現,我們經歷了很多讀寫,每次讀寫都伴隨著磁盤的讀寫(包括MQ也是寫磁盤的),和頻繁的序列化反序列化,以及翻倍的網絡IO。

那么讓我們揮舞起奧卡姆的剃刀,做一些刪減,把非必要的部分給刪掉,就變成了下圖的流程:

京東App秒級百G日志傳輸存儲架構設計與實戰

 

我們發現,其實寫本地磁盤、和MQ都是沒有必要的,我們完全可以將日志數據寫到本地內存,然后搞個線程,定時通過UDP將日志直接發送到worker端即可。

worker接收到之后,解析一下,寫入自己的內存隊列,再起數個異步線程,批量將隊列的數據寫入ClickHouse數據庫即可。

大家可能看到了,下圖的流程中,那個圓圈明顯比上圖的圓圈要小,這是為什么呢?因為我做了壓縮。

前文講過,我們單條報文40k-2M,這是一個非常大的報文,這里面都是一些用戶請求的入參Json和出參Json以及一些中途日志,我們完全沒有必要將原文原封不動往外傳輸。

通過采用主流的snappy、zstd等壓縮工具類,可以直接將字符串壓縮成byte[]再往外傳輸,這個被壓縮后的字符串,直至入庫都是byte[],全程不對大報文解壓。

那么這個壓縮能壓多少呢,80%-90%,一個60k的報文,往外送時就剩6-8k了,可想而知,僅僅壓縮一下原始數據,就在整個流程中,節省了巨大的帶寬,同時也大幅提升了worker的吞吐量。

這里有個小細節,udp單個最大報文是64kb,如果我們壓縮后,還是超過了64kb的話,udp是送不出去的,這里可以選擇發個http請求送到worker即可。

通過上圖,我們可以看到,當流程中的某些環節并不是必需的時,我們應該果斷砍掉,不要輕易照搬網上的方案,而應該選擇更適合自己的方案。下面我們詳細講一下系統是如何設計、運轉的。

更強悍的日志搜集系統

京東App秒級百G日志傳輸存儲架構設計與實戰

 

我們來審視一下這個鏈路極短的日志搜集系統。

配置中心:用來存儲worker的IP地址,供客戶端獲取自己模塊所分配的worker集群的ip。

client:客戶端啟動后,從配置中心拉取分配給自己這個模塊的worker集群的IP,并輪詢將搜集的日志壓縮后發送過去,通過UDP的方式。

worker:每個模塊會分配數量不等的worker機器,啟動后上報自己的IP地址到配置中心。接受到客戶端發來的日志后,解析相應的字段,批量寫入clickhouse數據庫。

clickhouse:一個強大的數據庫,壓縮比很高,寫入性能極強,按天分片,查詢速度佳。非常適合應用于日志系統這種寫入極大,查詢較少的系統。

dashboard:可視化界面,從clickhouse查詢數據展示給用戶,具有多條件多維度查詢功能。

大家都能看出來,這其中最關鍵的地方是worker端,它的承接流量、消費性能、入庫性能將決定著整個鏈路能否良好地運轉。

我們主要分別講解一下client端和worker端的實現。

京東App秒級百G日志傳輸存儲架構設計與實戰

 

Client端聚合日志

一次請求中,我們通常要保留的日志信息主要有:

(1)請求的出入參>

如果是http web應用,要獲取出入參比較簡單的方式就是通過自定義filter即可。client的sdk里定義了一個filter,接入方通過配置該filter生效即可搜集到出入參。

如果是其他rpc應用非http請求的,也提供了對應的filter攔截器來獲取出入參。

在獲取到出入參后,sdk對其中大報文,主要是出參進行了壓縮,并將整個數據定義為一個JAVA對象,做protobuf序列化,通過UDP方式往自己對應的worker集群輪詢傳輸。

(2)鏈路上自己打印的一些關鍵信息,如調用其他系統的的出入參,自己打印的一些info、error信息>

sdk分別提供了log4j、logback、log4j2三個常用日志框架的自定義appender,用戶可以通過在自己的日志配置文件(如logback.xml)中,將我自定義的appender定義出來即可,那么后續用戶在代碼里所有打印的info、error等日志都會執行這個自定義appender。

同樣,這個自定義appender也是將日志暫存內存,然后異步UDP外送到worker。

這里主要有兩個地方需要注意,一是當壓縮后的報文依舊超出udp最大報文值時,即通過http送出。二是這一次請求,鏈路中可能會使用多線程、線程池技術,為避免鏈路tracer的唯一id在線程池丟失,sdk采用了TransmittableThreadLocal來保持鏈路的ID,這個查一下就懂。

總體來說,client端實現較為簡單,省略了寫本地磁盤、消費文件發MQ等等步驟,整體只有一次Protobuf序列化操作,對CPU、接入方性能影響極小,采用UDP外送,不需要worker的任何回復,也不用考慮tcp模式下worker消費慢導致自己阻塞的問題。整體非常簡潔高效。

Worker端消費日志并入庫

worker端是調優的重點,由于要接收海量客戶端發來的日志,解析后入庫,所以worker需要具備很強的緩沖能力。

我們都能看出來,系統的瓶頸點肯定在入庫這個階段,解析日志,抽取字段都是效率很高的,而且完全可以通過控制線程的數量來控制住,而入庫將強受限于clickhouse的寫入性能。至于clickhouse是如何做的優化,后面會有clickhouse集群負責人來講一下做了哪些優化。

為了做好這個緩沖,即便日志接收量大于入庫量,我們也要能接下來這些數據,盡量不丟失。首先硬件上,采用大內存機器,8核32G的容器,來盡量多屯一些數據。其次,采用了雙緩沖隊列,先將所有接收的數據放一個隊列,然后多線程消費、解析成可供入庫的行數據,再放入一個待入庫隊列,然后批量入庫。

那么我們做的這些操作,能支撐什么樣的數據量呢?

通過線上的應用和嚴苛的壓測,這樣一臺單機Docker容器,每秒可以處理原始日志1-5千萬行,譬如一條用戶請求,中途產生了共計1千多行日志,那么這樣的一臺worker單機,每秒可以處理2萬客戶端QPS。對外寫clickhouse數據庫,每秒可以寫200多M比較穩定。

通過對上文的了解,我們知道,這些數據都是被壓縮過的,直至庫里面的都是壓縮過的,只有當最終用戶查詢時,才會進行解壓。所以,這200M,基本相當于原始數據1G多的大小。

也就是說,只要clickhouse寫入速度跟的上,這個系統僅需100臺就可以極其高效地處理原始秒級百G的日志。對比寫MQ的方案,中途所有會出現瓶頸的點如MQ寫磁盤速度、消費拉取速度等,都將不復存在。這是一個純內存交換的鏈路系統。

強悍的Clickhouse

通過以上的了解,我們可以清楚的看到,worker作為一個純內存計算的組件,client端通過worker的數量進行hash均勻分發到各個worker,所以worker可以動態擴容而且不存在性能瓶頸,其唯一受限制的就是寫入庫的速度。

倘若寫庫速度跟不上,則worker必須要拿有限的內存去屯下發來的大量數據,一旦寫滿則就會開始丟棄接收到的數據。所以整個系統的瓶頸點,就是寫庫的速度。

Clickhouse是面向海量數據實時、多維分析、高性能的新一代OLAP數據庫管理系統,實現了向量化執行和SIMD指令,對內存中的列式數據,一個batch調用一次SIMD指令,大幅縮短了計算耗時,帶來數倍的性能提升。目前已成為驅動京東集團業務增長、創新的“超級引擎”。那么在京東App秒級百G日志傳輸存儲架構中,Clickhouse如何支撐大吞吐量數據的寫入,主要在于兩點

1)集群高可用架構

EasyOLAP部署CH集群是三層結構:域名 + CHProxy + CH節點,域名轉發請求到CHProxy,再由CHProxy根據集群節點狀態來轉發。CHProxy的引入是為了讓Query均勻分布在每個節點上,,并對CHProxy做了一定的改進,自動感知集群節點的狀態變化。

京東App秒級百G日志傳輸存儲架構設計與實戰

 

多條件查詢控制臺

控制臺比較簡單,主要就是做一些sql語句查詢,做好clickhouse的高效查詢,這里簡單提一些知識點。

做好數據的分片,如按天分片。用好prewhere查詢功能,可以帶來性能的提升。做好索引字段的設計,譬如檢索常用的時間、pin。

細節難以盡述,要從百億千億數據中,做好極速的查詢,還需要對clickhouse的一些查詢特性有所了解。

下圖界面展示的即為一些索引項,點擊查看詳情,則從數據庫撈出壓縮過的數據,此時才解壓并展示給前端。查看鏈路,則是該次請求中,整個鏈路用戶打印的log(包括線程池內的)。

京東App秒級百G日志傳輸存儲架構設計與實戰

 


京東App秒級百G日志傳輸存儲架構設計與實戰

 

總結與對比

我們可以簡單的做一些對比,主要在于硬件成本和軟件性能的對比。

京東App秒級百G日志傳輸存儲架構設計與實戰

 

從上文可知,磁盤的占用原始方案占用了磁盤(1份),MQ(2份),數據庫(1份)。而在新的方案中,磁盤的占用僅剩下clickhouse的(0.8份),clickhouse自身又對數據做了壓縮,實際占用空間不到入庫容量的80%。

那么僅磁盤即可節省75%以上的存儲成本。

大家都知道,秒級的吞吐量,是伴隨著服務器Cpu的耗費的,并不是說只給個大硬盤,即可一臺服務器每秒吞吐1個G的。每臺服務器秒級的吞吐量是有上限的,秒級占用磁盤的上升,即對應Cpu數量的上升,要支撐一秒1G的磁盤寫入,需要5臺或以上的服務器。

京東App秒級百G日志傳輸存儲架構設計與實戰

 

那么在磁盤的大幅節約下,線性地節省了大量的中間過程Cpu服務器。實際粗略統計效果,流程中服務器可節約70%以上。

在軟件性能上,過程很好理解。對Client端的消耗主要就是序列化、寫磁盤、讀磁盤、反序列化這幾步的消耗,Udp則僅有一步序列化。我們假設MQ集群是有無限的寫入能力,可以吞下所有的發過去的日志,那么就是worker端的消費性能對比。

從MQ拉取并消費,這個過程如果MQ沒有積壓,則有零拷貝在支撐高速的拉取,如果積壓了,則可能產生大量的MQ磁盤IO,拉取速度會大幅下降。這個過程效率會明顯低于Udp發送到worker的處理效率,而且占用雙份的網絡帶寬。實際表現上,worker表現出的強勁性能,較之前單條拉取MQ集群時,消費性能提升在10倍以上。

本文到此就結束了,主要簡略介紹了一個新的日志搜集系統(用戶跟蹤框架)的設計方案,以及該方案能帶來的巨大的成本節省。相關代碼日后會開源于"gitee.com"的京東零售賬號下,屆時有相關需求的同學可以加以關注。

分享到:
標簽:架構
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定