自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

專車架構(gòu)進(jìn)化往事:好的架構(gòu)是進(jìn)化來(lái)的,不是設(shè)計(jì)來(lái)的

開(kāi)發(fā) 架構(gòu)
架構(gòu)進(jìn)化之路并非一帆風(fēng)順,也有波折和起伏,但一步一個(gè)腳印,專車的技術(shù)儲(chǔ)備越來(lái)越深厚。

很多年前,讀了 子柳 老師的《淘寶技術(shù)這十年》。這本書(shū)成為了我的架構(gòu)啟蒙書(shū),書(shū)中的一句話像種子一樣深埋在我的腦海里: “好的架構(gòu)是進(jìn)化來(lái)的,不是設(shè)計(jì)來(lái)的” 。

2015年,我加入神州專車訂單研發(fā)團(tuán)隊(duì),親歷了專車數(shù)據(jù)層「架構(gòu)進(jìn)化」的過(guò)程。這次工作經(jīng)歷對(duì)我而言非常有啟發(fā)性,也讓我經(jīng)常感慨:“好的架構(gòu)果然是一點(diǎn)點(diǎn)進(jìn)化來(lái)的”。

一、單數(shù)據(jù)庫(kù)架構(gòu)

產(chǎn)品初期,技術(shù)團(tuán)隊(duì)的核心目標(biāo)是: “快速實(shí)現(xiàn)產(chǎn)品需求,盡早對(duì)外提供服務(wù)” 。

彼時(shí)的專車服務(wù)都連同一個(gè) SQLServer 數(shù)據(jù)庫(kù),服務(wù)層已經(jīng)按照業(yè)務(wù)領(lǐng)域做了一定程度的拆分。

這種架構(gòu)非常簡(jiǎn)單,團(tuán)隊(duì)可以分開(kāi)協(xié)作,效率也極高。隨著專車訂單量的不斷增長(zhǎng),早晚高峰期,用戶需要打車的時(shí)候,點(diǎn)擊下單后經(jīng)常無(wú)響應(yīng)。

系統(tǒng)層面來(lái)看:

  1. 數(shù)據(jù)庫(kù)瓶頸顯現(xiàn)。頻繁的磁盤操作導(dǎo)致數(shù)據(jù)庫(kù)服務(wù)器 IO 消耗增加,同時(shí)多表關(guān)聯(lián),排序,分組,非索引字段條件查詢也會(huì)讓 cpu 飆升,最終都會(huì)導(dǎo)致數(shù)據(jù)庫(kù)連接數(shù)激增;
  2. 網(wǎng)關(guān)大規(guī)模超時(shí)。在高并發(fā)場(chǎng)景下,大量請(qǐng)求直接操作數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)連接資源不夠用,大量請(qǐng)求處于阻塞狀態(tài)。

二、SQL優(yōu)化和讀寫(xiě)分離

為了緩解主數(shù)據(jù)庫(kù)的壓力,很容易就想到的策略: SQL優(yōu)化 。通過(guò)性能監(jiān)控平臺(tái)和 DBA 同學(xué)協(xié)作分析出業(yè)務(wù)慢 SQL ,整理出優(yōu)化方案:

  1. 合理添加索引;
  2. 減少多表 JOIN 關(guān)聯(lián),通過(guò)程序組裝,減少數(shù)據(jù)庫(kù)讀壓力;
  3. 減少大事務(wù),盡快釋放數(shù)據(jù)庫(kù)連接。

另外一個(gè)策略是: 讀寫(xiě)分離 。

讀寫(xiě)分離的基本原理是讓主數(shù)據(jù)庫(kù)處理事務(wù)性增、改、刪操作( INSERT、UPDATE、DELETE),而從數(shù)據(jù)庫(kù)處理 SELECT 查詢操作。

專車架構(gòu)團(tuán)隊(duì)提供的 框架 中,支持讀寫(xiě)分離,于是數(shù)據(jù)層架構(gòu)進(jìn)化為如下圖:

讀寫(xiě)分離可以減少主庫(kù)寫(xiě)壓力,同時(shí)讀從庫(kù)可水平擴(kuò)展。當(dāng)然,讀寫(xiě)分離依然有局限性:

  1. 讀寫(xiě)分離可能面臨主從延遲的問(wèn)題,訂單服務(wù)載客流程中對(duì)實(shí)時(shí)性要求較高,因?yàn)閾?dān)心延遲問(wèn)題,大量操作依然使用主庫(kù)查詢;
  2. 讀寫(xiě)分離可以緩解讀壓力,但是寫(xiě)操作的壓力隨著業(yè)務(wù)爆發(fā)式的增長(zhǎng)并沒(méi)有很有效的緩解。

三、業(yè)務(wù)領(lǐng)域分庫(kù)

雖然應(yīng)用層面做了優(yōu)化,數(shù)據(jù)層也做了讀寫(xiě)分離,但主庫(kù)的壓力依然很大。接下來(lái),大家不約而同的想到了 業(yè)務(wù)領(lǐng)域分庫(kù) ,也就是:將數(shù)據(jù)庫(kù)按業(yè)務(wù)領(lǐng)域拆分成不同的業(yè)務(wù)數(shù)據(jù)庫(kù),每個(gè)系統(tǒng)僅訪問(wèn)對(duì)應(yīng)業(yè)務(wù)的數(shù)據(jù)庫(kù)。

業(yè)務(wù)領(lǐng)域分庫(kù)可以緩解核心訂單庫(kù)的性能壓力,同時(shí)也減少系統(tǒng)間的相互影響,提升了系統(tǒng)整體穩(wěn)定性。

隨之而來(lái)的問(wèn)題是:原來(lái)單一數(shù)據(jù)庫(kù)時(shí),簡(jiǎn)單的使用 JOIN 就可以滿足需求,但拆分后的業(yè)務(wù)數(shù)據(jù)庫(kù)在不同的實(shí)例上,就不能跨庫(kù)使用 JOIN了,因此需要對(duì) 系統(tǒng)邊界重新梳理,業(yè)務(wù)系統(tǒng)也需要重構(gòu) 。

重構(gòu)重點(diǎn)包含兩個(gè)部分:

  1. 原來(lái)需要 JOIN 關(guān)聯(lián)的查詢修改成 RPC 調(diào)用,程序中組裝數(shù)據(jù) ;
  2. 業(yè)務(wù)表適當(dāng)冗余字段,通過(guò)消息隊(duì)列或者異構(gòu)工具同步。

四、緩存和MQ

專車服務(wù)中,訂單服務(wù)是并發(fā)量和請(qǐng)求量最高,也是業(yè)務(wù)中最核心的服務(wù)。雖然通過(guò)業(yè)務(wù)領(lǐng)域分庫(kù),SQL 優(yōu)化提升了不少系統(tǒng)性能,但訂單數(shù)據(jù)庫(kù)的寫(xiě)壓力依然很大,系統(tǒng)的瓶頸依然很明顯。

于是,訂單服務(wù)引入了 緩存   MQ  。

乘客在用戶端點(diǎn)擊 立即叫車 ,訂單服務(wù)創(chuàng)建訂單,首先保存到數(shù)據(jù)庫(kù)后,然后將訂單信息同步保存到緩存中。

在訂單的載客生命周期里,訂單的修改操作先修改緩存,然后發(fā)送消息到 MetaQ  ,訂單落盤服務(wù)消費(fèi)消息,并判斷訂單信息是否正常(比如有無(wú)亂序),若訂單數(shù)據(jù)無(wú)誤,則存儲(chǔ)到數(shù)據(jù)庫(kù)中。

核心邏輯有兩點(diǎn):

  1. 緩存集群中存儲(chǔ)最近七天訂單詳情信息,大量訂單讀請(qǐng)求直接從緩存獲取;
  2. 在訂單的載客生命周期里,寫(xiě)操作先修改緩存,通過(guò)消息隊(duì)列異步落盤,這樣消息隊(duì)列可以起到消峰的作用,同樣可以降低數(shù)據(jù)庫(kù)的壓力。

這次優(yōu)化提升了訂單服務(wù)的整體性能,也為后來(lái)訂單服務(wù)庫(kù)分庫(kù)分表以及異構(gòu)打下了堅(jiān)實(shí)的基礎(chǔ)。

五、從 SQL Server 到 MySQL

業(yè)務(wù)依然在爆炸增長(zhǎng),每天幾十萬(wàn)訂單,訂單表數(shù)據(jù)量很快將過(guò)億,數(shù)據(jù)庫(kù)天花板遲早會(huì)觸及。

訂單 分庫(kù)分表 已成為技術(shù)團(tuán)隊(duì)的共識(shí)。業(yè)界很多分庫(kù)分表方案都是基于 MySQL 數(shù)據(jù)庫(kù),專車技術(shù)管理層決定先將訂單庫(kù)整體先從 SQLServer 遷移到 MySQL 。

遷移之前, 準(zhǔn)備工作 很重要 :

  1. SQLServer 和 MySQL 兩種數(shù)據(jù)庫(kù)語(yǔ)法有一些差異,訂單服務(wù)必須要適配 MySQL 語(yǔ)法。
  2. 訂單 order_id 是主鍵自增,但在分布式場(chǎng)景中并不合適,需要將訂單 id 調(diào)整為分布式模式。

當(dāng)準(zhǔn)備工作完成后,才開(kāi)始遷移。

遷移過(guò)程分兩部分: 歷史全量數(shù)據(jù)遷移  增量數(shù)據(jù)遷移 。

歷史數(shù)據(jù)全量遷移主要是 DBA 同學(xué)通過(guò)工具將訂單庫(kù)同步到獨(dú)立的 MySQL 數(shù)據(jù)庫(kù)。

增量數(shù)據(jù)遷移:因?yàn)?SQLServer 無(wú) binlog 日志概念,不能使用 maxwell 和 canal 等類似解決方案。訂單團(tuán)隊(duì)重構(gòu)了訂單服務(wù)代碼,每次訂單寫(xiě)操作的時(shí)候,會(huì)發(fā)送一條 MQ 消息到 MetaQ 。為了確保遷移的可靠性,還需要將新庫(kù)的數(shù)據(jù)同步到舊庫(kù),也就是需要做到 雙向同步 

遷移流程:

  1. 首先訂單服務(wù)(SQLServer版)發(fā)送訂單變更消息到 MetaQ ,此時(shí)并不開(kāi)啟「舊庫(kù)消息消費(fèi)」,讓消息先堆積在 MetaQ 里;
  2. 然后開(kāi)始遷移歷史全量數(shù)據(jù),當(dāng)全量遷移完成后,再開(kāi)啟「舊庫(kù)消息消費(fèi)」,這樣新訂單庫(kù)就可以和舊訂單庫(kù)數(shù)據(jù)保持同步了;
  3. 開(kāi)啟「新庫(kù)消息消費(fèi)」,然后部署訂單服務(wù)( MySQL 版),此時(shí)訂單服務(wù)有兩個(gè)版本同時(shí)運(yùn)行,檢測(cè)數(shù)據(jù)無(wú)誤后,逐步增加新訂單服務(wù)流量,直到老訂單服務(wù)完全下線。

六、自研分庫(kù)分表組件

業(yè)界分庫(kù)分表一般有 proxy 和 client 兩種流派。

▍ proxy模式

代理層分片方案業(yè)界有 Mycat , cobar 等 。

它的優(yōu)點(diǎn):應(yīng)用零改動(dòng),和語(yǔ)言無(wú)關(guān),可以通過(guò)連接共享減少連接數(shù)消耗。缺點(diǎn):因?yàn)槭谴韺?,存在額外的時(shí)延。

▍ client模式

應(yīng)用層分片方案業(yè)界有 sharding-jdbc , TDDL 等。

它的優(yōu)點(diǎn):直連數(shù)據(jù)庫(kù),額外開(kāi)銷小,實(shí)現(xiàn)簡(jiǎn)單,輕量級(jí)中間件。缺點(diǎn):無(wú)法減少連接數(shù)消耗,有一定的侵入性,多數(shù)只支持Java語(yǔ)言。

神州架構(gòu)團(tuán)隊(duì)選擇 自研 分庫(kù)分表組件,采用了 client 模式 ,組件命名: SDDL 

訂單服務(wù)需要引入是 SDDL 的 jar 包,在配置中心配置 數(shù)據(jù)源信息  , sharding key    路由規(guī)則 等,訂單服務(wù)只需要配置一個(gè) datasourceId  即可。

七、分庫(kù)分表策略

7.1 乘客維度

專車訂單數(shù)據(jù)庫(kù)的查詢主維度是: 乘客 ,乘客端按乘客 user_id 和 訂單 order_id 查詢頻率最高,我們選擇 user_id 做為 sharding key  ,相同用戶的訂單數(shù)據(jù)存儲(chǔ)到同一個(gè)數(shù)據(jù)庫(kù)中。

分庫(kù)分表組件 SDDL 和阿里開(kāi)源的數(shù)據(jù)庫(kù)中間件 cobar 路由算法非常類似的。

為了便于思維擴(kuò)展,先簡(jiǎn)單介紹下 cobar 的分片算法。

假設(shè)現(xiàn)在需要將訂單表平均拆分到4個(gè)分庫(kù) shard0 ,shard1 ,shard2 ,shard3 。首先將 [0-1023] 平均分為4個(gè)區(qū)段:[0-255],[256-511],[512-767],[768-1023],然后對(duì)字符串(或子串,由用戶自定義)做 hash, hash 結(jié)果對(duì)1024取模,最終得出的結(jié)果 slot  落入哪個(gè)區(qū)段,便路由到哪個(gè)分庫(kù)。

cobar 的默認(rèn)路由算法 ,可以和 雪花算法  天然融合在一起, 訂單 order_id  使用雪花算法,我們可以將 slot 的值保存在 10位工作機(jī)器ID  里。

通過(guò)訂單 order_id 可以反查出 slot , 就可以定位該用戶的訂單數(shù)據(jù)存儲(chǔ)在哪個(gè)分區(qū)里。

Integer getWorkerId(Long orderId) {
Long workerId = (orderId >> 12) & 0x03ff;
return workerId.intValue();
}

專車 SDDL 分片算法和 cobar 差異點(diǎn)在于:

  1. cobar 支持最大分片數(shù)是1024,而 SDDL 最大支持分庫(kù)數(shù)1024*8=8192,同樣分四個(gè)訂單庫(kù),每個(gè)分片的 slot 區(qū)間范圍是2048 ;

  1. 因?yàn)橐С?192個(gè)分片,雪花算法要做一點(diǎn)微調(diào),雪花算法的10位工作機(jī)器修改成 13 位工作機(jī)器,時(shí)間戳也調(diào)整為: 38 位時(shí)間戳(由某個(gè)時(shí)間點(diǎn)開(kāi)始的毫秒數(shù))。

7.2 司機(jī)維度

雖然解決了主維度乘客分庫(kù)分表問(wèn)題,但專車還有另外一個(gè)查詢維度,在司機(jī)客戶端,司機(jī)需要查詢分配給他的訂單信息。

我們已經(jīng)按照乘客 user_id 作為 sharding key ,若按照司機(jī) driver_id 查詢訂單的話,需要廣播到每一個(gè)分庫(kù)并聚合返回,基于此,技術(shù)團(tuán)隊(duì)選擇將乘客維度的訂單數(shù)據(jù) 異構(gòu) 到以司機(jī)維度的數(shù)據(jù)庫(kù)里。

司機(jī)維度的分庫(kù)分表策略和乘客維度邏輯是一樣的,只不過(guò) sharding key 變成了司機(jī) driver_id 。

異構(gòu)神器 canal 解析乘客維度四個(gè)分庫(kù)的 binlog ,通過(guò) SDDL 寫(xiě)入到司機(jī)維度的四個(gè)分庫(kù)里。

這里大家可能有個(gè)疑問(wèn):雖然可以異構(gòu)將訂單同步到司機(jī)維度的分庫(kù)里,畢竟有些許延遲,如何保證司機(jī)在司機(jī)端查詢到最新的訂單數(shù)據(jù)呢 ?

 緩存和MQ 這一小節(jié)里提到:緩存集群中存儲(chǔ)最近七天訂單詳情信息,大量訂單讀請(qǐng)求直接從緩存獲取。訂單服務(wù)會(huì)緩存司機(jī)和當(dāng)前訂單的映射,這樣司機(jī)端的大量請(qǐng)求就可以直接緩存中獲取,而司機(jī)端查詢訂單列表的頻率沒(méi)有那么高,異構(gòu)復(fù)制延遲在10毫秒到30毫秒之間,在業(yè)務(wù)上是完全可以接受的。

7.3 運(yùn)營(yíng)維度

專車管理后臺(tái),運(yùn)營(yíng)人員經(jīng)常需要查詢訂單信息,查詢條件會(huì)比較復(fù)雜,專車技術(shù)團(tuán)隊(duì)采用的做法是:訂單數(shù)據(jù)落盤在乘客維度的訂單分庫(kù)之后,通過(guò) canal 把數(shù)據(jù)同步到Elastic Search。

7.4 小表廣播

業(yè)務(wù)中有一些配置表,存儲(chǔ)重要的配置,讀多寫(xiě)少。在實(shí)際業(yè)務(wù)查詢中,很多業(yè)務(wù)表會(huì)和配置表進(jìn)行聯(lián)合數(shù)據(jù)查詢。但在數(shù)據(jù)庫(kù)水平拆分后,配置表是無(wú)法拆分的。

小表廣播的原理是:將小表的所有數(shù)據(jù)(包括增量更新)自動(dòng)廣播(即復(fù)制)到大表的機(jī)器上。這樣,原來(lái)的分布式 JOIN 查詢就變成單機(jī)本地查詢,從而大大提高了效率。

專車場(chǎng)景下,小表廣播是非常實(shí)用的需求。比如: 城市表 是非常重要的配置表,數(shù)據(jù)量非常小,但訂單服務(wù),派單服務(wù),用戶服務(wù)都依賴這張表。

通過(guò) canal 將基礎(chǔ)配置數(shù)據(jù)庫(kù)城市表同步到訂單數(shù)據(jù)庫(kù),派單數(shù)據(jù)庫(kù),用戶數(shù)據(jù)庫(kù)。

八、平滑遷移

分庫(kù)分表組件 SDDL  研發(fā)完成,并在生產(chǎn)環(huán)境得到一定程度的驗(yàn)證后,訂單服務(wù)從單庫(kù) MySQL 模式遷移到分庫(kù)分表模式條件已經(jīng)成熟。

遷移思路其實(shí)和 從 SQLServer 到 MySQL 非常類似。

整體遷移流程:

  1. DBA 同學(xué)準(zhǔn)備乘客維度的四個(gè)分庫(kù),司機(jī)維度的四個(gè)分庫(kù) ,每個(gè)分庫(kù)都是最近某個(gè)時(shí)間點(diǎn)的全量數(shù)據(jù);
  2. 八個(gè)分庫(kù)都是全量數(shù)據(jù),需要按照分庫(kù)分表規(guī)則刪除八個(gè)分庫(kù)的冗余數(shù)據(jù) ;
  3. 開(kāi)啟正向同步,舊訂單數(shù)據(jù)按照分庫(kù)分表策略落盤到乘客維度的分庫(kù),通過(guò) canal 將乘客維度分庫(kù)訂單數(shù)據(jù)異構(gòu)復(fù)制到司機(jī)維度的分庫(kù)中;
  4. 開(kāi)啟反向同步,修改訂單應(yīng)用的數(shù)據(jù)源配置,重啟訂單服務(wù),訂單服務(wù)新創(chuàng)建的訂單會(huì)落盤到乘客維度的分庫(kù),通過(guò) canal 將乘客維度分庫(kù)訂單數(shù)據(jù)異構(gòu)到 全量訂單庫(kù) 以及司機(jī)維度的數(shù)據(jù)庫(kù);
  5. 驗(yàn)證數(shù)據(jù)無(wú)誤后,逐步更新訂單服務(wù)的數(shù)據(jù)源配置,完成整體遷移。

九、數(shù)據(jù)交換平臺(tái)

專車訂單已完成分庫(kù)分表 , 很多細(xì)節(jié)都值得復(fù)盤:

  1. 全量歷史數(shù)據(jù)遷移需要 DBA 介入 ,技術(shù)團(tuán)隊(duì)沒(méi)有成熟的工具或者產(chǎn)品輕松完成;
  2. 增量數(shù)據(jù)遷移通過(guò) canal 來(lái)實(shí)現(xiàn)。隨著專車業(yè)務(wù)的爆發(fā)增長(zhǎng),數(shù)據(jù)庫(kù)鏡像,實(shí)時(shí)索引構(gòu)建,分庫(kù)異構(gòu)等需求越來(lái)越多,雖然canal 非常優(yōu)秀,但它還是有瑕疵,比如缺失任務(wù)控制臺(tái),數(shù)據(jù)源管理能力,任務(wù)級(jí)別的監(jiān)控和報(bào)警,操作審計(jì)等功能。

面對(duì)這些問(wèn)題,架構(gòu)團(tuán)隊(duì)的目標(biāo)是打造一個(gè)平臺(tái),滿足各種異構(gòu)數(shù)據(jù)源之間的實(shí)時(shí)增量同步和離線全量同步,支撐公司業(yè)務(wù)的快速發(fā)展。

基于這個(gè)目標(biāo),架構(gòu)團(tuán)隊(duì)自研了 dataLink 用于增量數(shù)據(jù)同步,深度定制了阿里開(kāi)源的 dataX 用于全量數(shù)據(jù)同步。

十、寫(xiě)到最后

專車架構(gòu)進(jìn)化之路并非一帆風(fēng)順,也有波折和起伏,但一步一個(gè)腳印,專車的技術(shù)儲(chǔ)備越來(lái)越深厚。

責(zé)任編輯:張燕妮 來(lái)源: 博客園
相關(guān)推薦

2022-04-24 11:01:09

架構(gòu)數(shù)據(jù)庫(kù)專車

2009-09-27 09:52:36

2020-03-03 08:40:16

細(xì)腰架構(gòu)進(jìn)化

2022-05-09 11:29:42

架構(gòu)數(shù)據(jù)

2013-09-10 11:15:10

比平話設(shè)計(jì)

2018-08-22 17:58:01

數(shù)據(jù)平臺(tái)數(shù)據(jù)倉(cāng)庫(kù)架構(gòu)

2016-10-17 13:50:31

2014-10-08 15:13:12

GITC2014全球互聯(lián)網(wǎng)技術(shù)大會(huì)

2011-09-01 09:34:21

架構(gòu)

2018-05-14 12:30:37

數(shù)據(jù)驅(qū)動(dòng)算法優(yōu)化

2017-03-02 11:25:43

云計(jì)算

2020-12-03 14:03:29

中臺(tái)數(shù)智化架構(gòu)

2012-09-28 13:23:43

編程語(yǔ)言語(yǔ)言進(jìn)化程序員

2017-02-20 09:02:31

Impala架構(gòu)設(shè)計(jì)

2024-10-29 14:34:46

2012-09-11 10:23:24

Windows 8

2023-10-30 16:02:20

區(qū)塊鏈元宇宙

2013-12-12 16:51:43

安卓進(jìn)化AndroidGoogle

2013-12-12 16:23:53

安卓進(jìn)化AndroidGoogle

2018-04-02 09:07:36

CIO
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)