如何設計乙個秒級100萬級的訂單支付架構

2021-10-05 02:56:54 字數 3109 閱讀 3017

在訂單支付系統中,往往會面臨這樣的問題:如何保證每秒萬級甚至10萬百萬級的支付請求或者訂單請求。在講這個這個設計之前來分析下要實現這個秒級100萬級的訂單支付架構會面臨怎樣的問題。

1.db層:讀寫的壓力,高可用,資料庫的一致性。

1.1.假定我們使用是的mysql,單庫,是無法支撐這個資料量級的併發操作的,我們單庫能輕鬆應對10萬級的訪問但是絕對支撐不了10萬級的寫操作。

1.2.假定我們解決了讀寫的壓力問題,我們還將面臨高可用的問題,怎樣的方案能確保資料庫集群宕機後保證資料庫的訪問不受影響。

1.3.假定我們解決了高可用的問題,我們還需要保證資料庫的一致性問題,否則我們將面臨資料丟失和不一致的問題。

接下我們將針對上面3個問題來逐步分析:

1.1.資料庫的讀寫問題,這是這個架構設計裡面最重要最核心的問題。我們知道,通常解決讀寫問題是通過分庫分表來解決的。分庫分表可以把執行sql的壓力根據既定的規則分攤到不同的庫和表,從而減小資料庫的壓力。不論是是分庫還是分表都是為了減小sql執行等待的時間。接下來開始我關於分庫分表的設計,以訂單表的設計為例:我們很清楚的知道分庫分表要解決的問題是訂單表的id主鍵設計問題,要保證在所有庫和表中是唯一的。怎麼保證呢,唯一性很容易想到uuid,uuid確實可以保證全域性唯一,不過uuid存在兩個問題:uuid一段隨機的字串是沒有順序的,執行查詢的效率是很低的;uuid是沒有業務含義的不具備業務含義的區分。

設計:我們已用的id來做鍵值的區分依據,採用二叉樹的方式來分庫分表。我們假設我們把order分成16個庫,每個庫裡面有10張表,這樣我們就有160張表分布在16個庫裡面。

接下來最關鍵的就是通過使用者id(uid)來計算和分配落地到哪個庫的哪張表。

演算法:我這邊庫的設計都是按8的倍數來設計的,便於後面做擴容的時候以8的倍數來擴容,演算法能完美適用擴容。

假設使用者的id為765

資料庫編號=(((765/10)% 16+1)-1)%8-1 下取整     ====》 db5

表序號=(765)%10 下取整        order5

通過這樣的計算我們可以把任何乙個使用者均勻的分配到各個資料庫和表。

這一步完成之後,我們還需要做的就是我們的程式如何按照這個演算法實現了,我這邊用的設計是在我們的應用程式計算處出使用者的這個訂單該落在哪個庫哪個表。

有了分庫分表的計算落地方案後,接下來我們來設計下訂單id:剛剛提到了uuid的不足之處,所以不能使用uuid;因為是分庫分表所以表的id自增是不可行的。這邊我採用了現在的雪花演算法(是有序的),雪花演算法計算的id是毫秒級的,1秒能產生26萬的唯一值。顯然能滿足10級的使用。我在雪花的基礎上在訂單id的上還增加了庫表的資訊。

訂單id=分庫分表資訊+雪花id(機器編號+集群編號+時間戳+自增id)

這樣我們基本上解決了分庫和分表的問題,同時有了高效的訂單編號計算的方案和演算法。

1.2接下來我們來**下  關於高可用的問題,如果我們所有的庫表都放在一台機器上,一旦伺服器宕機,那後果將是災難性的。所以高可用的方案是保證服務穩定執行的必要條件。如何高可用呢,我們首先想到的是資料庫的集群和主從備份。主從同步可以把主庫的資料實時同步到從庫,在這個過程中我們還可以實現讀寫分離,主庫寫,從庫讀等操作。

1.3.資料的一致性:在整個設計過程我們已經考慮了分庫分表的落地設計解決了讀寫併發的問題,通過資料庫的集群和主從設計實現了資料庫的高可用。還有乙個問題至關重要,就是資料的一致性,通常在訂單支付的系統中,我們會按使用者來切分資料庫的集群比如c端使用者和b端商戶,那麼資料的一致性就需要得到保證,在設計過程中我們可以選用訊息中介軟體來保證資料的寫入,在通過資料庫的監聽中介軟體來同步不同集群的差異資料。

2.對資料等級的分類:在設計這種高併發海量資料的系統,我們往往會通過各種快取機制比如redi等來提供系統的訪問速度和效能。那麼是不是所有表的資料我們都能做快取呢?答案是肯定不行的,所以我們需要對我們系統裡表的資料等級做劃分,哪些是可以快取的,哪些是不可以做快取的。這邊有參考樂視支付系統架構的設計,把資料分成幾種等級:

第1級:訂單資料和支付流水資料;這兩塊資料對實時性和精確性要求很高,所以不新增任何快取,讀寫操作將直接運算元據庫。

第3級:支付配置資訊;這些資料和使用者無關,具有資料量小,頻繁讀,幾乎不修改的特徵,所以我們使用本地記憶體進行快取。

按照這樣的等級劃分,我們就能很清晰的分配資源和設計快取,同時不會影響業務又能提供系統的效能。

3.在分析完db這一側的分析後我們來分析下,資料流量的問題:我們先來分析乙個關於秒殺活動的問題,假設我們的庫存有100件商品,但是參與活動的人可能有10萬甚至更多。這個時候我們如果有10萬個請求併發訪問,毫無疑問系統資料庫100%炸,導致的後果很可能一件商品沒被購買,系統還崩了。大多數的秒殺活動實際上真正到db層或者應用層的請求很可能才100,其餘的請求被隨機丟棄了,這樣就能很好的保證系統的正常執行,同時秒殺本身就存在搶不到的情況,所以沒搶到的使用者也只會認為是自己的手速或者網路問題。其實這是一鐘很好的思路,既沒有過度去想技術實現(成本很高,實現很複雜),又很好的完成了業務訴求。實際上我們所謂的訂單支付限流也可以借鑑這種思想,不過在丟棄請求這個細節是不同的,你不能把使用者的支付請求丟棄掉;所以怎麼做呢?我們借鑑秒殺的思想,我們在每秒最大能到db層的請求(r)要做個設計,r

總結:這邊的設計主要是從資料庫db層面和請求流量兩個方面闡述設計思路,實際應用鐘,在**層面還有很多很多的細節要考慮,比如分布式事務,快取更新同步策略,資料計算,多表操作等等。這邊分享的主要還是以思想為主, 大家又興趣可以嘗試自己搭建,模擬大請求嘗試一下,體會會更深,好的設計一定是為業務服務的,既不要過度設計(秒殺)也不要考慮的很不周全,導致後續擴充套件的問題。好的架構---》簡單,適用,可演變 我堅信的架構理念。

乙個簡單的一級指標和二級指標

如下 int i 1 int p i int pp p printf i p n i printf p p n p printf p d n p printf p p n p printf pp p n pp printf pp p n pp printf pp d n pp printf pp p...

乙個常見的優先順序問題

優先順序問題確實是比較讓人鬱悶的問題,有時候出錯了,查詢半天最後才發現是它的問題。下面這個問題也是很常見的乙個。a 3 b 5 if a 5 b 7 echo a b a和b分別為什麼呢?不執行 先猜一猜。第一眼看上去 不假思索的話 相信很多人說是6,8 然後稍加思索的話 可能會選 6,6 然後再思...

java優先順序的乙個細節

對於乙個連等型的表示式,其在不同位置相同的變數,會因為變數賦值順序的不同,影響變數的值是否賦值 成功,如下 public class test 這段 的結果是 03 雖然 表示式的運算順序是從右向左,但是變數在運算前 已經被從左至右讀入cpu,所以,對於第一部分 第乙個a的值為0,第二個a值為 1 ...