中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

攜程實(shí)時(shí)用戶行為系統(tǒng)實(shí)踐

2018-10-22    來(lái)源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

攜程實(shí)時(shí)用戶行為服務(wù)作為基礎(chǔ)服務(wù),目前普遍應(yīng)用在多個(gè)場(chǎng)景中,比如猜你喜歡(攜程的推薦系統(tǒng)),動(dòng)態(tài)廣告,用戶畫像,瀏覽歷史等等。

以猜你喜歡為例,猜你喜歡為應(yīng)用內(nèi)用戶提供潛在選項(xiàng),提高成交效率。旅行是一項(xiàng)綜合性的需求,用戶往往需要不止一個(gè)產(chǎn)品。作為一站式的旅游服務(wù)平臺(tái),跨業(yè)務(wù)線的推薦,特別是實(shí)時(shí)推薦,能實(shí)際滿足用戶的需求,因此在上游提供打通各業(yè)務(wù)線之間的用戶行為數(shù)據(jù)有很大的必要性。

攜程原有的實(shí)時(shí)用戶行為系統(tǒng)存在一些問(wèn)題,包括:1)數(shù)據(jù)覆蓋不全;2)數(shù)據(jù)輸出沒有統(tǒng)一格式,對(duì)眾多使用方提高了接入成本;3)日志處理模塊是web service,比較難支持多種數(shù)據(jù)處理策略和實(shí)現(xiàn)方便擴(kuò)容應(yīng)對(duì)流量洪峰的需求等。

而近幾年旅游市場(chǎng)高速增長(zhǎng),數(shù)據(jù)量越來(lái)越大,并且會(huì)持續(xù)快速增長(zhǎng)。有越來(lái)越多的使用需求,對(duì)系統(tǒng)的實(shí)時(shí)性,穩(wěn)定性也提出了更高的要求?偟膩(lái)說(shuō),當(dāng)前需求對(duì)系統(tǒng)的實(shí)時(shí)性/可用性/性能/擴(kuò)展性方面都有很高的要求。

一、架構(gòu)

這樣的背景下,我們按照如下結(jié)構(gòu)重新設(shè)計(jì)了系統(tǒng):

圖1:實(shí)時(shí)用戶行為系統(tǒng)邏輯視圖 

新的架構(gòu)下,數(shù)據(jù)有兩種流向,分別是處理流和輸出流。

在處理流,行為日志會(huì)從客戶端(App/Online/H5)上傳到服務(wù)端的Collector Service。Collector Service將消息發(fā)送到分布式隊(duì)列。數(shù)據(jù)處理模塊由流計(jì)算框架完成,從分布式隊(duì)列讀出數(shù)據(jù),處理之后把數(shù)據(jù)寫入數(shù)據(jù)層,由分布式緩存和數(shù)據(jù)庫(kù)集群組成。

輸出流相對(duì)簡(jiǎn)單,web service的后臺(tái)會(huì)從數(shù)據(jù)層拉取數(shù)據(jù),并輸出給調(diào)用方,有的是內(nèi)部服務(wù)調(diào)用,比如推薦系統(tǒng),也有的是輸出到前臺(tái),比如瀏覽歷史。系統(tǒng)實(shí)現(xiàn)采用的是Java+Kafka+Storm+Redis+Mysql+Tomcat+Spring的技術(shù)棧。

  • Java :目前公司內(nèi)部Java化的氛圍比較濃厚,并且Java有比較成熟的大數(shù)據(jù)組件

  • Kafka/Storm :Kafka作為分布式消息隊(duì)列已經(jīng)在公司有比較成熟的應(yīng)用,流計(jì)算框架Storm也已經(jīng)落地,并且有比較好的運(yùn)維支持環(huán)境。

  • Redis : Redis的HA,SortedSet和過(guò)期等特性比較好地滿足了系統(tǒng)的需求。

  • MySQL: 作為基礎(chǔ)系統(tǒng),穩(wěn)定性和性能也是系統(tǒng)的兩大指標(biāo),對(duì)比nosql的主要選項(xiàng),比如hbase和elasticsearch,十億數(shù)據(jù)級(jí)別上mysql在這兩方面有更好的表現(xiàn),并且經(jīng)過(guò)設(shè)計(jì)能夠有不錯(cuò)的水平擴(kuò)展能力。

目前系統(tǒng)每天處理20億左右的數(shù)據(jù)量,數(shù)據(jù)從上線到可用的時(shí)間在300毫秒左右。查詢服務(wù)每天服務(wù)8000萬(wàn)左右的請(qǐng)求,平均延遲在6毫秒左右。下面從實(shí)時(shí)性/可用性/性能/部署幾個(gè)維度來(lái)說(shuō)明系統(tǒng)的設(shè)計(jì)。

二、實(shí)時(shí)性

作為一個(gè)實(shí)時(shí)系統(tǒng),實(shí)時(shí)性是首要指標(biāo)。線上系統(tǒng)面對(duì)著各種異常情況。例如如下幾種情況:

  1. 突發(fā)流量洪峰,怎么應(yīng)對(duì);

  2. 出現(xiàn)失敗數(shù)據(jù)或故障模塊,如何保證失敗數(shù)據(jù)重試并同時(shí)保證新數(shù)據(jù)的處理;

  3. 環(huán)境問(wèn)題或bug導(dǎo)致數(shù)據(jù)積壓,如何快速消解;

  4. 程序bug,舊數(shù)據(jù)需要重新處理,如何快速處理同時(shí)保證新數(shù)據(jù);

系統(tǒng)從設(shè)計(jì)之初就考慮了上述情況。

首先是用storm解決了突發(fā)流量洪峰的問(wèn)題。storm具有如下特性:

圖2:Storm特性

作為一個(gè)流計(jì)算框架,和早期大數(shù)據(jù)處理的批處理框架有明顯區(qū)別。批處理框架是執(zhí)行完一次任務(wù)就結(jié)束運(yùn)行,而流處理框架則持續(xù)運(yùn)行,理論上永不停止,并且處理粒度是消息級(jí)別,因此只要系統(tǒng)的計(jì)算能力足夠,就能保證每條消息都能第一時(shí)間被發(fā)現(xiàn)并處理。

對(duì)當(dāng)前系統(tǒng)來(lái)說(shuō),通過(guò)storm處理框架,消息能在進(jìn)入kafka之后毫秒級(jí)別被處理。此外,storm具有強(qiáng)大的scale out能力。只要通過(guò)后臺(tái)修改worker數(shù)量參數(shù),并重啟topology(storm的任務(wù)名稱),可以馬上擴(kuò)展計(jì)算能力,方便應(yīng)對(duì)突發(fā)的流量洪峰。

對(duì)消息的處理storm支持多種數(shù)據(jù)保證策略,at least once,at most once,exactly once。對(duì)實(shí)時(shí)用戶行為來(lái)說(shuō),首先是保證數(shù)據(jù)盡可能少丟失,另外要支持包括重試和降級(jí)的多種數(shù)據(jù)處理策略,并不能發(fā)揮exactly once的優(yōu)勢(shì),反而會(huì)因?yàn)槭聞?wù)支持降低性能,所以實(shí)時(shí)用戶行為系統(tǒng)采用的atleast once的策略。這種策略下消息可能會(huì)重發(fā),所以程序處理實(shí)現(xiàn)了冪等支持。

storm 的發(fā)布比較簡(jiǎn)單,上傳更新程序jar包并重啟任務(wù)即可完成一次發(fā)布,遺憾的是沒有多版本灰度發(fā)布的支持。

圖3:Storm架構(gòu)

在部分情況下數(shù)據(jù)處理需要重試,比如數(shù)據(jù)庫(kù)連接超時(shí),或者無(wú)法連接。連接超時(shí)可能馬上重試就能恢復(fù),但是無(wú)法連接一般需要更長(zhǎng)時(shí)間等待網(wǎng)絡(luò)或數(shù)據(jù)庫(kù)的恢復(fù),這種情況下處理程序不能一直等待,否則會(huì)造成數(shù)據(jù)延遲。實(shí)時(shí)用戶行為系統(tǒng)采用了雙隊(duì)列的設(shè)計(jì)來(lái)解決這個(gè)問(wèn)題。

圖4:雙隊(duì)列設(shè)計(jì)

生產(chǎn)者將行為紀(jì)錄寫入Queue1(主要保持?jǐn)?shù)據(jù)新鮮),Worker從Queue1消費(fèi)新鮮數(shù)據(jù)。如果發(fā)生上述異常數(shù)據(jù),則Worker將異常數(shù)據(jù)寫入Queue2(主要保持異常數(shù)據(jù))。

這樣Worker對(duì)Queue1的消費(fèi)進(jìn)度不會(huì)被異常數(shù)據(jù)影響,可以保持消費(fèi)新鮮數(shù)據(jù)。RetryWorker會(huì)監(jiān)聽Queue2,消費(fèi)異常數(shù)據(jù),如果處理還沒有成功,則按照一定的策略(如下圖)等待或者重新將異常數(shù)據(jù)寫入Queue2。

圖5:補(bǔ)償重試策略

另外,數(shù)據(jù)發(fā)生積壓的情況下,可以調(diào)整Worker的消費(fèi)游標(biāo),從最新的數(shù)據(jù)重新開始消費(fèi),保證最新數(shù)據(jù)得到處理。中間未經(jīng)處理的一段數(shù)據(jù)則啟動(dòng)backupWorker,指定起止游標(biāo),在消費(fèi)完指定區(qū)間的數(shù)據(jù)之后,backupWorker會(huì)自動(dòng)停止。(如下圖)

圖6:積壓數(shù)據(jù)消解

三、可用性

作為基礎(chǔ)服務(wù),對(duì)可用性的要求比一般的服務(wù)要高得多,因?yàn)橄掠我蕾嚨姆⻊?wù)多,一旦出現(xiàn)故障,有可能會(huì)引起級(jí)聯(lián)反應(yīng)影響大量業(yè)務(wù)。項(xiàng)目從設(shè)計(jì)上對(duì)以下問(wèn)題做了處理,保障系統(tǒng)的可用性:

  1. 系統(tǒng)是否有單點(diǎn)?

  2. DB 擴(kuò)容/維護(hù)/故障怎么辦?

  3. Redis 維護(hù)/升級(jí)補(bǔ)丁怎么辦?

  4. 服務(wù)萬(wàn)一掛了如何快速恢復(fù)?如何盡量不影響下游應(yīng)用?

首先是系統(tǒng)層面上做了全棧集群化。kafka和storm本身比較成熟地支持集群化運(yùn)維;web服務(wù)支持了無(wú)狀態(tài)處理并且通過(guò)負(fù)載均衡實(shí)現(xiàn)集群化;Redis和DB方面攜程已經(jīng)支持主備部署,使用過(guò)程中如果主機(jī)發(fā)生故障,備機(jī)會(huì)自動(dòng)接管服務(wù);通過(guò)全棧集群化保障系統(tǒng)沒有單點(diǎn)。

另外系統(tǒng)在部分模塊不可用時(shí)通過(guò)降級(jí)處理保障整個(gè)系統(tǒng)的可用性。先看看正常數(shù)據(jù)處理流程:(如下圖)

圖7:正常數(shù)據(jù)流程

在系統(tǒng)正常狀態(tài)下,storm會(huì)從kafka中讀取數(shù)據(jù),分別寫入到redis和mysql中。服務(wù)從redis拉。ㄈ〔坏綍r(shí)從db補(bǔ)償),輸出給客戶端。DB降級(jí)的情況下,數(shù)據(jù)流程也隨之改變(如下圖)

圖8:系統(tǒng)降級(jí)-DB

當(dāng)mysql不可用時(shí),通過(guò)打開db降級(jí)開關(guān),storm會(huì)正常寫入redis,但不再往mysql寫入數(shù)據(jù)。數(shù)據(jù)進(jìn)入reids就可以被查詢服務(wù)使用,提供給客戶端。另外storm會(huì)把數(shù)據(jù)寫入一份到kafka的retry隊(duì)列,在mysql正常服務(wù)之后,通過(guò)關(guān)閉db降級(jí)開關(guān),storm會(huì)消費(fèi)retry隊(duì)列中的數(shù)據(jù),從而把數(shù)據(jù)寫入到mysql中。redis和mysql的數(shù)據(jù)在降級(jí)期間會(huì)有不一致,但系統(tǒng)恢復(fù)正常之后會(huì)通過(guò)retry保證數(shù)據(jù)最終的一致性。redis的降級(jí)處理也類似(如下圖)

圖9:系統(tǒng)降級(jí)-Redis

唯一有點(diǎn)不同的是redis的服務(wù)能力要遠(yuǎn)超過(guò)mysql。所以在redis降級(jí)時(shí)系統(tǒng)的吞吐能力是下降的。這時(shí)我們會(huì)監(jiān)控db壓力,如果發(fā)現(xiàn)mysql壓力較大,會(huì)暫時(shí)停止數(shù)據(jù)的寫入,降低mysql的壓力,從而保證查詢服務(wù)的穩(wěn)定。

為了降低故障情況下對(duì)下游的影響,查詢服務(wù)通過(guò)Netflix的Hystrix組件支持了熔斷模式(如下圖)。

圖10:Circuit Breaker Pattern

在該模式下,一旦服務(wù)失敗請(qǐng)求在給定時(shí)間內(nèi)超過(guò)一個(gè)閾值,就會(huì)打開熔斷開關(guān)。在開關(guān)開啟情況下,服務(wù)對(duì)后續(xù)請(qǐng)求直接返回失敗響應(yīng),不會(huì)再讓請(qǐng)求經(jīng)過(guò)業(yè)務(wù)模塊處理,從而避免服務(wù)器進(jìn)一步增加壓力引起雪崩,也不會(huì)因?yàn)轫憫?yīng)時(shí)間延長(zhǎng)拖累調(diào)用方。

開關(guān)打開之后會(huì)開始計(jì)時(shí),timeout后會(huì)進(jìn)入Half Open的狀態(tài),在該狀態(tài)下會(huì)允許一個(gè)請(qǐng)求通過(guò),進(jìn)入業(yè)務(wù)處理模塊,如果能正常返回則關(guān)閉開關(guān),否則繼續(xù)保持開關(guān)打開直到下次timeout。這樣業(yè)務(wù)恢復(fù)之后就能正常服務(wù)請(qǐng)求。

另外,為了防止單個(gè)調(diào)用方的非法調(diào)用對(duì)服務(wù)的影響,服務(wù)也支持了多個(gè)維度限流,包括調(diào)用方AppId/ip限流和服務(wù)限流,接口限流等。

四、性能&擴(kuò)展

由于在線旅游行業(yè)近幾年的高速增長(zhǎng),攜程作為行業(yè)領(lǐng)頭羊也蓬勃發(fā)展,因此訪問(wèn)量和數(shù)據(jù)量也大幅提升。公司對(duì)業(yè)務(wù)的要求是可以支撐10倍容量擴(kuò)展,擴(kuò)展最難的部分在數(shù)據(jù)層,因?yàn)樯婕暗酱媪繑?shù)據(jù)的遷移。

實(shí)時(shí)用戶行為系統(tǒng)的數(shù)據(jù)層包括Redis和Mysql,Redis因?yàn)閷?shí)現(xiàn)了一致性哈希,擴(kuò)容時(shí)只要加機(jī)器,并對(duì)分配到新分區(qū)的數(shù)據(jù)作讀補(bǔ)償就可以。

Mysql 方面,我們也做了水平切分作為擴(kuò)展的準(zhǔn)備,分片數(shù)量的選擇考慮為2的n次方,這樣做在擴(kuò)容時(shí)有明顯的好處。因?yàn)閿y程的mysql數(shù)據(jù)庫(kù)現(xiàn)在普遍采用的是一主一備的方式,在擴(kuò)容時(shí)可以直接把備機(jī)拉平成第二臺(tái)(組)主機(jī)。假設(shè)原來(lái)分了2個(gè)庫(kù),d0和d1,都放在服務(wù)器s0上,s0同時(shí)有備機(jī)s1。擴(kuò)容只需要如下幾步:

  1. 確保s0 -> s1同步順利,沒有明顯延遲

  2. s0 暫時(shí)關(guān)閉讀寫權(quán)限

  3. 確認(rèn)s1已經(jīng)完全同步s0更新

  4. s1 開放讀寫權(quán)限

  5. d1 的dns由s0切換到s1

  6. s0 開放讀寫權(quán)限

遷移過(guò)程利用mysql的復(fù)制分發(fā)特性,避免了繁瑣易錯(cuò)的人工同步過(guò)程,大大降低了遷移成本和時(shí)間。整個(gè)操作過(guò)程可以在幾分鐘完成,結(jié)合DB降級(jí)的功能,只有在dns切換的幾秒鐘時(shí)間會(huì)產(chǎn)生異常。

整個(gè)過(guò)程比較簡(jiǎn)單方便,降低了運(yùn)維負(fù)擔(dān),一定程度也能降低過(guò)多操作造成類似gitlab式悲劇的可能性。

五、部署

前文提到storm部署是比較方便的,只要上傳重啟就可以完成部署。部署之后由于程序重新啟動(dòng)上下文丟失,可以通過(guò)Kafka記錄的游標(biāo)找到之前處理位置,恢復(fù)處理。

另外有部分情況下程序可能需要多版本運(yùn)行,比如行為紀(jì)錄暫時(shí)有多個(gè)版本,這種情況下我們會(huì)新增一個(gè)backupJob,在backupJob中運(yùn)行歷史版本。

 

 

來(lái)自:http://mp.weixin.qq.com/s/kIwTnNFsNWMcEpEIRZfQlw

 

標(biāo)簽: dns Mysql 大數(shù)據(jù) 大數(shù)據(jù)處理 服務(wù)器 權(quán)限 數(shù)據(jù)庫(kù) 網(wǎng)絡(luò)

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:說(shuō)說(shuō)MQ之RocketMQ(二)

下一篇:服務(wù)端I/O性能大比拼:Node、PHP、Java、Go