278
財經資訊
處理-通過ConsumerLib實現不丟、保序、去重__最佳實踐_日誌服務-阿裏雲
日誌處理是一個很大範疇,其中包括實時計算、數據倉庫、離線計算等眾多點。這篇文章主要討論如何在實時計算場景中,如何能做到日誌處理保序、不丟失、不重複,並且在上下遊業務係統不可靠(存在故障),業務流量劇烈波動情況下,如何保持這三點。
為了能夠方便理解,這裏會使用《銀行的一天》作為例子將概念解釋清楚。在篇幅的末尾,我會介紹下日誌服務LogHub功能,是如何與Spark Streaming、Storm Spout等配合,完成日誌數據的處理過程。
問題定義
什麼是日誌數據?原LinkedIn員工Jay Kreps在《The Log: What every software engineer should know about real-time data’s unifying abstraction》描述中提到:“append-only, totally-ordered sequence of records ordered by time”
- Append Only:日誌是一種追加模式,一旦產生過後就無法修改
- Totally Order By Time:嚴格有序,每條日誌有一個確定時間點。不同日誌在秒級時間維度上可能有重複,比如有2個操作GET、SET發生在同一秒鍾,但對於計算機而言這兩個操作也是有順序的
什麼樣的數據可以抽象成日誌?
半世紀前說起日誌,想到的是船長、操作員手裏厚厚的筆記。如今計算機誕生使得日誌產生與消費無處不在:服務器、路由器、傳感器、GPS、訂單、及各種設備通過不同角度描述著我們生活的世界。從船長日誌中我們可以發現,日誌除了帶一個記錄的時間戳外,可以包含幾乎任意的內容,例如:一段記錄文字、一張圖片、天氣狀況、船行方向等。幾個世紀過去了,“船長日誌”的方式已經擴展到一筆訂單、一項付款記錄、一次用戶訪問、一次數據庫操作等多樣的領域。
在計算機世界中,常用的日誌有:Metric,Binlog(Database、NoSQL),Event,Auditing,Access Log 等。
在我們今天的演示例子中,我們把用戶到銀行的一次操作作為一條日誌數據。其中包括用戶、賬號名、操作時間、操作類型、操作金額等。
例如:
2016-06-28 08:00:00 張三 存款 1000元
2016-06-27 09:00:00 李四 取款 20000元
LogHub數據模型
為了能抽象問題,這裏以阿裏雲日誌服務下LogHub作為演示模型,詳細可以參見日誌服務下基本概念。
- Log: 由時間、及一組Key,Value對組成
- LogGroup: 一組日誌的集合,包含相同Meta(IP,Source)等
兩者關係如下:
- Shard: 分區,LogGroup讀寫基本單元,可以理解為48小時為周期的FIFO隊列。每個Shard提供 5 MB/S Write, 10 MB/S Read能力。Shard 有邏輯區間(BeginKey,EndKey)用以歸納不同類型數據
- Logstore:日誌庫,用以存放同一類日誌數據。Logstore是一個載體,通過由[0000, FFFF..)區間Shard組合構建而成,Logstore會包含1個或多個Shard
- Project: Logstore存放容器
這些概念相互關係如下:
銀行的一天
我們來以19世紀銀行來舉例子,城市裏有若幹用戶(Producer),到銀行去存取錢(User Operation),銀行有若幹個櫃員(Consumer)。因為19世紀還沒有電腦可以實時同步,因此每個櫃員都有一個小賬本能夠記錄對應信息,每天晚上把錢和賬本拿到公司去對賬。
在分布式世界裏,我們可以把櫃員認為是固定內存和計算能力單機。用戶是來自各個數據源的請求,Bank大廳是處理用戶存取數據的日誌庫(Logstore)。
- Log/LogGroup:用戶發出的存取款等操作
- 用戶(User):Log/LogGroup生產者
- 櫃員(Clerk):銀行處理用戶請求的員工
- 銀行大廳(Logstore):用戶產生的操作請求先進入銀行大廳,再交給櫃員處理
- 分區(Shard):銀行大廳用以安排用戶請求的組織方式
問題1:保序(Ordering)
銀行有2個櫃員(A,B),張三進了銀行,在櫃台A上存了1000元,A把張三1000元存在自己的賬本上。張三到了下午覺得手頭緊到B櫃台取錢,B櫃員一看賬本。不對啊,你沒有在我這裏存錢?
從這個例子可以看到,存取款是一個嚴格有序的操作,需要同一個櫃員(處理器)來處理同一個用戶的操作,這樣才能保持狀態一致性。
實現保序的方法很簡單:排隊,創建一個Shard,終端隻有一個櫃員A來處理。用戶請求先進先出,一點問題都沒有。但帶來的問題是效率低下,假設有1000個用戶來進行操作,即使有10個櫃員也無濟於事。
這種場景怎麼辦?
- 假設有10個櫃員,我們可以創建10個Shard
- 如何保證對於同一個賬戶的操作是有序的?可以根據一致性Hash方式將用戶進行映射。例如我們開10個隊伍(Shard),每個櫃員處理一個Shard,把不同銀行賬號或用戶姓名,映射到特定Shard中。在這種情況下張三 Hash(Zhang)= Z 永遠落在一個特定Shard中(區間包含Z),處理端麵對的永遠是櫃員A。
當然如果張姓用戶比較多,也可以換其他策略。例如根據用戶AccountID、ZipCode進行Hash,這樣就可以使得每個Shard中操作請求更均勻。
問題2:不丟失(At-Least Once)
張三拿著存款在櫃台A處理,櫃員A處理到一半去接了個電話,等回來後以為業務已經辦理好了,於是開始處理下一個用戶的請求,張三的存款請求因此被丟失。
雖然機器不會人為犯錯,在線時間和可靠性要比櫃員高。但難免也會遇到當機、或因負載高導致的處理中斷,因為這樣的場景丟失用戶的存款,這是萬萬不行的。
這種情況怎麼辦呢?
A可以在自己日記本上(非賬本)記錄一個項目:當前已處理到Shard哪個位置,隻有當張三的這個存款請求被完全確認後,櫃員A才能叫下一個。
帶來問題是什麼?可能會重複。比如A已經處理完張三請求(更新賬本),準備在日記本上記錄處理到哪個位置之時,突然被叫開了,當他回來後,發現張三請求沒有記錄下來,他會把張三請求再次處理一遍,這就會造成重複。
問題3:不重複(Exactly Once)
重複一定會帶來問題嗎?不一定。
在冪等情況下,重複雖然會有浪費,但對結果沒有影響。什麼叫冪等:重複消費不對結果產生影響的操作叫做冪等。例如用戶有一個操作 “查詢餘額”,該操作是一個隻讀操作,重複做不影響結果。對於非隻讀操作,例如注銷用戶這類操作,可以連續做兩次。
但現實生活中大部分操作不是冪等的,例如存款、取款等,重複進行計算會對結果帶來致命的影響。解決的方式是什麼呢?櫃員(A)需要把賬本完成 + 日記本標記Shard中處理完成作為一個事物合並操作,並記錄下來(CheckPoint)。
如果A暫時離開或永久離開,其他櫃員隻要使用相同的規範:記錄中已操作則處理下一個即可,如果沒有則重複做,過程中需要保證原子性。
CheckPoint可以將Shard 中的元素位置(或時間)作為Key,放入一個可以持久化的對象中。代表當前元素已經被處理完成。
業務挑戰
以上三個概念解釋完成後,原理並不複雜。但在現實世界中,規模的變化與不確定性會使得以上三個問題便得更複雜。例如:
- 遇到發工資日子,用戶數會大漲
- 櫃員(Clerk)畢竟不是機器人,他們需要休假,需要吃午飯
- 銀行經理為了整體服務體驗,需要加快櫃員,以什麼作為判斷標準?Shard中處理速度?
- 櫃員在交接過程中,能否非常容易地傳遞賬本與記錄?
現實中的一天
8點銀行開門
隻有一個Shard0,用戶請求全部排在Shard0下,櫃員A也正好可以處理
10點進入高峰期間
銀行經理決定把10點後Shard0分裂成2個新Shard(Shard1,Shard2),並且給了如下規定,姓名是[A-W]用戶到Shard1中排隊,姓名是[X, Y, Z] 到Shard 2 中排隊等待處理,為什麼這兩個Shard區間不均勻?因為用戶的姓氏本身就是不均勻的,通過這種映射方式可以保證櫃員處理的均衡。
10-12點請求消費狀態:
櫃員A處理2個Shard非常吃力,於是經理派出櫃員B、C出廠。因為隻有2個Shard,B開始接管A負責一個Shard,C處於閑置狀態。
中午12點人越來越多
銀行經理覺得Shard1下櫃員A壓力太大,因此從Shard1中分裂出(Shard3,Shard4)兩個新的Shard,Shard3由櫃員A處理、Shard4由櫃員C處理。在12點後原來排在Shard 1中的請求,分別到Shard3,Shard4中。
12點後請求消費狀態:
流量持續到下午4點後,開始逐漸減少
因此銀行經理讓櫃員A、B休息,讓C同事處理Shard2,Shard3,Shard4中的請求。並逐步將Shard2與Shard3合並成Shard5,最後將Shard5和Shard4合並成一個Shard,當處理完成Shard中所有請求後銀行關門。
現實中的日誌處理
上述過程可以抽象成日誌處理的經典場景,如果要解決銀行的業務需求,我們要提供彈性伸縮、並且靈活適配的日誌基礎框架,包括:
- 對Shard進行彈性伸縮,參考LogHub彈性伸縮(Merge/Split)
- 消費者上線與下線能夠對Shard自動適配,過程中數據不丟失,參考[LogHub Consumer Library-協同消費組自動負載均衡] (https://help.aliyun.com/document_detail/28998.html)
- 過程中支持保序,參考LogHub支持保序寫入和消費
- 過程中不重複(需要消費者配合)
- 觀察到消費進度,以便合理調配計算資源,參考通過控製台查看協同消費組進度
- 支持更多渠道日誌接入(對銀行而言開通網上銀行、手機銀行、支票等渠道,可以接入更多的用戶請求),參考LogHub多種數據接入方式
通過LogHub + LogHub Consumer Library 能夠幫助你解決日誌實時處理中的這些經典問題,隻需把精力放在業務邏輯上,而不用去擔心流量擴容、Failover等家常瑣事,是不是很爽?
另外,Storm、Spark Streaming已經通過Consumer Library實現了對應的接口,歡迎試用。有興趣的讀者可以參考下日誌服務的主頁,以及日誌處理圈子,裏麵有不少幹貨哦。
最後更新:2016-10-08 19:21:45
上一篇:
處理-使用訪問日誌統計__最佳實踐_日誌服務-阿裏雲
下一篇:
索引查詢-消息服務(MNS)日誌__最佳實踐_日誌服務-阿裏雲
新建集合__結構管理_DMS for MongoDB_用戶指南(NoSQL)_數據管理-阿裏雲
數據集管理__監控結果管理_用戶指南_業務實時監控服務 ARMS-阿裏雲
數據管理服務協議__產品常見問題_數據管理-阿裏雲
SSH 登錄時出現如下錯誤:Too many authentication failures for root__遠程登錄 (SSH)_Linux操作運維問題_雲服務器 ECS-阿裏雲
Zeppelin 使用說明__開源組件介紹_用戶指南_E-MapReduce-阿裏雲
查詢路由表列表__路由表相關接口_API 參考_雲服務器 ECS-阿裏雲
曆史發展__產品簡介_加密服務-阿裏雲
Logtail-配置__Getting-Started_日誌服務-阿裏雲
文檔更新記錄__API使用手冊_歸檔存儲-阿裏雲
SetListenerAccessControlStatus__Listener相關API_API 參考_負載均衡-阿裏雲
相關內容
常見錯誤說明__附錄_大數據計算服務-阿裏雲
發送短信接口__API使用手冊_短信服務-阿裏雲
接口文檔__Android_安全組件教程_移動安全-阿裏雲
運營商錯誤碼(聯通)__常見問題_短信服務-阿裏雲
設置短信模板__使用手冊_短信服務-阿裏雲
OSS 權限問題及排查__常見錯誤及排除_最佳實踐_對象存儲 OSS-阿裏雲
消息通知__操作指南_批量計算-阿裏雲
設備端快速接入(MQTT)__快速開始_阿裏雲物聯網套件-阿裏雲
查詢API調用流量數據__API管理相關接口_API_API 網關-阿裏雲
使用STS訪問__JavaScript-SDK_SDK 參考_對象存儲 OSS-阿裏雲