攜程度假商品千億日誌系統架構演進

作者簡介

cd,攜程資深後端開發工程師,度假商品系統研發,專注於後端系統性能提升。

在攜程旅遊度假的線路類商品系統中,由於商品結構複雜,涉及底層數據表上千張,在日常供應商以及業務維護過程中,每日產生 6 億 + 的數據變動記錄。這些數據的變動留痕,不但可供錄入方查看,也對日常產研的排障起着至關重要的作用,同時也可以提供給 BI 做數據進一步分析。商品日誌系統建設尤爲重要,隨着商品日誌系統不斷髮展迭代,已經積累達到 1700 億條日誌。

本文將介紹線路商品日誌系統的演進過程以及在其中遇到的問題。

一、發展軌跡

線路商品日誌系統的發展大致可以分爲以下三個階段:

2019 年以前:單表日誌

在 2019 年以前,商品系統尚無統一的日誌系統來記錄商品的變更,在系統中使用 DB 日誌表,該表以非結構化的方式記錄商品基本信息的變動。

2020 年~ 2022 年:平臺化

在系統改造過程中,建立統一的商品系統日誌平臺,通過配置的方式記錄商品的數據變動日誌,覆蓋商品維護的全部流程。

2023 ~2024 :開放

經過在線路商品系統的實踐,商品系統日誌平臺經歷百億級數據的考驗,並以靈活的配置方式記錄數據變動日誌,同時支持自定義索引字段,具有接入和使用成本較低的優勢。爲此,通過對商品系統日誌進行改造,逐步向門票、用車等業務線開放使用。

二、演進過程

2.1 V1.0 DB 單表存儲

在 2019 年以前,記錄線路商品的變動日誌較爲簡單,在 DB 中建立一張日誌表(id,LogContent)來記錄日誌,數據變動以非結構化的文本記錄在 LogContent 字段內,且僅覆蓋商品最基本的信息,在使用時通過數據庫查詢工具執行 sql 語句 like 關鍵字進行查詢,這種方式帶來的問題也顯而易見:

由於是單表文本字段存儲,導致表的數量非常巨大,達到單表 10 億 +(370GB)的數據,查詢超時問題嚴重,不得不進行定期歸檔。

由於日誌內容以文本字段存儲,在進行日誌查詢時,一般由開發人員使用 like 語句直接查詢 DB,例如:select id, LogContent from log where LogContent like '%1234%'。查詢速度緩慢,嚴重影響日常排障流程。

由於日誌寫入與業務代碼強耦合,且採用非結構化存儲。對於新增日誌,需要對業務代碼進行改動,在接入時存在一定的成本,且接入後無法直接提供給供應商或業務人員直接使用,最終仍需要開發人員進行查詢轉換。

2.2 V2.0 平臺化

2.2.1 技術選型

針對 V1.0 遇到的問題,重點在於海量日誌數據的存儲與查詢,業內解決海量日誌數據存儲與查詢的方案一般有以下幾個:

ES+Hbase

HBase 提供高併發的隨機寫和支持實時查詢,是構建在 HDFS 基礎上的 NoSql 數據庫,適用於海量日誌數據的存儲,可支持到 PB 級別的數據存儲。但其查詢能力有所欠缺,支持 RowKey 快速查詢,若有複雜查詢則需要自建索引。ES 提供強大的搜索能力,支持各種複雜的查詢條件,適合快速檢索及靈活查詢的場景。ES + HBase 的組合,利用各個組件的優勢,結合起來解決海量日誌數據存儲及查詢的問題,但架構較爲複雜,需要保證兩個組件間數據的一致性。

MongoDB

支持多種查詢,具有文檔型及嵌套的數據結構,但其支持的數據量級一般在 10 億級別,對比 HBase 要欠缺得多。如果想要處理 TB 級以上的數據量,需要進行適當的架構設計和優化,例如利用分片集羣來水平擴展數據等,付出的成本會比較高。

ClickHouse

Clickhouse 是一個開源的列式數據庫,採用列存儲的數據組織方式,具有高性能、可伸縮性、容錯性和低延遲查詢等特點。查詢性能出色,可實現秒級甚至毫秒級的查詢性能,對於數據壓縮和存儲效率高,可節省成本。適用於海量數據的存儲及查詢場景。

通過對以上方案進行對比,我們的數據量級已經超過 MongoDB 一般的處理能力,因此該方案被淘汰。對比 ES + HBase 與 ClickHouse,這兩個方案都比較適合海量日誌的存儲與查詢,但是受限於內部成本控制,CK 集羣的日誌保存時長被控制在一定天數內,無法滿足我們業務場景的需求。最終,我們選擇 ES + HBase 的方案。

2.2.2 整體架構

基本原理即利用 HBase 解決存儲問題,利用 ES 解決搜索問題,並將 ES 的 DocID 與 HBase 的 RowKey 關聯起來。通過發揮各個組件的優勢,相互結合解決海量日誌的存儲與查詢問題。如上圖所示,在接入日誌 API 後,所有日誌均經過 MQ 進行異步處理,如此既能夠將日誌寫入與業務代碼的邏輯解耦,又能確保寫入速度的平穩,避免高峯流量對整個 ES + HBase 集羣的寫入造成壓力。

2.2.3 RowKey 設計

RowKey 設計原則:

唯一性:RowKey 應保證每行數據的唯一性;

散列性:數據均勻分佈,避免熱點數據產生;

順序性:可以提高查詢性能;

簡潔性:減少存儲空間及提高查詢性能;

可讀性:以便人工查詢及理解;

對於線路商品日誌,對於直接可讀性要求不高,查詢的場景我們是從 ES 中先查出 RowKey,再用 RowKey 去 hbase 查詢日誌原文,整個過程 RowKey 是人工不可見的,結合我們實際的場景,線路商品數據日誌的 RowKey 由五部分構成 {0}-{1}-{2}-{3}-{4}

{0}:傳入的 pk 轉換爲 md5[pk] 值 16 進制字符串,取前 8 爲

{1}:tableId 補 0 至 8 位

{2}:pk+4 位隨機值補 0 至 24 位

{3}:log 類型補 0 至 16 位

{4}:時間戳

2.2.4 擴展

對於線路商品信息的維護分散於不同的模塊中,例如錄入模塊、直連模塊等。鑑於此,我們抽象出統一的數據寫入服務,並提供統一的日誌接入 API,API 內部異步寫入日誌。在底層的數據寫入服務中,將所有的寫入操作接入日誌 API。通過這個方式,將擴展性統一到日誌配置中心。

寫入流程

日誌的寫入流程如上圖所示,客戶端調用日誌 API 以進行數據變動日誌的寫入操作。日誌服務在接收到請求後,將其拋入 MQ,由後續的消費組進行消費處理。消費組件在接收到消息後,會進行相應的消費處理,並根據上述的 RowKey 生成策略爲該條日誌生成 RowKey,隨後將日誌文本內容寫入 HBase,在寫入成功之後,再將索引數據寫入到 ES。其中,若 HBase 或 ES 中的任何一個寫入失敗,都會將此條日誌寫入補償 redis 集羣,再由補償邏輯進行後續補償,以確保整個日誌的寫入成功。

查詢流程

日誌的查詢流程如上圖所示:客戶端調用查詢 API 並傳入查詢參數,日誌服務接收到請求參數後,將其轉換爲 ES 分頁查詢請求,從 ES 集羣中查出 RowKey,再彙總 RowKey 並從 HBase 中批量查出日誌全文內容。

此外,我們利用上述查詢 API,建立一個日誌查詢頁面,供研發人員使用。在該頁面,相關開發人員可以便捷地進行數據變動日誌的查詢。上述日誌平臺的建立,相對完美地解決線路商品海量數據變動日誌的存儲及查詢問題。同時,抽象日誌的配置中心,解決一定的擴展性問題。

整個系統的優點在於:基於表級別日誌的商品日誌記錄,覆蓋全面,配置靈活,索引結構化存儲,支持海量日誌數據的存儲及查詢。

缺點是:對於使用方而言存在一定的侷限性,過於 “技術化”,開發人員使用較爲方便,但供應商與業務人員使用困難。

2.3 V3.0 賦能

2.3.1 業務賦能

存儲能力

隨着日誌寫入量的增加,日誌查詢效率逐漸下降,對 ES 和 HBase 的拆分勢在必行。如下圖所示,我們對 ES 和 HBase 進行橫向的拆分與擴容,並在日誌配置中心制定匹配規則,根據接入日誌類型的不同,將其匹配到不同的集羣進行寫入。此外,對於接入方,我們也支持獨立集羣申請,使用方可以根據自身情況決定是使用獨立的集羣部署,還是使用公用集羣。

搜索能力

搜索能力的提升主要由以下兩個部分:

索引字段擴展:支持的索引字段更多。前期我們絕大部分場景的日誌的索引條件是產品 id 或者資源 ID,隨着接入的日誌變多,索引字段也變的豐富起來。對於日誌搜索場景我們進行梳理,預留 10 個可支持不同查詢的索引字段(其中四個數值型、4 個字符型,2 個日期型)供使用方使用,覆蓋絕大多數的查詢場景。

ES 索引分區:隨着接入的日誌增多,單個索引文件也愈發龐大,直接影響日誌的查詢性能。一般而言,對於日誌類型數據,常見的方案是依據時間建立索引,該方案的優勢如下:

1)提升查詢性能。若日誌攜帶時間範圍進行查詢,則可僅搜索特定時間段的索引,避免全量索引的查詢開銷。

2)便於數據管理。可以按照時間刪除舊的索引,從而節省存儲空間。

通過對日誌進行分類,主要包括商品信息、開關班、價格庫存等模塊。隨後結合業務使用場景、每天產生的增量數據以及服務器資源進行評估,最終決定按周建立索引,且索引數據保留一年。

1)利用定時任務在每週一時創建下一週的索引;

2)利用定時任務每週刪除已過期的索引;

基於以上存儲能力與搜索能力的擴展提升之後,我們在日誌配置中心定製了【業務線 <--> 日誌集羣】的路由規則,來決定接入的其它業務線日誌最終存儲的日誌集羣,提供了更加靈活與具有彈性的業務線接入能力。

2.3.2 供應商賦能

展示能力

在 V2.0 版本中,日誌頁面僅限於研發人員使用,底層數據過於技術化,業務與供應商難以理解。通常情況下,如果能將日誌的查詢前置到供應商及業務環節,將極大地減少研發人員平時工作中的排障時間。

爲此,我們提供 B 端的日誌查詢頁面,給供應商及業務人員平時排查問題使用。我們對日誌內容進行格式化的轉換處理,將其轉換爲供應商和業務人員能夠理解的信息,包括行轉列、新舊對比、KV 轉換、關聯數據查詢等。日誌內容不再是抽象的文本,而是展示爲與平時使用的商品系統相對應的內容。這對業務和供應商更加友好。

擴展能力

基於上一步展示能力的提升,對於新接入的日誌如何能快速爲業務及供應商提供 B 端的頁面進行查看,這一步將大幅節省開發排查時間。對底層日誌數據需要轉換爲業務及供應商能看懂的信息的場景進行分析,並總結 7 種數據展示的方式,分別如下:

1)文本字段類:此種展示內容最爲簡易,無需進行轉換,用戶可直接理解日誌記錄的內容,前端展示的即爲此內容。

2)數據關聯類:此類日誌內容中記錄的是一個 id,但實際內容存在於另一個關聯表的數據中,例如 id:1 表示的是跟團遊,不能將 id:1 的日誌展示給用戶,而需轉換爲 “跟團遊”,這就需要進行一步關聯 db 表的查詢轉換。

3)枚舉類:此類日誌內容記錄的是一個 key 值,實際用戶能理解的是該 key 值所代表的含義,例如產品鑽級:0,就需要轉換爲:“不分級”,這就需要關聯枚舉值的配置文件進行查詢轉換。

4)位存儲類:此類日誌內容記錄的是一種計算後的結果數值。例如支付方式是通過按位與計算然後累加的結果。這種情況就需要按照一定的計算方式將其還原回去。

5)字段組合:此類日誌記錄的是分散的數據,但實際需要將數據結合在一起查看纔會更具業務意義,例如資源適用人檔,日誌中分爲最大、最小記錄。實際展示時需要結合到一起展示範圍。

6)外部接口:此類日誌記錄的是一種依賴外部接口的值,例如日誌記錄的是城市 id:2,代表的是上海,這就需要調用外部接口將 2 轉換爲上海。

7)差異對比類:此類日誌需對結果進行解析以作對比,從而使用戶能夠更爲直觀地理解。通常存在兩種情形:其一,日誌內容所記錄的即爲兩份對比數據,此種情況僅需依循規則予以解析即可;其二,若日誌數據屬於當次的快照數據,則需與前一次快照數據進行對比,以找出差異。最終達成如下圖所示的展示效果。

針對以上這些日誌解析的場景,我們最終構建一個日誌轉換配置。對於新加入的日誌,在絕大多數場景下,我們只需修改底層的數據提取及轉換配置,便可較爲快速的配置出日誌查詢頁面,提供給供應商使用。

三、結語

本文詳細介紹度假商品日誌平臺的演進歷程,以及在各個階段遇到的問題及解決方案。在整個演進過程中,針對海量日誌數據存儲與搜索的技術挑戰,我們採取一系列措施,實現千億級數據查詢在 500ms 內的響應。

同時將日誌系統開放,將問題查詢解決前置到供應商及業務人員,極大降低一些數據變動查詢需求的複雜度,減輕研發及 TS 同事重複性的工作。此外,我們還對日誌平臺進行橫向的擴容配置,以支持更多的業務線可以接入。截至目前,多個業務線總數據存儲量達到千億級別。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/_nyvMlek_kPT0poVIC1jWg