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