信用算力基于 RocketMQ 实现金融级数据服务的实践
微服務(wù)架構(gòu)已成為了互聯(lián)網(wǎng)的熱門話題之一,而這也是互聯(lián)網(wǎng)技術(shù)發(fā)展的必然階段。然而,微服務(wù)概念的提出者 Martin Fowler 卻強(qiáng)調(diào):分布式調(diào)用的第一原則就是不要分布式。
縱觀微服務(wù)實(shí)施過程中的弊端,可以推斷出作者的意圖,就是希望系統(tǒng)架構(gòu)者能夠謹(jǐn)慎地對(duì)待分布式調(diào)用,這是分布式系統(tǒng)自身存在的缺陷所致。但無論是 RPC 框架,還是 REST 框架,都因?yàn)轳v留在不同進(jìn)程空間的分布式組件,而引入了額外的復(fù)雜度。因而可能對(duì)系統(tǒng)的效率、可靠性、可預(yù)測性等諸多方面帶來負(fù)面影響。
信用算力自2016年開始實(shí)施微服務(wù)改造,通過消息隊(duì)列(Message Queue),后文簡稱MQ,來規(guī)避微服務(wù)存在的缺陷,實(shí)現(xiàn)金融級(jí)數(shù)據(jù)服務(wù)。以下是一些使用場景和心得。
為什么需要 MQ
一、案例介紹
先來看一個(gè)當(dāng)前的真實(shí)業(yè)務(wù)場景。
對(duì)于通過信息流獲客的企業(yè)而言,當(dāng)用戶注冊時(shí),因業(yè)務(wù)需求會(huì)調(diào)用用戶服務(wù),然后執(zhí)行一系列操作,注冊 -> 初始化賬戶信息 -> 邀友獎(jiǎng)勵(lì)發(fā)放 -> 發(fā)放優(yōu)惠券 -> ... -> 信息流數(shù)據(jù)上報(bào)。
用戶服務(wù)的開發(fā)人員壓力非常大,因?yàn)樾枰{(diào)用非常多的服務(wù),業(yè)務(wù)耦合嚴(yán)重。如果當(dāng)時(shí)賬戶服務(wù)正在執(zhí)行發(fā)版操作,那么初始化賬戶動(dòng)作會(huì)失敗。然而平臺(tái)經(jīng)過不斷的迭代更新,后續(xù)又新增了一個(gè)簽到業(yè)務(wù),新注冊用戶默認(rèn)簽到一次。這就需要修改用戶服務(wù),增加調(diào)用簽到服務(wù)的接口。每當(dāng)遇到此種情況,開發(fā)用戶服務(wù)的同學(xué)就非常不爽了,為什么總是我?新增簽到業(yè)務(wù)和用戶服務(wù)又有什么關(guān)系?
為解決此類重度依賴的問題,我們在架構(gòu)層面引入了 MQ,用來規(guī)避微服務(wù)之間重度耦合調(diào)用的弊端。新架構(gòu)如下圖:
用戶完成注冊動(dòng)作后,只需要往 MQ 發(fā)送一個(gè)用戶注冊的通知消息,下游業(yè)務(wù)如需要依賴注冊相關(guān)的數(shù)據(jù),訂閱注冊消息的 topic 即可,從而實(shí)現(xiàn)了業(yè)務(wù)的解耦。
看完上述真實(shí)的案例后,大家可能產(chǎn)生疑惑,到底什么是 MQ,使用 MQ 又有什么好處?適合使用 MQ 的場景和不適合使用 MQ 的場景有哪些不同?
二、什么是 MQ?
簡單來說,MQ(MessageQueue)是一種跨進(jìn)程的通信機(jī)制,用于上下游傳遞消息。
適合使用 MQ 的場景有:
1、上游不關(guān)心下游執(zhí)行結(jié)果,例如上述案例中用戶注冊后,我們并不關(guān)心賬戶是否初始化,是否上報(bào)了信息流等;
2、異步返回執(zhí)行時(shí)間長:例如上述案例中,當(dāng)邀友獎(jiǎng)勵(lì)發(fā)放,需要經(jīng)歷很多風(fēng)控規(guī)則,執(zhí)行時(shí)間比較長,但是用戶并不關(guān)注獎(jiǎng)勵(lì)何時(shí)發(fā)放。
不適合使用MQ場景
調(diào)用方實(shí)時(shí)關(guān)注執(zhí)行結(jié)果,例如用戶發(fā)起注冊動(dòng)作后,需要立刻知道,注冊結(jié)果是成功還是失敗,這種需要實(shí)時(shí)知道最終執(zhí)行結(jié)果的場景,就不適合使用MQ。
三、使用MQ的好處:
1、解耦
2、可靠投遞
3、廣播
4、最終一致性
5、流量削峰
6、消息投遞保證
7、異步通信(支持同步)
8、提高系統(tǒng)吞吐、健壯性
MQ 的技術(shù)選型
目前業(yè)內(nèi)比較主流的 MQ 包括 RocketMQ、ActiveMQ、RabbitMQ、Kafka等,關(guān)于性能、存儲(chǔ)、社區(qū)活躍度等各方面的技術(shù)對(duì)比已經(jīng)很多,本文不再重復(fù)。
但我們發(fā)現(xiàn)通過簡單的選型對(duì)比,很難抉擇到底選擇哪款MQ產(chǎn)品。因?yàn)榻鹑谛袠I(yè)對(duì)于數(shù)據(jù)一致性以及服務(wù)可用性的要求非常高,所以任何關(guān)于技術(shù)的選項(xiàng)都顯得尤為重要。
經(jīng)調(diào)研,如微眾銀行、民生銀行、平安銀行等國內(nèi)知名的互聯(lián)網(wǎng)銀行和直銷銀行代表,都在使用 RocketMQ,且 RocketMQ 出生在阿里系,經(jīng)受過各種生產(chǎn)壓力的考驗(yàn),非常穩(wěn)定。并且,目前此項(xiàng)技術(shù)已經(jīng)捐增給 Apache 社區(qū),社區(qū)活躍度非常高。另外 RocketMQ 開發(fā)語言是Java,開發(fā)同學(xué)遇到解決不了的問題點(diǎn),或者不清楚的概念,可以直接 Debug 源碼。經(jīng)過多方面的比較,我們選擇 RocketMQ 作為規(guī)避微服務(wù)弊端的利器。
MQ 在微服務(wù)下的使用場景
MQ 是一種跨進(jìn)程的通信機(jī)制,用于上下游傳遞消息,目前信用算力將 RocketMQ 應(yīng)用于解耦、流量削峰、分布式事務(wù)的處理等幾個(gè)場景。
一、解耦
通常解耦的做法是生產(chǎn)者發(fā)送消息到 MQ,下游訂閱 MQ 的特定 topic,當(dāng)下游接收到消息后開始處理業(yè)務(wù)邏輯。
那么,消息發(fā)送方到底應(yīng)該是由誰來承擔(dān)?是服務(wù)提供者在處理完RPC請求后,根據(jù)業(yè)務(wù)需求開始發(fā)送消息嗎?但此刻開發(fā)人員就會(huì)抱怨為什么總是我?為什么處理完業(yè)務(wù)后需要發(fā)送 MQ?
為此,在解耦的過程中通過訂閱數(shù)據(jù)庫的 BinLog 日志,開發(fā)了一套 BinLog 日志解析模塊,專門解析日志,然后生成 JSON 字符串后發(fā)送消息到 MQ,下游訂閱 MQ 即可。流程如下:
目前所有需要依賴下游服務(wù)的業(yè)務(wù)線,其數(shù)據(jù)變動(dòng)都采用此方案。
方案優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
1、服務(wù)之間依賴完全解耦,任何基于注冊行為的業(yè)務(wù)變更,都無需依賴上游,只需訂閱MQ即可;
2、系統(tǒng)的穩(wěn)定性和吞吐量增加了,用戶注冊的響應(yīng)時(shí)間縮短了;
缺點(diǎn):
1、引入MQ后系統(tǒng)復(fù)雜性增加,維護(hù)成本增加;
2、從注冊開始到全部數(shù)據(jù)初始化結(jié)束的整體時(shí)間增加了;
二、流量削峰
每逢遇到會(huì)員日的時(shí)候,平臺(tái)會(huì)發(fā)送大量的會(huì)員福利活動(dòng)通知,以短信、站內(nèi)信、PUSH 消息的方式通知注冊用戶。所有的消息會(huì)在很短的時(shí)間全部推送到消息中心,同時(shí)正常的業(yè)務(wù)通知任然有大量業(yè)務(wù)消息推送到消息中心。為保障平臺(tái)的穩(wěn)定性和可靠性,在消息中心前置了多種 topic,如短信、推送、站內(nèi)提醒。消息中心接收到消息后會(huì)全部寫入不同 topic 的 MQ,多個(gè)消費(fèi)者來消費(fèi)并把信息推送給終端用戶。
三、分布式事務(wù)
用戶在平臺(tái)上支付他訂購某種業(yè)務(wù)的時(shí)候,需要涉及到支付服務(wù)、賬戶服務(wù)、優(yōu)惠券服務(wù)、積分服務(wù),在單體模式下這種業(yè)務(wù)非常容易實(shí)現(xiàn),通過事務(wù)即可完成,偽代碼如下:
然而,在微服務(wù)的情況下,原本通過簡單事務(wù)處理的卻變得非常復(fù)雜,若引入兩階段提交(2PC)或者補(bǔ)償事務(wù)(TCC)方案,則系統(tǒng)的復(fù)雜程度會(huì)增加。
信用算力的做法是通過本地事務(wù) + MQ 消息的方式來解決, 雖然 RocketMQ 也支持事務(wù)消息,但是其他主流 MQ 并沒有此項(xiàng)功能,所以綜合考慮采用如下方案:
- 消息上游:需要額外建一個(gè)tc_message表,并記錄消息發(fā)送狀態(tài)。消息表和業(yè)務(wù)數(shù)據(jù)在同一個(gè)數(shù)據(jù)庫里面,而且要在一個(gè)事務(wù)里提交。然后消息會(huì)經(jīng)過MQ發(fā)送到消息的消費(fèi)方。如果消息發(fā)送失敗,會(huì)進(jìn)行重試發(fā)送;
- 消息上游:開啟定時(shí)任務(wù)掃描tc_message表,如果超過設(shè)置的時(shí)間內(nèi)狀態(tài)沒有變更,會(huì)再次發(fā)送消息到MQ,如重試次數(shù)達(dá)到上限則發(fā)起告警操作;
- 消息下游:需要處理這個(gè)消息,并完成自己的業(yè)務(wù)邏輯。此時(shí)如果本地事務(wù)處理成功,表明已經(jīng)處理完成了,需要發(fā)起業(yè)務(wù)回調(diào)通知業(yè)務(wù)方;
方案優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
1、用最小的代價(jià)實(shí)現(xiàn)分布式事物,以達(dá)到數(shù)據(jù)最終一致性;
2、方案非常靈活,任何環(huán)節(jié)都可以人為控制;
缺點(diǎn):
1、復(fù)雜性增加了,業(yè)務(wù)操作的時(shí)候需要寫入 tc_message 表以及發(fā)送 MQ,同時(shí)還需要考慮狀態(tài)超時(shí)未變更的補(bǔ)發(fā)機(jī)制以及告警處理機(jī)制;
2、用戶看到的數(shù)據(jù),存在有短暫不一致的情況;
心得體會(huì)
使用 RocketMQ 3年多了,總體來說運(yùn)行的非常穩(wěn)定,基本上沒有發(fā)生過生產(chǎn)事故,下面說說這幾年使用下來的心得體會(huì):
1、一個(gè)應(yīng)用盡可能用一個(gè) Topic,消息子類型用 tags 來標(biāo)識(shí)。Topic 名稱和 Tags 名稱可以自行設(shè)置。Producer,Consumer都需要規(guī)范,要做到見名知意。發(fā)送消息時(shí)候必須攜帶 Tags,消費(fèi)方在訂閱消息時(shí),才可以利用 Tags 在 Broker 做消息過濾。
2、每條消息在業(yè)務(wù)層面有唯一標(biāo)識(shí)碼,方便在系統(tǒng)出現(xiàn)異常的情況,可以通過業(yè)務(wù)維度查詢。舉個(gè)栗子,當(dāng)用戶在平臺(tái)注冊成功后,會(huì)以 Topic 和 UserID 作為唯一標(biāo)識(shí)碼(topic_user_10011),服務(wù)器會(huì)為每個(gè)消息創(chuàng)建索引,該消息會(huì)持久化入庫,以防將來定位消息丟失等問題。下游收到消息后會(huì)以 Topic+Key 方式來記錄消費(fèi)行為,包括消息日期、當(dāng)前機(jī)器IP地址、處理結(jié)果等;也可以通過 Topic+Key 的方式來查詢這條消息內(nèi)容,包括消息被誰消費(fèi),以及這條 MQ 在每個(gè)環(huán)節(jié)的處理狀態(tài)。
3、消息發(fā)送成功或者失敗,都需要記錄 log 日志,且必須打印 sendresult、MsgID、唯一標(biāo)識(shí)碼。
4、由于上游會(huì)做消息重試機(jī)制,所以下游消息必須要做冪等處理。
5、需要封裝 MQ 的 API 在封裝后,API 需屏蔽底層 MQ 的特性,開發(fā)人員無需關(guān)注到底是用的哪個(gè) MQ 來支持本地分布式事物、MQ 消息自動(dòng)入庫、自動(dòng)打印日志,減少開發(fā)人員操作成本。
總的來說,MQ 是一個(gè)互聯(lián)網(wǎng)架構(gòu)中常見的解耦利器,在這3年中,信用算力在微服務(wù)中一直使用 MQ 來為金融客戶提供高質(zhì)量的數(shù)據(jù)服務(wù)。雖然 MQ 不是唯一方案,但是從目前階段來看,的確是一種非常不錯(cuò)的解決方案。
?
原文鏈接
本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。
總結(jié)
以上是生活随笔為你收集整理的信用算力基于 RocketMQ 实现金融级数据服务的实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阿里云Kubernetes服务上使用Te
- 下一篇: TableStore实战:DLA+SQL