storm應用從(cóng)數據源讀(dú)取數據

2018-04-22 14:54:54 admin

有贊使用storm已經有将近3年(nián)時間,穩定支撐著(zhe)實時統計、數據同步、對賬、監控、風控等業(yè)務。訂單實時統計是其中一(yī)個(gè)典型的業(yè)務,對數據準确性、性能(néng)等方面都有較高(gāo)要求,也是上(shàng)線時間最久的一(yī)個(gè)實時計算(suàn)應用。通(tōng)過訂單實時統計,描述使用storm時,遇到(dào)的準确性、性能(néng)、可靠性等方面的問題。

訂單實時統計的演進

第一(yī)版:流程走通(tōng)

在使用storm之前,顯示實時統計數據一(yī)般有兩種方案:

在數據庫裡(lǐ)執行count、sum等聚合查詢,是簡單快速的實現方案,但容易出現慢(màn)查詢。

在業(yè)務代碼裡(lǐ)對統計指标做累加,可以滿足指标的快速查詢,但統計邏輯耦合到(dào)業(yè)務代碼,維護不方便,而且錯(cuò)誤數據定位和修正不方便。

既要解耦業(yè)務和統計,也要滿足指标快速查詢,基于storm的實時計算(suàn)方案可以滿足這兩點需求。

一(yī)個(gè)storm應用的基本結構有三部分:數據源、storm應用、結果集。storm應用從(cóng)數據源讀(dú)取數據,經過計算(suàn)後,把結果持久化或發送消息給其他應用。

第一(yī)版的訂單實時統計結構如下(xià)圖。在數據源方面,最早嘗試在業(yè)務代碼裡(lǐ)打日志(zhì)的方式,但總有業(yè)務分支無法覆蓋,采集的數據不全。我們的業(yè)務數據庫是mysql,随後嘗試基于mysql binlog的數據源,采用了阿裡(lǐ)開(kāi)源的canal,可以做到(dào)完整的收集業(yè)務數據變更。

在結果數據的處理上(shàng),我們把統計結果持久化到(dào)了mysql,并通(tōng)過另一(yī)個(gè)後台應用的RESTful API對外提供服務,一(yī)個(gè)mysql就(jiù)可以滿足數據的讀(dú)寫需求。

為(wèi)了提升實時統計應用吞吐量,需要提升消息的并發度。spout裡(lǐ)設置了消息緩沖區,隻要消息緩沖區不滿,就(jiù)會(huì)源源不斷從(cóng)消息源canal拉取數據,并把分發到(dào)多(duō)個(gè)bolt處理。

第二版:性能(néng)提升

第一(yī)版的性能(néng)瓶頸在統計結果持久化上(shàng)。為(wèi)了确保數據的準确性,把所有的統計指标持久化放(fàng)在一(yī)個(gè)數據庫事(shì)務裡(lǐ)。一(yī)筆訂單狀态更新後,會(huì)在一(yī)個(gè)事(shì)務裡(lǐ)有兩類操作:

訂單的曆史狀态也在數據庫裡(lǐ)存著(zhe),要與曆史狀态對比決定統計邏輯,并把最新的狀态持久化。storm的應用本身是無狀态的,需要使用存儲設備記錄狀态信息

當大家知道實時計算(suàn)好用後,各産品都希望有實時數據,統計邏輯越來越複雜(zá)。店鋪、商品、用戶等多(duō)個(gè)指标的寫操作都是在一(yī)個(gè)事(shì)務裡(lǐ)commit,這一(yī)簡單粗暴的方式早期很好滿足的統計需求,但是對于update操作持有鎖時間過長(cháng),嚴重影響了并發能(néng)力。

為(wèi)此做了數據庫事(shì)務的瘦身:

去除曆史狀态的mysql持久化,而是通(tōng)過單條binlog消息的前後狀态對比,決定統計邏輯,這樣就(jiù)做到(dào)了統計邏輯上(shàng)的無狀态。但又(yòu)産生(shēng)了新問題,如何保證消息有且隻有處理一(yī)次,為(wèi)此引入了一(yī)個(gè)redis用于保存最近24小(xiǎo)時内已成功處理的消息binlog偏移量,而storm的消息分發機(jī)制又(yòu)可以保證相(xiàng)同消息總是能(néng)分配到(dào)一(yī)個(gè)bolt,避免線程安全問題。

統計業(yè)務拆分,先是線上(shàng)業(yè)務和公司内部業(yè)務分離,随後又(yòu)把線上(shàng)業(yè)務按不同産品拆分。這個(gè)不僅僅是bolt級别的拆分,而是在spout就(jiù)完全分開(kāi)

随著(zhe)統計應用拆分,在canal和storm應用之間加上(shàng)消息隊列。canal不支持多(duō)消費(fèi)者,而實時統計業(yè)務也不用關系數據庫底層遷移、主從(cóng)切換等維護工(gōng)作,加上(shàng)消息隊列能(néng)把底層數據的維護和性能(néng)優化交給更專業(yè)的團隊來做。

熱點數據在mysql裡(lǐ)做了分桶。比如,通(tōng)常一(yī)個(gè)店鋪天級别的統計指标在mysql裡(lǐ)是一(yī)行數據。如果這個(gè)店鋪有突發的大量訂單,會(huì)出現多(duō)個(gè)bolt同時去update這行數據,出現數據熱點,mysql裡(lǐ)該行數據的鎖競争異常激烈。我們把這樣的熱點數據做了分桶,實驗證明在特定場景下(xià)可以有一(yī)個(gè)數量級吞吐量提升。

最終,第二版的訂單實時統計結構如下(xià),主要變化在于引入了MQ,并使用redis作為(wèi)消息狀态的存儲。而且由最初的一(yī)個(gè)應用,被拆成了多(duō)個(gè)應用。

為(wèi)您推薦