本文根據(jù)羅代均老師在〖deeplus直播第261期〗線上分享演講內(nèi)容整理而成(文末有獲取本期回放的方式,不要錯(cuò)過)
羅代均
OPPO安第斯系統(tǒng)資深工程師
- 負(fù)責(zé)OPPO后端體系建設(shè),包括API網(wǎng)卡、用戶流量調(diào)度、微服框架、調(diào)用鏈路跟蹤等,經(jīng)歷了OPPO用戶從千萬級(jí)到億級(jí)的增長(zhǎng)歷程。
一、多活業(yè)務(wù)架構(gòu)
1、OPPO多活架構(gòu)原則
第一,主線多活。
多活成本比較高的,雙活是兩倍,三活可能成本會(huì)低一些,但三活的難度更大。因此沒有辦法對(duì)所有業(yè)務(wù)進(jìn)行多活,只能對(duì)主線做多活。
第二,是保障多數(shù)用戶。
舉個(gè)例子,系統(tǒng)有個(gè)充值的功能,充值功能本身是強(qiáng)一致的,完全不能允許任何的延遲或者是副本的讀。
但是多活切換之后,只有少數(shù)用戶在切換的前幾分鐘有充值的,這部分用戶余額可能沒有通過過去,只需要對(duì)這部分用戶進(jìn)行服務(wù)降級(jí),其他絕大多數(shù)用戶是可以使用完整的服務(wù)的。
第三,數(shù)據(jù)分類,應(yīng)用不同的CAP模型。
CAP定理不是針對(duì)的業(yè)務(wù)功能,比如說賬號(hào)、支付、登錄,CAP定理是對(duì)數(shù)據(jù)的要求。一個(gè)功能可能用到多個(gè)數(shù)據(jù),數(shù)據(jù)本身的一致性、可用性、延遲的容忍是不一樣的。
所以需要對(duì)業(yè)務(wù)功能用到的數(shù)據(jù)進(jìn)行分類,比如余額數(shù)據(jù)、流水?dāng)?shù)據(jù)、日志數(shù)據(jù)、個(gè)人資料數(shù)據(jù)……我們對(duì)每個(gè)數(shù)據(jù)進(jìn)行一致性、可用性的需求分析,一致性要求很強(qiáng),這個(gè)數(shù)據(jù)就選用同城高可用的數(shù)據(jù)庫服務(wù)。這個(gè)數(shù)據(jù)一致性要求不高、允許延遲,就可以選擇異地高可用的數(shù)據(jù)庫服務(wù)。
所以這個(gè)業(yè)務(wù)來說不是整體使用一個(gè)CAP模型,在業(yè)務(wù)內(nèi)部,因?yàn)椴煌臄?shù)據(jù)分類,使用了不同的模型,因此業(yè)務(wù)有時(shí)候存在部分降級(jí)的情況。
第四,平臺(tái)業(yè)務(wù)SDK化。
OPPO的業(yè)務(wù)比較多,比如瀏覽器、軟件商店、廣告務(wù)、音樂、視頻等非常多的業(yè)務(wù),這些業(yè)務(wù)都用了平臺(tái)化的服務(wù),比如評(píng)論系統(tǒng)、消息系統(tǒng),還有賬號(hào)鑒權(quán)的系統(tǒng)等等。
OPPO公司的機(jī)房比較多,主要的就有好幾個(gè)機(jī)房,我們的上層業(yè)務(wù)是分布在不同的機(jī)房里面去,這對(duì)平臺(tái)業(yè)務(wù)來說就比較麻煩,上層業(yè)務(wù)可能只需要做雙活就行了,而平臺(tái)業(yè)務(wù)可能就要做七活、甚至八活,而且七、八個(gè)機(jī)房都要有讀和寫,難度就非常大。
為解決這個(gè)問題,我們提出平臺(tái)業(yè)務(wù)進(jìn)行SDK化思路,把這種平臺(tái)型業(yè)務(wù),拆分成獨(dú)立的域名,從SDK開始拆分,這樣我們平臺(tái)業(yè)務(wù)只需要單獨(dú)做多活就行了,不需要在每個(gè)機(jī)房都提供讀寫的能力。
第五,數(shù)據(jù)最終一致。
第六,我們的記錄日志、流水,避免修改、計(jì)數(shù)操作。
2、同城多活業(yè)務(wù)架構(gòu)
上圖是典型同城多活的業(yè)務(wù)架構(gòu),應(yīng)用層是完全無狀態(tài)的,隨便打流量。四層采用DPDK技術(shù)開發(fā),七層包括Nginx和API網(wǎng)關(guān)兩個(gè)組件,Nginx只用來做SSL卸載、WAF防火墻,其他功能都是API網(wǎng)關(guān)來提供。
數(shù)據(jù)層以主備為主,寫流量只會(huì)寫到Master節(jié)點(diǎn),但是讀的流量可以訪問slave節(jié)點(diǎn),但是也不一定,看業(yè)務(wù)本身數(shù)據(jù)一致性要求,如果要求非常強(qiáng)一致的,我們的讀也只會(huì)指向Master節(jié)點(diǎn)。
需要注意,我們把Nginx和API網(wǎng)關(guān)都放到同一個(gè)容器中,兩只之間采用進(jìn)程間通信。這樣的好處是,我們擴(kuò)容的時(shí)候,我們可以將整個(gè)七層同步去擴(kuò)容,而不會(huì)存在某一層組件容量不足的情況。
另外就是注冊(cè)中心,我們沒有使用 k8s本身的一個(gè)注冊(cè)功能,而是自己基于數(shù)據(jù)庫,實(shí)現(xiàn)了AP模型的注冊(cè)中心,保證注冊(cè)中心的跨機(jī)房高可用。同時(shí)注冊(cè)中心兼容Consul協(xié)議,從而更好地融入開源生態(tài)。多個(gè)k8s集群的實(shí)例,都會(huì)注冊(cè)到統(tǒng)一的注冊(cè)中心里面去。這個(gè)注冊(cè)的動(dòng)作,是由發(fā)布平臺(tái)完成的,好處是應(yīng)用發(fā)布的時(shí)候,發(fā)布平臺(tái)可以提前摘掉流量,避免重啟影響服務(wù)的成功率。
3、異地多活業(yè)務(wù)架構(gòu)——單元化
異地多活,比較典型的架構(gòu)是單元化,就是將用戶進(jìn)行分片,將不同的用戶分片放到不同的機(jī)房里面去,這樣可以做到一個(gè)完全的擴(kuò)展,隨著用戶規(guī)模的增加,我們可以很容易去擴(kuò)展機(jī)房的數(shù)量,這些都可以持續(xù)的去增加的,包括每個(gè)機(jī)房的容量也可能不一樣。比如有的機(jī)房大,有的機(jī)房小,我們可以調(diào)整每個(gè)機(jī)房存放的單元數(shù)量。
這里確實(shí)實(shí)現(xiàn)了多活,每個(gè)機(jī)房都有流量,每個(gè)機(jī)房也是讀寫,是完全的多活,但是單元高可用的問題如何解決,單元的歸屬機(jī)房故障了,如果把這個(gè)單元轉(zhuǎn)移另一個(gè)機(jī)房繼續(xù)提供服務(wù)。
4、異地雙活業(yè)務(wù)架構(gòu)
上圖是我們使用較多的異地雙活架構(gòu),首先我們將用戶按照地域維度進(jìn)行了一個(gè)單元?jiǎng)澐郑热缯f按照地域?qū)⒂脩魟澐譃槠邆€(gè)大區(qū)單元。
注意這個(gè)單元?jiǎng)澐质怯脩羰状卧L問服務(wù)的時(shí)候進(jìn)行的,然后客戶端就保存了單元號(hào),就不會(huì)產(chǎn)生變化了,所以用戶出差,換到因?yàn)榱硗庖粋€(gè)地域里面去,它所屬的單元號(hào)我們是不會(huì)變化的,還是訪問單元?dú)w屬的機(jī)房,這個(gè)時(shí)候可能就不是訪問最優(yōu)的機(jī)房。
這樣的好處是,當(dāng)一個(gè)用戶移動(dòng)的時(shí)候,數(shù)據(jù)訪問就不會(huì)在兩個(gè)機(jī)房之間跳來跳去,避免雙向同步的數(shù)據(jù)沖突問題,很容易實(shí)施。
數(shù)據(jù)層在兩個(gè)機(jī)房,都是完全全量的,兩個(gè)機(jī)房間數(shù)據(jù)是做雙向同步,沒有誰是主誰是從的區(qū)分,是完全對(duì)等的架構(gòu)。
用戶流量調(diào)度按單元進(jìn)行,這樣可以保證一個(gè)用戶,他只會(huì)訪問其中一個(gè)機(jī)房,不會(huì)在南北兩個(gè)機(jī)房之間跳來跳去,就算是用戶出差也是如此,按照首次訪問服務(wù)時(shí)的地域來劃分的單元。只要我們的調(diào)度規(guī)則沒有變更的情況下,一個(gè)用戶他永遠(yuǎn)只會(huì)在其中一個(gè)機(jī)房讀寫,這樣的好處就是,第一個(gè)可以避免我們的同步的沖突,第二個(gè)好處就是容忍了數(shù)據(jù)延遲的情況,比如說一個(gè)用戶他永遠(yuǎn)是看到北方機(jī)房,南北之間數(shù)據(jù)同步的延遲日常情況下其實(shí)是感知不到的。
這個(gè)架構(gòu)是非常簡(jiǎn)單,只需要在客戶端網(wǎng)絡(luò)庫里面做一些封裝,對(duì)用戶進(jìn)行單元?jiǎng)澐?,按單元進(jìn)行流量調(diào)度就可以了,雙向同步比較好實(shí)施,延遲、沖突,這些問題都可以避免。
除了地域之外,也可以按照賬號(hào)或者設(shè)備來劃分單元。按賬號(hào)或者設(shè)備劃分單元的好處是,如果按照地域劃分單元,在用戶刪除手機(jī)App這種情況下,APP里面保存的單元號(hào)就沒有了,下次訪問服務(wù)的時(shí)候就需要重新分配單元號(hào),因?yàn)榈赜蚩赡芎椭安煌?,就可能分配到不同的單元?hào),按賬號(hào)或者設(shè)備劃分就沒有這個(gè)問題,重新分配還是原來的單元號(hào)。
前面說到,南北機(jī)房的數(shù)據(jù)層都是全量的,一般情況下,按地域的劃分單元的模式,就算重新分配了單元號(hào),也不影響數(shù)據(jù)的讀寫訪問。
5、異地雙活——評(píng)論系統(tǒng)案例
上圖是平臺(tái)型業(yè)務(wù)-評(píng)論系統(tǒng)異地生活的案例,評(píng)論系統(tǒng)從SDK開始,就進(jìn)行了域名拆分,避免了在業(yè)務(wù)域名所在機(jī)房?jī)?nèi)部去做跨機(jī)房的評(píng)論服務(wù)調(diào)用,影響服務(wù)的可用性和性能。
如上圖所示,我們只對(duì)MySQL原始數(shù)據(jù)層做了南北雙機(jī)房同步,第二層的評(píng)論元數(shù)據(jù)表,還有第三層的一個(gè)Cache,這兩層實(shí)際上沒做同步的。兩個(gè)機(jī)房分別基于MySQL數(shù)據(jù)獨(dú)自去重建第二層的元數(shù)據(jù)表,第三層的Cache,以及重建其他的數(shù)據(jù)源。
這樣好處就是,我們只有一個(gè)數(shù)據(jù)源做了南北機(jī)房的同步,就可以避免雙數(shù)據(jù)源同步的時(shí)候,兩個(gè)數(shù)據(jù)源之間會(huì)存在同步的進(jìn)度不一致,從而兩個(gè)數(shù)據(jù)源之間的依賴關(guān)系出現(xiàn)問題。
舉個(gè)例子,我們上面的評(píng)論表、點(diǎn)贊表這一層,最上面這一層做了同步以后,我們中間第二層如果也做了同步,然后第二層同步以后,兩個(gè)數(shù)據(jù)可能存在差異,比如說第一層同步快一點(diǎn),第二層同步得慢一點(diǎn),同樣是南方的用戶,他們看到這個(gè)數(shù)據(jù)之間的存在不匹配的問題。
因?yàn)橛脩袅髁空{(diào)度是按單元進(jìn)行的,兩個(gè)機(jī)房的數(shù)據(jù)雖然有差異,有延遲,但是用戶感知不到的。一個(gè)用戶要么看到南方機(jī)房,要么看到北方機(jī)房,我們?cè)u(píng)論數(shù)量?jī)蓚€(gè)機(jī)房有差異,點(diǎn)贊數(shù)量有差異,回復(fù)數(shù)都有差異,但是無所謂,用戶是感知不到差異的。需要注意的一點(diǎn),就是當(dāng)多活切換的時(shí)候,用戶能感知到一個(gè)差異,但日常情況下用戶感知不到這個(gè)差異。
6、異地N活業(yè)務(wù)架構(gòu)
上圖是比較復(fù)雜異地N活業(yè)務(wù)架構(gòu)。它基本的思路就是對(duì)用戶進(jìn)行兩級(jí)的劃分。第一級(jí)按照設(shè)備和賬號(hào)劃分單元,其中單元里面既有登錄的用戶,也有未登錄的用戶。
在第二級(jí)劃分的單元內(nèi)部,我們?cè)賾?yīng)用異地雙活的模式,或者是同城多活的模式,比如說左邊單元1,按照地域做第二級(jí)的劃分,把它劃分成南北兩個(gè)副本,既然是副本,肯定數(shù)據(jù)是全量的,是異地雙活模式,兩個(gè)副本數(shù)據(jù)做雙向同步,這種模式適用非強(qiáng)一致的業(yè)務(wù)。
那么強(qiáng)一致的業(yè)務(wù)怎么辦呢?比如右邊的單元4,跨同城的兩個(gè)機(jī)房,單元內(nèi)部采用同城多活的模式,就是共享跨機(jī)房高可用的數(shù)據(jù)層,是主備的的。這種模式適合強(qiáng)一致的業(yè)務(wù)。
前面說了單元內(nèi)部主要兩種模式,第一種是異地雙活,雙向同步,主主模式,讀寫在本機(jī)房,然后做雙向同步;第二種是同城多活,主備的模式,跨機(jī)房共享主備切換的數(shù)據(jù)層。除此之外,單元內(nèi)部還可以選擇主從,冷備等模式。
7、服務(wù)部署
上圖是服務(wù)部署架構(gòu)。服務(wù)部署分為幾大部分。
第一部分是中心域。
中心域主要是部署一些運(yùn)營(yíng)管理后臺(tái),還有一些爬蟲,還有一些非常長(zhǎng)尾的應(yīng)用,但這些業(yè)務(wù)可能不太重要,也不需要做一個(gè)多活。中心域的讀寫都是在中心機(jī)房,然后把數(shù)據(jù)單向同步到其他單元機(jī)房。
第二部分是全局域。
全局域主要存放非單元分片維度的數(shù)據(jù),比如評(píng)論、消息等。這些數(shù)據(jù)不能按統(tǒng)一維度進(jìn)行拆分,需要全量的訪問,放到全局域的數(shù)據(jù)都是全量的。
第三部分是單元域。
存放按單元拆分的數(shù)據(jù),比如用戶訂單、收藏、下載記錄等。
8、服務(wù)路由
用戶會(huì)先請(qǐng)求到API網(wǎng)關(guān),API網(wǎng)關(guān)根據(jù)請(qǐng)求的單元號(hào)參數(shù),判斷是是否訪問錯(cuò)了機(jī)房,如果訪問錯(cuò)了,就做重定向,或者跨機(jī)房轉(zhuǎn)發(fā),用戶自己選擇的其中一種模式。轉(zhuǎn)發(fā)的模式比較依賴于兩個(gè)機(jī)房之間的專線的帶寬和穩(wěn)定性,重定向模式機(jī)房之間的帶寬要求會(huì)低一些,客戶端重新發(fā)起請(qǐng)求,這兩個(gè)機(jī)房之間的網(wǎng)絡(luò)專線要求低一些。
前面說到用戶首次請(qǐng)求的時(shí)候,會(huì)給客戶端分配一個(gè)單元號(hào),這個(gè)單元號(hào)將會(huì)存儲(chǔ)起來,以后每次業(yè)務(wù)請(qǐng)求都會(huì)帶上這個(gè)單元號(hào)。
請(qǐng)求到了單元內(nèi)部,單元號(hào)會(huì)做一個(gè)全鏈路的傳遞,全鏈路傳遞是通過調(diào)用鏈來實(shí)現(xiàn)的,調(diào)用鏈可以把一些參數(shù)做全鏈路的傳遞。應(yīng)用實(shí)例打上了單元號(hào)的標(biāo)簽,微服務(wù)調(diào)用方通過單元號(hào)對(duì)實(shí)例進(jìn)行篩選,防止請(qǐng)求打到其他單元。
數(shù)據(jù)訪問層要做一個(gè)兜底的操作,可能由于服務(wù)路由還是其他的一些原因,不小心訪問錯(cuò)了單元,這個(gè)數(shù)據(jù)層有可能訪問錯(cuò),所以數(shù)據(jù)訪問層要做一個(gè)兜底,根據(jù)傳過來單元號(hào),做拒絕或者轉(zhuǎn)發(fā)。
9、用單元化解決業(yè)務(wù)擴(kuò)展性問題
單元化不只是可以用來解決多活的問題,也可以用來解決業(yè)務(wù)擴(kuò)展性問題。在一個(gè)機(jī)房?jī)?nèi)部,如果服務(wù)1000萬用戶,他可能需要10個(gè)數(shù)據(jù)庫,服務(wù)1億個(gè)用戶,需要100個(gè)數(shù)據(jù)庫,如果100個(gè)數(shù)據(jù)庫讓每個(gè)應(yīng)用實(shí)例都連上的話,連接數(shù)就太多了。
可以在一個(gè)機(jī)房?jī)?nèi)部也拆分多個(gè)單元,每個(gè)單元保證1000萬、2000萬左右的用戶,隨著用戶的增長(zhǎng),我們?cè)賹卧獢?shù)量進(jìn)行增加就行了,這樣就可以保證每一個(gè)單元內(nèi)部的服務(wù)規(guī)模受控。
二、多活數(shù)據(jù)同步
1、MySQL同城多活
上圖是MySQL同城多活架構(gòu),MySQL對(duì)外看上去是一個(gè)集群,只有一個(gè)IP。我們需要解決的問題是:怎么讓跨機(jī)房的集群看到的是同一個(gè)IP?這里就用到了Anycast技術(shù),IP的作用可以理解為域名,我們把一個(gè) VIP用Anycast技術(shù),將它路由到兩個(gè)機(jī)房,或者是三個(gè)機(jī)房。我們是路由到三個(gè)機(jī)房,然后就到了機(jī)房?jī)?nèi)部,再通過 ECMP協(xié)議將流量再分到多個(gè)四層負(fù)載均衡節(jié)點(diǎn)。
通過Anycast第一層路由到不同的機(jī)房,第二層的ECMP再路由到基于DPDK技術(shù)開發(fā)的四層負(fù)載均衡節(jié)點(diǎn)。這樣我們整個(gè)的數(shù)據(jù)庫對(duì)外看到的VIP就是同一個(gè)了,所有機(jī)房看到VIP都是同一個(gè)。利用Anycast和ECMP兩個(gè)技術(shù),實(shí)現(xiàn)跨AZ共享VIP。
然后是數(shù)據(jù)層,數(shù)據(jù)層我們現(xiàn)在是一主三從,然后需要2個(gè)以上slave同步成功,才能完成最終的成功。
MySQL版本需要5.7以上,操作系統(tǒng)內(nèi)核需要打一個(gè) toa補(bǔ)丁,這樣經(jīng)過四層負(fù)載均衡之后,MySQL Server才能拿到真正來源IP。因?yàn)槲覀冞@邊要做一個(gè)IP白名單的授權(quán),如果不打補(bǔ)丁,拿到的來源IP就是四層負(fù)載均衡的IP,就沒法做IP白名單授權(quán)了。當(dāng)然top補(bǔ)丁有一個(gè)缺陷,就是只能支持ipv4,這在內(nèi)網(wǎng)使用問題不大。
底層采用了開源的MySQL拓?fù)涔芾斫M件,通過檢測(cè)我們數(shù)據(jù)庫節(jié)點(diǎn)的情況,然后做重新選組做切換,然后通知SLB改變后端指向,流量打到新的master節(jié)點(diǎn),
Anycast不是必須的,也可以用域名代替,但是域名有個(gè)問題,需要重新接連的時(shí)候才會(huì)發(fā)起解析,所以域名切換的時(shí)候可能會(huì)切不干凈。Anycast做切換是立即生效的,因?yàn)檫@是路由協(xié)議的一個(gè)變更,馬上就能切過去,不存在解析不干凈和生效不一致的問題。
Anycast除了內(nèi)網(wǎng)之外,外網(wǎng)也用的比較多,比如說谷歌上負(fù)載均衡器,它發(fā)布的IP就是Anycast的IP,在公網(wǎng)環(huán)境下,在不同的地區(qū)路由到不同的一個(gè)真實(shí)地址,包括我們 DNS Server也是用Anycast去發(fā)布的,在不同的區(qū)域,路由到就近的IDC,所以Anycast技術(shù)應(yīng)用還比較廣泛。
2、MySQL異地多活
上圖是MySQL的異地多活架構(gòu),重點(diǎn)在于提升同步的性能,從源庫訂閱到數(shù)據(jù)以后,不是直接寫目標(biāo)庫,而是先存起來,在目標(biāo)機(jī)房部署中繼日志模塊。這樣的好處是,我們可以在網(wǎng)絡(luò)上快速的傳輸過去,中繼日志并行去寫目標(biāo)庫。
這個(gè)設(shè)計(jì)性能提升非常大,OPPO實(shí)際業(yè)務(wù)場(chǎng)景下,這個(gè)模式比訂閱后直接寫目標(biāo)庫提升了幾倍。因?yàn)橐肓酥欣^日志,就存在兩階段提交的問題。比如中繼日志寫成功,但是中繼日志寫目標(biāo)庫沒有成功。這就存在數(shù)據(jù)一致性問題,需要用到兩階段提交。
還有就是數(shù)據(jù)壓縮和加密,對(duì)數(shù)據(jù)的安全和同步性能也非常重要。
然后是多消費(fèi)者支持,訂閱模塊會(huì)保存數(shù)據(jù),每個(gè)訂閱方可以維持自己的消費(fèi)位點(diǎn),彼此之間沒有干擾,從而減少多訂閱方同步對(duì) Source DB的壓力。
3、MySQL訂閱——數(shù)據(jù)最終一致
以前面提到的評(píng)論系統(tǒng)為例,數(shù)據(jù)同步只同步MySQL那一層,而其他的數(shù)據(jù)源Cache、MQ、ES、排序服務(wù)等,分別訂閱MySQL binlog重新構(gòu)建。
原則上,我們盡量只同步底層的一份MySQL數(shù)據(jù),其他數(shù)據(jù)源訂閱MySQL重建。前面說到,MySQL只需要訂閱一次,Jins程序自己存儲(chǔ)了一份數(shù)據(jù)到本地文件隊(duì)列,然后分別重放到Cache、MQ、ES等其他數(shù)據(jù)源,也可以多次重放數(shù)據(jù)。
如果多數(shù)據(jù)源分別進(jìn)行同步的話,多個(gè)數(shù)據(jù)源同步的進(jìn)度是沒法保證協(xié)調(diào)一致的,必然有的數(shù)據(jù)源快,有的數(shù)據(jù)源慢,這有可能導(dǎo)致兩個(gè)數(shù)據(jù)源之間的關(guān)聯(lián)關(guān)系出現(xiàn)一些程序錯(cuò)誤。所以我們盡量只同步一個(gè)數(shù)據(jù)源,再基于MySQL重建其他的數(shù)據(jù)源,避免進(jìn)度不一致的問題。
4、MySQL數(shù)據(jù)對(duì)比&修復(fù)
OPPO的業(yè)務(wù)場(chǎng)景,很多地方都非常依賴底層的 MySQL數(shù)據(jù)同步,兩個(gè)機(jī)房之間之間到底有沒有差異,是蠻重要的。
因此我們?cè)O(shè)計(jì)了一個(gè)獨(dú)立的MySQL比對(duì)修復(fù)工具,就執(zhí)行上圖這樣一個(gè)SQL語句,通過這個(gè)SQL語句,對(duì)一段時(shí)間之內(nèi)的所有數(shù)據(jù)算一個(gè)異或的值,通過異或值去比對(duì)兩個(gè)機(jī)房之間數(shù)據(jù)差異,如果比對(duì)有差異,我們?cè)倏s小比對(duì)范圍,逐步逼近到差異的記錄行,這個(gè)語句的執(zhí)行效率還是蠻高的。
但是這個(gè)方案有個(gè)不足,要求我們數(shù)據(jù)庫里面有一個(gè)時(shí)間戳的字段,程序會(huì)對(duì)比前一個(gè)周期內(nèi)的所有記錄的異或值,判斷兩個(gè)機(jī)房之間數(shù)據(jù)是否有差異。
另外一重要場(chǎng)景就是數(shù)據(jù)修復(fù),因?yàn)闃I(yè)務(wù)可能配置錯(cuò)了數(shù)據(jù)庫、應(yīng)用實(shí)例配置生效不一致,再比如A單元數(shù)據(jù)寫到B單元,這個(gè)時(shí)候需要修復(fù)數(shù)據(jù),通過這個(gè)工具,把兩個(gè)數(shù)據(jù)庫不一致的數(shù)據(jù)行整理出來,然后人工做識(shí)別或者批量修復(fù)。
5、redis多活
Redis同城多活的架構(gòu)如上圖所示,我們?cè)赗edis Server上面做了一層代理,下層Redis Server沒有使用Redis cluster技術(shù),代理將流量進(jìn)行分片,分發(fā)到了不同的Redis Group里面去,每個(gè)Group里面就是普通的Redis主從。
主從之間采用binlog的同步,因?yàn)镽edis本身沒有binlog,我們把 AOF做了改造,把讓它變成binlog的這種格式,這里改造的工作量不大。
然后代理也支持兩種模式,一種是重定向模式,一種是轉(zhuǎn)發(fā)模式。轉(zhuǎn)發(fā)模式就是寫主讀從,它只會(huì)把寫流量轉(zhuǎn)到了主機(jī)房里面去,但是從機(jī)房是能讀的。重定向模式就不一樣,重定向模式是非常更強(qiáng)一致的,讀寫都只能在主機(jī)房。
前面反復(fù)提到,CAP是針對(duì)數(shù)據(jù)的,是指數(shù)據(jù)本身的延遲或者差異的容忍度,所以這兩種模式都需要支持,有的數(shù)據(jù)它就是要強(qiáng)一致,一定要到主庫里面的去讀,但有的數(shù)據(jù)它允許從庫讀,允許延遲。
異地多活也很簡(jiǎn)單,異地多活兩個(gè)機(jī)房各部署一個(gè)組件去訂閱同機(jī)房的Redis,訂閱Redis的binlog,訂閱的數(shù)據(jù)寫到MQ里面去,兩個(gè)機(jī)房分別重放binlog,實(shí)現(xiàn)起來并不復(fù)雜。
最后簡(jiǎn)單說一下binlog的格式,里面包括了命令、數(shù)據(jù)產(chǎn)生的機(jī)房、遞增的序號(hào),還有一個(gè)時(shí)間戳。還需要注意的一點(diǎn),Redis持久化RDB也要改造一下,RDB需要包含一個(gè) binlog offset,binlog讀取偏移量,需要把它記下來,因?yàn)橹鲝念嵉沟臅r(shí)候,我們訂閱程序要重新從offset開始繼續(xù)訂閱下面的命令。
廣告:Gdevops廣州站:解答2021運(yùn)維、數(shù)據(jù)庫、金融科技亟待抉擇的三大問題
三、GSLB流量調(diào)度
1、Http DNS
最后講我們的GSLB流量調(diào)度,首先是為什么要使用Http DNS。
第一個(gè)是防劫持。
DNS劫持,DNS是多級(jí)緩存,部分環(huán)節(jié)存在解析劫持的情況。
DNS黑洞,這個(gè)大家可能遇到比較少,什么叫DNS黑洞呢?就是運(yùn)營(yíng)商監(jiān)控到某個(gè)域名有惡意的請(qǐng)求,封殺他的時(shí)候不小心擴(kuò)大了封殺的范圍,我們已經(jīng)出現(xiàn)過幾次這種情況,有時(shí)候某個(gè)地區(qū)甚至可以把整個(gè)cn頂級(jí)域名全封殺,這種封殺的范圍很大,稱之為DNS黑洞。整個(gè)2020年已經(jīng)發(fā)生過多次這種情況了,某個(gè)地域整個(gè)頂級(jí)域名都給你封殺掉,大家都解決不了。
第二個(gè)是快速生效。
首先是DNS本身的多級(jí)緩存,這個(gè)時(shí)間不受控制,但它可能不是主要問題,更主要的問題是客戶端長(zhǎng)連接。
我們還沒上Http DNS之前,業(yè)務(wù)使用了客戶端長(zhǎng)連接,需要20分鐘甚至一個(gè)小時(shí)才能大部分流量調(diào)度走。主要的原因就在客戶端長(zhǎng)連接,DNS做了變更以后,只有客戶端重新發(fā)起連接的時(shí)候,它才會(huì)發(fā)重新發(fā)起解析,才拿到新的IP,如果連接沒斷開,就一直不會(huì)轉(zhuǎn)移,所以這部分長(zhǎng)連接用戶根本就切不走。
如果是機(jī)房入口網(wǎng)絡(luò)故障還好,連接天然會(huì)斷開,如果是因?yàn)闃I(yè)務(wù)自己的問題,需要把流量切走,這種情況下就會(huì)發(fā)現(xiàn)根本切不走,所以客戶端長(zhǎng)連接是比較重要的問題。所以客戶端網(wǎng)絡(luò)庫需要處理一下,解析變更的時(shí)候,需要主動(dòng)去關(guān)閉連接,但是傳統(tǒng)DNS,沒有解析變更的通知機(jī)制,不發(fā)起解析就不知道解析變更了,這里就進(jìn)入了循環(huán)了,需要仔細(xì)的思考一下流程。
第三個(gè)是精準(zhǔn)調(diào)度。
傳統(tǒng)的DNS解析只能獲取到IP這一個(gè)參數(shù),首先IP信息不準(zhǔn)確,包括運(yùn)營(yíng)商歸屬、地域歸屬,都不是很準(zhǔn)確,國(guó)外運(yùn)營(yíng)商特別多,情況更嚴(yán)重?,F(xiàn)在IPv6也在快速的推廣,信息不準(zhǔn)確的情況更為嚴(yán)重。其次傳統(tǒng)DNS無法做到用戶維度、設(shè)備維度的解析。
最后是生效一致性。
單元一旦發(fā)生調(diào)度以后,在單元內(nèi)的所有用戶要同時(shí)調(diào)走,不能說一部分先調(diào)走,一部分后調(diào)走,這樣數(shù)據(jù)寫入就亂了,需要保證全體用戶生效的一致性。
2、單元調(diào)度
下面講單元調(diào)度的主要流程
第一步: 劃分用戶單元
劃分用戶單元主要有三種模式:
- 按設(shè)備劃分單元;
- 按賬號(hào)劃分單元;
- 按地域劃分單元。
這里有個(gè)地方需要注意,我們?yōu)榱藙澐謫卧?,客戶端肯定要傳一些參?shù),如果按賬號(hào)劃分單元,需要傳賬號(hào)ID;按設(shè)備劃分單元,需要傳設(shè)備的IMEI,或者國(guó)內(nèi)Android廠商推行的OpenID;按地域劃分單元很簡(jiǎn)單,直接從IP里面可以獲取,不用客戶端傳遞參數(shù)。
因?yàn)殡[私合規(guī)要求,比如說海外業(yè)務(wù),直接傳用戶的ID或設(shè)備信息,是違規(guī)的,因?yàn)槲覀冞@個(gè)調(diào)度的域名它是一個(gè)獨(dú)立的域名,它不是業(yè)務(wù)本身的,這個(gè)域名很難跟用戶解釋,即使跟用戶簽了協(xié)議,因?yàn)闃I(yè)務(wù)主體的不同,可能也不一定包含了這個(gè)域名,所以我們做了一個(gè)匿名化處理,設(shè)計(jì)了兩個(gè)新參數(shù),一個(gè)叫ADG(匿名設(shè)備分組),一個(gè)叫AUG(匿名用戶分組)。
我們將賬號(hào)ID和10萬取模的值定義為AUG,設(shè)備ID與10萬取模的值定義為ADG。通過這種方式,把設(shè)備和賬號(hào)分成10萬個(gè)桶,然后對(duì)桶分單元,比如說1~5000桶是單元1,5000~1萬桶是單元2。這樣我們就不用傳真實(shí)的設(shè)備ID和真實(shí)賬號(hào)。
第二步:客戶端獲取單元號(hào)。
客戶端首次訪問業(yè)務(wù)的時(shí)候要分一個(gè)單元號(hào),這樣就算按地域劃分單元,基本上也不會(huì)出現(xiàn)變更,只要用戶的APP不被刪除,我們OPPO手機(jī)的好處就是,我們的APP是不怕被刪除的,我們的數(shù)據(jù)不會(huì)被清掉;但如果是一個(gè)外發(fā)的APP,可能就存在APP刪除,這個(gè)可以考慮用設(shè)備或者賬號(hào)分單元。獲取到單元號(hào)之后,就永久保存在客戶端。
第三步:客戶端解析域名IP。
域名解析的時(shí)候會(huì)帶上單元號(hào)的參數(shù),獲取這個(gè)單元對(duì)應(yīng)的IP列表,然后客戶端緩存IP列表。需要注意的一點(diǎn)是緩存機(jī)制,建議根據(jù)網(wǎng)絡(luò)環(huán)境進(jìn)行緩存,比如WiFi名稱,或者運(yùn)營(yíng)商的名稱,底層的緩存數(shù)據(jù)結(jié)構(gòu)就是域名加上網(wǎng)絡(luò)環(huán)境的名稱。這樣的好處就是,用戶網(wǎng)絡(luò)切換的時(shí)候,比如說家里面是WiFi,我們拿的是IP1,我們一出門,網(wǎng)絡(luò)環(huán)境變了,我們?nèi)〕龅木彺鍵P就是IP2,在每個(gè)網(wǎng)絡(luò)環(huán)境都是緩存最優(yōu)的IP。
另外一點(diǎn)需要注意是:我們?yōu)槊總€(gè)單元還分配了一個(gè)單元域名,這是一個(gè)傳統(tǒng)DNS域名,主要是降級(jí)的時(shí)候使用。可以設(shè)想一下,如果我們沒有為每個(gè)單元單獨(dú)分配一個(gè)傳統(tǒng)DNS域名,一旦降級(jí)的時(shí)候就會(huì)走到業(yè)務(wù)的主域名,而傳統(tǒng)DNS是不能攜帶任何參數(shù)的,無法做到按單元進(jìn)行解析,用戶流量就全都亂了。
所以每個(gè)單元分配一個(gè)域名的好處就是,降級(jí)的時(shí)候只要降級(jí)到我們這個(gè)單元的域名,這樣大多數(shù)用戶解析結(jié)果還是準(zhǔn)確的,不準(zhǔn)確的一部分通過API網(wǎng)關(guān)重定向或者內(nèi)部轉(zhuǎn)發(fā),只要很少用戶需要走這個(gè)路徑,絕大多數(shù)用戶還是最佳的路徑。
第四步:客戶端重定向。
因?yàn)檎{(diào)度過程當(dāng)中還有一部分用戶在訪問舊的IP,我們是通過API網(wǎng)關(guān),把新機(jī)房IP直接告訴客戶端,客戶端立即用新IP重試,并且異步去刷新解析,如果只是反饋一個(gè)狀態(tài)碼,告訴客戶端需要重新刷新解析,客戶端的總請(qǐng)求時(shí)間就會(huì)拉得比較長(zhǎng),這就是重定向模式。
但除了重定向模式,還有轉(zhuǎn)發(fā)模式,但是轉(zhuǎn)發(fā)模式比較依賴機(jī)房之間的專線帶寬和穩(wěn)定性,如果公司規(guī)模不是很大的話,機(jī)房之間的專線帶寬和穩(wěn)定性可能趕不上公網(wǎng),重定向模式可能更適合一些。
3、單元調(diào)度注意事項(xiàng)
數(shù)據(jù)層聯(lián)動(dòng),舉一個(gè)用戶余額充值的例子,這是非常強(qiáng)一致的,我們可以維護(hù)一個(gè)數(shù)據(jù)不一致用戶清單,比如說有用戶剛剛進(jìn)行了充值,這個(gè)數(shù)據(jù)還沒在各個(gè)機(jī)房達(dá)成一致,機(jī)房調(diào)度的時(shí)候,只是這一部分用戶需要進(jìn)行服務(wù)降級(jí),其他用戶還可以繼續(xù)提供完整的服務(wù)。
4、域名解析刷新時(shí)機(jī)
接下來講域名解析刷新時(shí)機(jī)。因?yàn)镠ttpDNS是直連解析的,不像傳統(tǒng)DNS有多級(jí)的緩存,如果我們還沿用傳統(tǒng)DNS的 TTL方式來刷新解析,這個(gè)TTL就不能設(shè)置得太短,太短了HttpDNS Server的壓力非常大。TTL設(shè)置過長(zhǎng)又不能滿足業(yè)務(wù)快速恢復(fù)的要求。
所以域名解析的及時(shí)刷新依賴另外兩種途徑,第一種途徑是失敗。我們請(qǐng)求一個(gè)服務(wù),要么連接錯(cuò)誤,要么響應(yīng)內(nèi)容出現(xiàn)錯(cuò)誤,比如說我們響應(yīng)了500,或者其他我們認(rèn)可的一個(gè)響應(yīng)值(客戶端可以自己定一個(gè)規(guī)則),我們?cè)L問失敗的時(shí)候,就需要立即去刷新一下域名解析,因?yàn)檎?qǐng)求失敗的時(shí)候可能需要做一個(gè)機(jī)房調(diào)度,不管是業(yè)務(wù)后端出現(xiàn)了問題,或者是連接不上,這種情況都需要做機(jī)房調(diào)度,需要客戶端刷新解析。
第二種途徑是指令,如果是因?yàn)槲覀儙挷蛔?,做活?dòng),或者其他原因的,需要把流量切走,這時(shí)我們可以通過API網(wǎng)關(guān)下發(fā)指令,下發(fā)指令也是隨著API網(wǎng)關(guān)的正常的業(yè)務(wù)請(qǐng)求,響應(yīng)Header帶下去,不是單獨(dú)的通道,也不是通過Push推送。
這樣我們就可以兜底,要么會(huì)請(qǐng)求失敗,會(huì)立即刷新解析。要么請(qǐng)求成功,響應(yīng)header就會(huì)攜帶指令。所以用戶一定能走到失敗和指令其中一條路徑。因此我們做了調(diào)度變更以后,用戶一定會(huì)刷新,不再依賴TTL了,過期時(shí)間可以設(shè)置非常長(zhǎng),這樣我們絕大多數(shù)請(qǐng)求,都不會(huì)發(fā)生真正的解析請(qǐng)求。
通常情況下,傳統(tǒng)DNS有2%~3%的解析失敗率,還是挺高的。通過這種方式,我們就可以把解析成功率做到99.5%以上,日常情況下甚至能做到接近100%。
5、調(diào)度生效一致性
下面講一講調(diào)度生效的一致性,當(dāng)我們的客戶端降級(jí)到傳統(tǒng)DNS的時(shí)候,就會(huì)解析到錯(cuò)誤的機(jī)房,在調(diào)用生效過程當(dāng)中,也會(huì)訪問到舊的機(jī)房,所以我們?cè)贏PI網(wǎng)關(guān)會(huì)做一個(gè)攔截,因?yàn)槊總€(gè)請(qǐng)求都帶上了單元號(hào),API網(wǎng)關(guān)就可以判斷這個(gè)請(qǐng)求是否請(qǐng)求到了正確的機(jī)房,如果請(qǐng)求錯(cuò)了機(jī)房,API網(wǎng)關(guān)把請(qǐng)求定向單元當(dāng)前歸屬的機(jī)房。
定向用戶請(qǐng)求有兩種模式,一種是轉(zhuǎn)發(fā)模式,API網(wǎng)關(guān)直接轉(zhuǎn)發(fā)到新機(jī)房的業(yè)務(wù)后端實(shí)例。另一種是重定向模式,API網(wǎng)關(guān)在響應(yīng)header攜帶了重定向指令,以及新機(jī)房的IP(避免客戶端多一次的請(qǐng)求),客戶端立即重試新IP。
轉(zhuǎn)發(fā)模式需要消耗較多的機(jī)房專線帶寬,重定向模式的總體時(shí)長(zhǎng)更高,業(yè)務(wù)可以自由選擇兩種模式。
解析刷新采用并行跑馬的模式,客戶端會(huì)并行請(qǐng)求兩個(gè)HttpDNS Server和一個(gè)傳統(tǒng)DNS,三個(gè)請(qǐng)求同時(shí)發(fā)出去。如果HttpDNS Server請(qǐng)求成功,哪個(gè)先到就用哪個(gè),如果兩個(gè)HttpDNS Server請(qǐng)求都失敗,就使用傳統(tǒng)DNS解析結(jié)果。因?yàn)槊總€(gè)單元都分配一個(gè)傳統(tǒng)域名,所以傳統(tǒng)DNS解析結(jié)果和HttpDNS解析結(jié)果也基本是一致,只有極少數(shù)用戶會(huì)解析錯(cuò)誤,API網(wǎng)關(guān)重定向一次以后也能糾正過來。
6、調(diào)度決策大腦
調(diào)度決策大腦會(huì)收集很多路的原始監(jiān)控?cái)?shù)據(jù),比如客戶端調(diào)用鏈的數(shù)據(jù)、外網(wǎng)撥測(cè)平臺(tái)的數(shù)據(jù)、機(jī)房網(wǎng)絡(luò)監(jiān)控的數(shù)據(jù)等等,多路數(shù)據(jù)匯總到?jīng)Q策大腦里,進(jìn)行比對(duì)分析,得出故障的結(jié)論。
調(diào)度決策大腦一定要依賴多路監(jiān)控?cái)?shù)據(jù)源,因?yàn)閱温窋?shù)據(jù)的質(zhì)量無法保證,比如可能會(huì)出現(xiàn)撥測(cè)用例配置錯(cuò)誤、網(wǎng)絡(luò)監(jiān)控?cái)?shù)據(jù)丟失等,所以單路數(shù)據(jù)都是不可信的,需要多路數(shù)據(jù)源做交叉的比對(duì),過濾抖動(dòng)、防止誤判。
調(diào)度決策大腦最終會(huì)輸出一個(gè)指令,指令只會(huì)告訴你故障類型,比如:機(jī)房故障、運(yùn)營(yíng)商線路故障、機(jī)房之間網(wǎng)絡(luò)(DCI)故障,或者是容量不足、業(yè)務(wù)自身出現(xiàn)了問題等。業(yè)務(wù)自身出現(xiàn)問題,比如業(yè)務(wù)的數(shù)據(jù)庫故障,也需要切到另外的機(jī)房去。
決策指令同時(shí)發(fā)到兩個(gè)地方,既要發(fā)給接入層,也要發(fā)給數(shù)據(jù)層,為什么需要這樣呢?
假設(shè)我們同城兩個(gè)機(jī)房之間,專線出現(xiàn)了故障,兩個(gè)機(jī)房的數(shù)據(jù)庫肯定達(dá)不成一致,同步不過去了。這個(gè)情況下,假設(shè)我們的數(shù)據(jù)庫選主B機(jī)房,而接入層保留A機(jī)房, A機(jī)房的數(shù)據(jù)庫完全寫不進(jìn)去,即使寫進(jìn)去也是錯(cuò)誤的,這里我們要保證數(shù)據(jù)層和接入層兩邊選擇的機(jī)房要一致。
所以這種專線故障情況下,我們是調(diào)度決策大腦來通知,做統(tǒng)一的決策,同時(shí)通知接入層、數(shù)據(jù)層做聯(lián)動(dòng),選擇同一機(jī)房,這個(gè)主機(jī)房的選擇是事先配置好的,它不是由我們剛剛說的Raft組件來解決的。
7、調(diào)度效果
上圖是我們9月份做過的一次機(jī)房調(diào)度的效果,基本上做到分鐘級(jí)(實(shí)際上是秒級(jí)的)的生效,是很陡的一個(gè)曲線。
四、總結(jié)
最后,給大家總結(jié)一下今天分享的內(nèi)容:
>>>>
Q&A
Q1:Http DNS也有緩存的吧?
A1 :對(duì),剛剛提到我們Http DNS緩存時(shí)間非常長(zhǎng),緩存了一周的時(shí)間,而且緩存的時(shí)候是根據(jù)環(huán)境來緩存的,就是按照 WiFi名稱、運(yùn)營(yíng)商的名稱來做緩存,這樣網(wǎng)絡(luò)切換的時(shí)候可以拿到最優(yōu)的IP。
緩存的時(shí)間非常長(zhǎng),是因?yàn)橛蛎馕龅乃⑿?,是不依賴緩存過期的,如果能請(qǐng)求成功,API網(wǎng)關(guān)在響應(yīng)Header就會(huì)帶上調(diào)度指令,如果請(qǐng)求失敗客戶端也會(huì)主動(dòng)去刷新解析。因此解析的刷新,是不依賴緩存過期時(shí)間的。
Q2:同城多活網(wǎng)絡(luò)是怎么配置的??jī)蓚€(gè)機(jī)房使用相同的ip地址,還是不同的?
A2 :對(duì)于跨機(jī)房高可用的數(shù)據(jù)庫來說,用戶看到的是同一個(gè)IP,第一層使用Anycast路由到機(jī)房,第二層使用ECMP路由到多個(gè)四層負(fù)載均衡節(jié)點(diǎn),單個(gè)四層負(fù)載均衡的流量扛不住,四層負(fù)載均衡是一個(gè)集群,通過ECMP實(shí)現(xiàn)流量分發(fā)。
多余入口流量來說,前面架構(gòu)圖可以看到,接入層在兩個(gè)機(jī)房從四層、七層都是獨(dú)立的,接入層有2組出口IP,如果其中一個(gè)機(jī)房運(yùn)營(yíng)商線路出現(xiàn)問題,根據(jù)調(diào)度決策系統(tǒng)的指令,自動(dòng)停止該運(yùn)營(yíng)商線路的IP解析。
Q3:老師能介紹一下多活帶來什么業(yè)務(wù)收益嗎?是什么契機(jī)促使 OPPO開始做異地多活?
A3 :OPPO業(yè)務(wù)多活的三個(gè)核心訴求是成本、擴(kuò)展、容災(zāi)。
成本是指業(yè)務(wù)總體技術(shù)運(yùn)營(yíng)成本,包括基礎(chǔ)設(shè)施的資源成本、研發(fā)成本,還包括業(yè)務(wù)中斷的成本、品牌和口碑的成本;
擴(kuò)展是因?yàn)闃I(yè)務(wù)規(guī)模過大,一個(gè)服務(wù)需要調(diào)用數(shù)百個(gè)三方實(shí)例、一個(gè)數(shù)據(jù)庫被數(shù)百個(gè)實(shí)例連接、一個(gè)服務(wù)需要連接幾十個(gè)數(shù)據(jù)庫,這就需要對(duì)用戶進(jìn)行分片,縮小業(yè)務(wù)規(guī)模,自然演進(jìn)到單元化多活的架構(gòu);
容災(zāi)一方面是極端情況下用戶數(shù)據(jù)可靠性保障的需求,另一方面還是業(yè)務(wù)過于復(fù)雜、處理的鏈路很長(zhǎng),總有一些意想不到情況的發(fā)生,頻率還挺高,問題定位到恢復(fù)的時(shí)間達(dá)不到公司RTO的要求。機(jī)房?jī)?nèi)部共享了運(yùn)營(yíng)商線路、DNS、SNAT防火墻、負(fù)載均衡、K8S集群、注冊(cè)中心、監(jiān)控等等資源,而機(jī)房之間是相對(duì)隔離的環(huán)境,同時(shí)出問題的概率大為降低。在業(yè)務(wù)出現(xiàn)無法自動(dòng)恢復(fù)的故障時(shí),先切換機(jī)房恢復(fù)業(yè)務(wù),然后再?gòu)娜荻ㄎ粏栴}根因。
Q4:隨著業(yè)務(wù)發(fā)展啟用多個(gè)訂閱時(shí),如何減少對(duì)數(shù)據(jù)庫的壓力?
A4 :我們從數(shù)據(jù)庫源庫訂閱出來以后,先落地到本地文件隊(duì)列,然后多個(gè)訂閱方可以維持自己的同步位點(diǎn),所以對(duì)于源數(shù)據(jù)庫來說,只會(huì)有一次訂閱。
Q5:請(qǐng)問同城雙活方案MHA manager部署在哪個(gè)數(shù)據(jù)中心?
A5 :我們這里不是MHA,我們用的是一個(gè)開源的Raft組件,部署在同城的3個(gè)機(jī)房,通過Raft組件檢測(cè)數(shù)據(jù)庫的狀態(tài)、觸發(fā)切換。
Q6:Http DNS和Local DNS的區(qū)別是什么?
A6 :Http DNS走的是HTTP協(xié)議,客戶端直連解析,沒有運(yùn)營(yíng)商的多級(jí)緩存。Local DNS就是運(yùn)營(yíng)商的DNS,成功率低,還有劫持、黑洞等問題,而且這兩年黑洞頻率是越來越高了,前幾年基本上很少出現(xiàn)黑洞情況。傳統(tǒng)DNS劫持情況現(xiàn)在好一些了,像移動(dòng)端的接口劫持相對(duì)來說會(huì)少一些,H5的劫持多一點(diǎn)。
Http DNS就是依賴HTTP協(xié)議做解析,但這個(gè)壓力會(huì)比較大,因?yàn)镠ttp DNS沒有多級(jí)緩存,所有請(qǐng)求都到我們的機(jī)房,所以刷新機(jī)制的設(shè)計(jì)就非常關(guān)鍵,前面一個(gè)章節(jié)詳細(xì)介紹解析刷新的時(shí)機(jī)。
HttpDNS還有一個(gè)好處,因?yàn)槭亲远x的協(xié)議,可以傳遞其他參數(shù),比如設(shè)備信息、賬號(hào)信息,這樣才能夠?qū)崿F(xiàn)按用戶單元進(jìn)行解析、調(diào)度。
Q7:能否制定統(tǒng)一的用戶單元?jiǎng)澐忠?guī)則?
A7 :這個(gè)問題比較好,我們最開始也是想這樣子的,我們有云服務(wù)、廣告、信息流、音樂、視頻等業(yè)務(wù),起初也想整個(gè)公司使用一套單元?jiǎng)澐忠?guī)則,這樣業(yè)務(wù)之間可以做到單元內(nèi)封閉調(diào)用,避免跨機(jī)房的調(diào)用。
最終的方案,業(yè)務(wù)之間沒有使用同一套單元?jiǎng)澐忠?guī)則。主要原因是:比如說有個(gè)業(yè)務(wù)他經(jīng)常會(huì)做活動(dòng),做活動(dòng)的時(shí)候他需要將一部分用戶調(diào)度走,如果全公司用一套規(guī)則的話,所有業(yè)務(wù)都要跟著調(diào)度走,其他業(yè)務(wù)是不同意的。所以我們是每個(gè)業(yè)務(wù)自己制定單元?jiǎng)澐忠?guī)則。
那這里怎樣解決業(yè)務(wù)之間跨機(jī)房調(diào)用呢?前面說到了平臺(tái)型業(yè)務(wù)SDK化,上層業(yè)務(wù)之間本身沒有強(qiáng)依賴,音樂、軟件商店、視頻之間本身沒有強(qiáng)依賴,他們主要是依賴平臺(tái)型服務(wù),如賬號(hào)、評(píng)論服務(wù)、消息中心、推送服務(wù)等。這些平臺(tái)型業(yè)務(wù)我們最開始也是提供機(jī)房?jī)?nèi)部API去給其他業(yè)務(wù)器調(diào)用,這就導(dǎo)致我們的平臺(tái)型服務(wù)在每一個(gè)機(jī)房都要去部署,每個(gè)機(jī)房都要提供讀寫功能。所以我們將平臺(tái)型域名拆分出來,從SDK就開始就和業(yè)務(wù)域名分開,平臺(tái)型自己做多活。當(dāng)然平臺(tái)型業(yè)務(wù)無法做到100%的SDK化拆分,平臺(tái)型服務(wù)的部分?jǐn)?shù)據(jù)也需要單向同步到各機(jī)房,提供本地查詢的服務(wù)。
Q8:Redis日志是哪個(gè)開源組件做到的來的?
A8 :Redis binlog是OPPO自己修改的,基于AOF修改,簡(jiǎn)單說一下binlog的格式,里面包括了命令、數(shù)據(jù)產(chǎn)生的機(jī)房、遞增的序號(hào),還有一個(gè)時(shí)間戳。
相關(guān)的組件今年會(huì)開源出去,OPPO微服務(wù)體系ESA Stack、存儲(chǔ)已經(jīng)對(duì)外開源,可以搜索一下。
Q9:MQ數(shù)據(jù)同步了,如果切換,在A機(jī)房寫入了,但是還沒消費(fèi),此時(shí)切到B機(jī)房,B機(jī)房咋知道從那個(gè)點(diǎn)開始消費(fèi)呢?
A9 :OPPO主要使用RocketMQ定制版本,節(jié)點(diǎn)跨同城AZ部署即可。