從最初的單機應用到現(xiàn)在的大型互聯(lián)網(wǎng)分布式系統(tǒng),數(shù)據(jù)源一直在業(yè)務系統(tǒng)中扮演著重要的角色,多樣的需求造就了Mysql、Memcached、Redis、Elasticsearch等這些耳熟能詳?shù)拇鎯M件,因各自的特點,在系統(tǒng)中承擔著不同的職能。因為數(shù)據(jù)量、訪問量等挑戰(zhàn),我們時常又面臨著各種維度的分庫分表,數(shù)據(jù)冗余復雜度。本文從京東到家提示音的需求出發(fā),探討多數(shù)據(jù)源的職責分工,數(shù)據(jù)異構同步實踐和問題總結,大致分為以下三個部分
提示音業(yè)務背景
履約系統(tǒng)的數(shù)據(jù)源職責分工
數(shù)據(jù)異構的實踐、問題和總結
提示音業(yè)務背景
訂單履約系統(tǒng)是電商系統(tǒng)的核心生產(chǎn)流程,對于京東到家來說也不例外,到家的履約系統(tǒng)涉及到用戶、商家、物流多端的交互。如下圖所示,從用戶提交訂單到服務履約系統(tǒng),大致經(jīng)歷了支付、下發(fā)商家、商家確認、訂單打印、揀貨、下發(fā)物流、配送、妥投等環(huán)節(jié),這是一個基本的即時零售履約流程。標藍的流程是到家和商家交互的功能點,比如:下發(fā)商家、訂單打印等環(huán)節(jié)。把訂單下發(fā)給商家時,首當其沖的環(huán)節(jié)是商家要確認這個訂單,并且開始履約流程。但是,在實際業(yè)務中,商家在有些情況往往會出現(xiàn)履約瓶頸,比如過分忙碌或閑暇的時間段,商家不會一直盯著管理系統(tǒng)等待新訂單的來臨。這時商家需要一個提示功能,即提示音需求。
提示音需求需要不斷的查詢底層存儲Es,并提示給商家有訂單到達了,需要商家開始履約流程,如果商家沒有響應。就不斷查詢,不斷提示。就是這樣的一個循環(huán)提醒的功能,在大促期間,訂單量級增大導致查詢量級也對應增大?;旧厦看未蟠俣紩袳S查到CPU飆高,甚至出現(xiàn)不可用的情況。為了保護履約系統(tǒng),臨時方案是做一個功能開關,在大促期間對提示音功能降級,不再查詢和提示商家,由商家主動查看管理系統(tǒng)??墒墙导壊⒉皇俏覀兿胍姆桨?。因為最終商家收不到提示。導致履約質量下降,于是提示音就面臨一個問題,即“存儲組件無法支撐提示音業(yè)務的查詢體量”。
底層數(shù)據(jù)源職責分工
要解決面臨的查詢量級問題,就必須首先分析一下底層的存儲方案。以下是對到家訂單履約系統(tǒng)底層存儲的一個整體概括,分職責進行介紹.
Redis
Redis在履約系統(tǒng)中主要承載的一個職責是worker跑批任務的存儲和查詢。因履約系統(tǒng)中大量運用了跑批任務來實現(xiàn)最終一致性設計,而Redis的Zset結構比較匹配這樣的需求,將時間作為分值,不斷的提供近期任務的查詢是Redis在履約系統(tǒng)中充當?shù)淖畲舐毮堋槭裁碦edis沒有承載過多的查詢職能呢?一般Redis是應用于緩存場景,得益于其高性能,多樣的數(shù)據(jù)結構特點。但是,在數(shù)據(jù)量和復雜的查詢條件上,沒有Es支持的好,關鍵點是業(yè)務系統(tǒng)查詢條件復雜度是比較高的,所以,Redis沒有承載過多的查詢職能
Mysql
Mysql在履約系統(tǒng)存儲中的職能是持久化存儲訂單數(shù)據(jù),主要還是使用其強大的事務機制,以保障我們的數(shù)據(jù)寫入正確性、可靠性。從履約流程上來看,將數(shù)據(jù)做冷熱分離,熱點數(shù)據(jù)是我們在履約中的訂單.(也就是未完成的訂單),而完成的訂單,由于其使用率較低,我們稱之為冷數(shù)據(jù)。這樣的一個拆分也就是上圖中對應的業(yè)務庫和歷史庫。業(yè)務庫是熱庫,而歷史庫則是冷庫。冷熱分離思想,使單庫單表數(shù)據(jù)量維持在千萬級別。從而避免了對應的分庫分表復雜度。
從部署架構上看,我們對業(yè)務庫進行了大量的主從分割。
biz slave是業(yè)務庫從庫,它也承載一些履約中的訂單查詢職能。
big data slave集群是大數(shù)據(jù)抽數(shù)據(jù)用做統(tǒng)計分析的職能。
delay slave設置延遲一定時間消費binlog是為了防止master被誤操作而兜底的。比如錯誤執(zhí)行了刪除db的命令,這樣的延遲消費機制就可以利用binlog進行兜底回滾。
Elasticsearch
Es在數(shù)據(jù)存儲中承擔了大量的查詢職責,這主要取決于它優(yōu)秀的查詢能力,并有天然分布式的特點。在數(shù)據(jù)量復雜度解決方案上,避免了mysql分庫分表的復雜度。這里我們一共有3個Es集群。其中HOT ES和FULL ES也是進行了冷熱分離,這樣對查詢流量進行拆分,保證生產(chǎn)履約流程的獨立性,從而保證履約系統(tǒng)的穩(wěn)定性。
第三套ES集群Remind Elastic Cluster則是為了解決上述提示音的問題。在部署提示音集群之前,所有的提示音查詢流量都是打到熱集群的。也正是這樣的訪問量請求,導致了熱集群時有發(fā)生CPU飆高,接口響應緩慢,卡頓業(yè)務線程,影響主流程生產(chǎn)。所以,我們對熱集群進行了進一步的拆分,即提示音單獨集群的方案。
數(shù)據(jù)寫入復雜度問題
當確定冗余一套提示音集群以后,面臨的問題就轉變?yōu)榱松蠄D的寫入復雜度問題,從圖上來看,我們在拆分這套集群之前,訂單中心每次操作訂單寫入。面臨的是三個數(shù)據(jù)源的寫入工作,現(xiàn)在提出第四套數(shù)據(jù)源 ES REMIND,如果仍然采用直接寫入的方式,維護難度過大,這對研發(fā)人員是非常不友好的。于是考慮用異構中間件的方式來去寫入ES REMIND的數(shù)據(jù)
異構中間件的優(yōu)勢是屏蔽了數(shù)據(jù)同步的復雜度,但是隨之而來的是數(shù)據(jù)寫入鏈路可靠性、及時性等問題。而且,數(shù)據(jù)傳輸本身一般都具有高可用的需求,之前,高可用在業(yè)務應用上,因為業(yè)務應用的集群方式本身是計算高可用的。但異構中間件則要在高可用、可靠性、及時性三個維度上滿足我們的要求,于是我們了進行如下調(diào)研。
特性\產(chǎn)品 | Canal | Maxwell | Databus | CloudCanal |
---|---|---|---|---|
社區(qū)活躍度 | 高 | 中 | 高 | 商業(yè)化產(chǎn)品 |
可用性 | 高 | 低 | 高 | 高 |
產(chǎn)品熟練度 | 高 | 低 | 低 | 高 |
首先,在常用的數(shù)據(jù)存儲支撐上沒有太大差別,常用的存儲組件,這些異構中間件都是支持的。所以,我們更加著眼于以上3個指標。
社區(qū)活躍度代表了后續(xù)的維護性以及開源產(chǎn)品問題的快速響應
可用性方面的需求是非常強烈的,數(shù)據(jù)傳輸是不能中斷的,提示音數(shù)據(jù)允許少量延遲,但不允許中斷
最終采用Canal的根本原因還是在學習成本和熟練度上。
Canal簡介和實踐
經(jīng)過對業(yè)務背景、底層數(shù)據(jù)存儲支持、異構中間件的調(diào)研,我們最終采用了Canal作為本次需求異構的方案。
Canal工作流程簡介
從職責拆分上,Canal主流程大致如上圖所示,同步數(shù)據(jù)的工作大致分為以下幾個步驟,Canal這種異步通信的設計要求你的系統(tǒng)必須具備可回溯、重試、冪等、延遲等特點,業(yè)務數(shù)據(jù)也必須有相應的容忍度。
Step1 Load&Store:Connection 從Zookeeper 獲取到當前消費的binlog filename和position信息。隨后將該信息附帶到dump協(xié)議里,Mysql Master接到dump請求,開始推送binlog數(shù)據(jù)。Binlog經(jīng)過Parser解析之后投遞到Sink,Sink則承載了過濾消息的作用,過濾掉沒有訂閱的binlog事件,最終把消息存儲到Store中。
Step2:Send&Ack:用任務worker的方式,不斷掃描Store,最終將Store中的數(shù)據(jù)發(fā)送到目的地,目的地可以是具體的存儲組件,也可以是mq產(chǎn)品。圖中,Kafka是我們的實踐方案所用,投遞消息完成之后將消息ACK給Store組件。
Step3:Update MetaInfo:這個時候數(shù)據(jù)雖然發(fā)送了。但是,我們的元信息binlog的filename和position仍然沒有更新,在這個操作上,Canal仍然采取了異步的方式去同步該信息,將最新的position同步到zookeeper上。
Canal的兩種HA
Deployer的HA是靠Zookeeper的臨時節(jié)點和重試機制實現(xiàn)的,一臺Deployer實例成功啟動后,就會在Zookeeper上創(chuàng)建對應的目錄節(jié)點。此時,另外一臺節(jié)點不斷的檢測目錄是否存在,當啟動中的主機故障,臨時目錄丟失,standby主機得以啟動,從而保證Deployer的高可用
Mysql的HA則是靠一個單獨的線程不斷的Detect來實現(xiàn)的。但是,Mysql的HA,只能用GTID的模式,這是因為mysql master和slave的binlogfile name position是不一致的。如果用master的binlog filename和position去slave發(fā)送dump協(xié)議,這會出現(xiàn)無法匹配的問題。但是GTID是全局有序的,這也就導致了Mysql的HA只在GTID模式下才可用。
部署實踐
有了上面對Canal的大致了解,就有了到家的提示音異構實踐,部署方式如上圖。我們部署了兩臺Deployer用于數(shù)據(jù)傳輸?shù)母呖捎?。同時把消息投遞到了kafka,利用adapter的集群部署進行批量消費,插入到提示音集群的Es中。在順序性保障上采用了訂單id hash的策略,保證在partition上是有序的。這樣也就保證了在訂單業(yè)務操作上是整體有序的。
在鏈路上采用kafka來傳輸,主要還是應對大促期間binlog數(shù)據(jù)量級的特點,保證插入到Es之前有緩沖buffer作用。這也是直連方式的弱點,直連方式在大數(shù)據(jù)量短時間寫入時,對目的地存儲組件有可能會造成瞬間的大量插入,從而損耗目的地存儲組件的資源,可能影響到業(yè)務使用。但是,長鏈路也有數(shù)據(jù)延遲的缺點,如果對數(shù)據(jù)時效要求比較高的業(yè)務。還是建議用直連方式來搭建對應的異構方案。具體采用直連還是mq的方式同步,需要根據(jù)實際情況具體分析。
Meta Manager使用Zookeeper來存儲,與Deployer的HA形成有效持久化配合。
實踐問題&總結
問題一:kafka不可用
如上圖,第一個比較有代表性的問題是kafka集群不可用,直接導致Es數(shù)據(jù)斷層,從而影響到用戶的履約體驗。首先,kafka集群所在的網(wǎng)絡環(huán)境和機器主機發(fā)生問題,Deployer的Store數(shù)據(jù)存滿,直接導致數(shù)據(jù)delay了8個小時。提示音雖然沒有提示,商家端也會有PC端的管理系統(tǒng)同步訂單,但是需要商家主動刷新才可以刷新出來新的訂單。所以,并不是所有的訂單都履約超時,這導致過了很久才發(fā)現(xiàn)這個問題。緊急把訪問切到之前的ES熱集群。之后,重新把kafka服務部署到可用狀態(tài),數(shù)據(jù)雖然慢慢的追上了,但是原來在kafka中沒有被adapter消費的一部分數(shù)據(jù)卻丟掉了,這主要還是因為貪圖了性能,設置了kafka落盤頻率問題。
丟數(shù)據(jù)在數(shù)據(jù)異構的需求中是不可容忍的事情,索性這次事故基本上鎖定了丟數(shù)據(jù)的原因。所以,我們將Zookeeper中存儲的Canal元信息jouralName和position設置到對應的事故之前的位置,將數(shù)據(jù)重新跑到ES中,至此問題解決。
問題總結之一:報警和監(jiān)控手段
在分布式系統(tǒng)的鏈路復雜度和數(shù)據(jù)量復雜度背景下,監(jiān)控手段和必要的報警機制是至關重要的,如果沒有發(fā)現(xiàn)問題更談不上解決問題。比如kafka不可用問題很久都沒有發(fā)現(xiàn)。引入了數(shù)據(jù)異構方案,但是卻沒有監(jiān)控手段。這相當于自己在身邊埋了一顆定時炸彈,真正發(fā)現(xiàn)的時候,可能已經(jīng)無法挽回對應的損失了。在問題解決之后,搭建了對應的監(jiān)控系統(tǒng)Promethos Grafana。并且,針對Promethos的Delay指標設置報警閾值,實時報警.
問題總結之二:數(shù)據(jù)異構的兜底方案
數(shù)據(jù)異構相比較業(yè)務系統(tǒng)來說,是一個需要非常謹慎的功能。畢竟數(shù)據(jù)是一切的根本。一般來說,如果沒有數(shù)據(jù)異構的實踐經(jīng)驗,不建議將該方案引入到生產(chǎn)的核心業(yè)務中。如果確實要引入數(shù)據(jù)異構方案,那必須考慮到所有可能的情況。錯誤情況多的話,勢必會影響到業(yè)務迭代和功能落地的效率。由此,得出結論,如果無法窮舉可能遇到的問題情況,那么,最起碼要預見到最壞的情況。并考慮該情況下,業(yè)務應該如何的快速降級到可用情況,以求最小損失。這樣才可以在之后的運行中,慢慢發(fā)現(xiàn),慢慢解決。這要比一次性構想所有錯誤情況容易落地的多。比如kafka機器故障或網(wǎng)絡故障情況,到家的做法是降級到了熱集群做臨時方案。想象一下,引入了數(shù)據(jù)異構組件,沒有降級方案。出現(xiàn)故障,數(shù)據(jù)斷層時所面臨的業(yè)務影響和修復問題的壓力是無比巨大的。
問題二:Deployer故障,自動HA
如上圖所示,第二個遇到的問題是Deployer機器發(fā)生故障,系統(tǒng)自動HA到備機,任務得以繼續(xù)消費。總起來說,問題二并沒有給業(yè)務帶來直接影響,但是,還是比較經(jīng)典的一個案例。這需要回歸到設計環(huán)節(jié)的討論上,Canal實踐初期,在成本視角,如下兩個問題有很大的代表性,當初還是經(jīng)過了一個比較有意義的討論:
出于成本考慮,僅部署一臺Deployer實例是否可以?
一臺機器部署兩個Deployer實例是否可以?
答案是不可以!單例部署,或在機器維度上的多例部署,都不能解決機器維度的故障,從而導致數(shù)據(jù)鏈路斷層問題。出于總結,回顧一下高可用的范圍:多機器、多機房、多地區(qū)、多國家。范圍越大,高可用自然越是穩(wěn)定。但是帶來的成本和數(shù)據(jù)傳輸要求也越高,一般都是根據(jù)業(yè)務量級和業(yè)務重要程度進行取舍。
總結
以上就是到家履約系統(tǒng)在數(shù)據(jù)異構方面的實踐,我們從業(yè)務背景出發(fā),分析了底層存儲以及面臨的寫入復雜度問題。最終實踐了Canal的數(shù)據(jù)異構,在實踐中,我們主要得出以下3個經(jīng)驗教訓,希望對大家有所幫助!
數(shù)據(jù)異構的鏈路、監(jiān)控、報警尤其重要,有必要在第一期引入,及時發(fā)現(xiàn)問題,及時解決。否則,帶來的損失將是非常巨大的。
如果無法窮舉所有可能的錯誤情況,有必要冗余一條寫入鏈路用來降級存儲,這樣可以及時的降級到可用的備用方案上
冗余機器+狀態(tài)監(jiān)測 = 高可用。單臺機器部署,不是高可用,不要為了節(jié)約成本選擇單臺部署多個實例。
年營收2萬億、凈利潤下滑至90億,大宗供應鏈五巨頭業(yè)績出爐!
1828 閱讀京東物流遼寧省京東幫服資源招商
1610 閱讀兩大物流國企成立合資公司,意欲何為?
1320 閱讀共探AI時代的供應鏈數(shù)智化發(fā)展之路!《數(shù)智化供應鏈白皮書》正式發(fā)布 ?
1279 閱讀物流企業(yè)銷售激勵背后的秘密
1085 閱讀破局與重生:傳統(tǒng)國際貨代如何通過數(shù)字化轉型實現(xiàn)戰(zhàn)略突圍
1132 閱讀深圳首發(fā)!順豐同城與肯德基推出無人車智能配送服務
1007 閱讀關稅大戰(zhàn)遇上全球供應鏈:蘋果公司深度研究與戰(zhàn)略推演
898 閱讀運滿滿江浙滬上線“即時單”業(yè)務,打造極速貨運新體驗
923 閱讀外賣戰(zhàn)OR即配戰(zhàn)?京東美團博弈,快遞受傷?
882 閱讀