一年前,在上一家公司接手了一個(gè)含有訂單系統(tǒng)的項(xiàng)目,業(yè)務(wù)并不復(fù)雜,但是當(dāng)時(shí)令我比較困惑的是訂單表的設(shè)計(jì)。
困惑的點(diǎn)主要是隨著訂單量增加,單表的存儲(chǔ)能力將達(dá)到瓶頸,必然要采用分表的方案,那么按照什么維度拆分合適呢?
分表之后帶來(lái)的最大的挑戰(zhàn)是訂單查詢。如果以用戶為中心,采用userId取模,可以很方便的處理用戶查單訴求,但是對(duì)商家或產(chǎn)品而言,數(shù)據(jù)就比較分散,相反如果以商家或商品為中心,則用戶查單比較困難。
由于對(duì)這樣的業(yè)務(wù)沒(méi)有成熟的經(jīng)驗(yàn),最后只能采取相對(duì)討巧的方案,按照自然日期分表,考慮訂單量并不大,當(dāng)時(shí)是每個(gè)季度一張表,一年4張表。
為什么說(shuō)討巧?以用戶查單為例,查詢頁(yè)默認(rèn)要選擇一個(gè)季度,也就是將用戶訂單數(shù)據(jù)限制在一張表中做查詢。大多數(shù)時(shí)候用戶也只是查看最近訂單,所以勉強(qiáng)可以接受。
如果用戶一定要查看全部訂單,只能將所有訂單表union all,當(dāng)時(shí)想的是至少前幾個(gè)年頭訂單表數(shù)量有限,性能問(wèn)題不會(huì)太嚴(yán)重,以后再想辦法進(jìn)行優(yōu)化。
前幾天又想到了這個(gè)訂單表的設(shè)計(jì)問(wèn)題,于是和現(xiàn)在的同事進(jìn)行了簡(jiǎn)單的溝通,也學(xué)到了非常寶貴的經(jīng)驗(yàn)。在這里簡(jiǎn)單記錄一下,說(shuō)的不對(duì)的地方希望大家多多包涵并不吝賜教。
具體怎么做呢?
簡(jiǎn)單來(lái)說(shuō)就是冗余+同步+檢查。
數(shù)據(jù)冗余,非常有效的解決了數(shù)據(jù)分散的問(wèn)題。將訂單落庫(kù)訂單表(暫且稱作訂單表O),訂單表按照日期分表,按天,周,月,季度或者年都可以,可根據(jù)實(shí)際業(yè)務(wù)量選擇。分表首先解決了單表存儲(chǔ)的瓶頸問(wèn)題。如何冗余?以用戶查單為例,新建用戶訂單表(訂單表U-O),將userId取模分表,冗余一份訂單數(shù)據(jù),U-O表中的數(shù)據(jù)可以只包含重要信息如下單時(shí)間,數(shù)量,金額,訂單狀態(tài)等(列表頁(yè)展示)。訂單詳情信息可以從O表中查詢。
這樣一來(lái),用戶查單自然就只限一張表中啦。這么簡(jiǎn)單的問(wèn)題為什么我沒(méi)想到呢?不過(guò)這樣一來(lái),新的問(wèn)題出現(xiàn)了,就是如何保證這兩份(也可能多份)訂單表數(shù)據(jù)同步?雖然訂單的大部分信息不會(huì)經(jīng)常變更,但是在訂單完成之前,必然有訂單狀態(tài)的變更或用戶更新的可能。這就是我將要說(shuō)的數(shù)據(jù)同步問(wèn)題。
如何同步?可能大家會(huì)想到將幾份訂單數(shù)據(jù)放入事務(wù)處理,雖然事務(wù)可以有效的解決同步問(wèn)題(事務(wù)一致性),但是我認(rèn)為事務(wù)一方面影響了數(shù)據(jù)庫(kù)性能,另一方便增加了接口復(fù)雜性(耦合)。同事給我的方案是通過(guò)消息組件同步,消息在分布式系統(tǒng)中是非常重要的存在,可以很好的將服務(wù)解耦,而且高可用,支持高并發(fā),響應(yīng)速度快。
但是消息同步還不能保證數(shù)據(jù)同步的絕對(duì)一致,比如消息延時(shí),重復(fù),丟失等。一方面要優(yōu)化消息組件的穩(wěn)定性,另一方面要做好監(jiān)控。最重要的是要采取一個(gè)主動(dòng)檢查的手段。
做好數(shù)據(jù)檢查。比如啟一個(gè)job每天凌晨進(jìn)行一次前一天的數(shù)據(jù)檢查,比對(duì)所有訂單的一致性。既然采用了消息機(jī)制,我們所有的對(duì)訂單的更新操作都是對(duì)O表進(jìn)行的,因此以O(shè)表數(shù)據(jù)為準(zhǔn)即可。
以上就是同事那里收獲到的比較不錯(cuò)的方案,因?yàn)闆](méi)有深入剖析,加之我所說(shuō)的比較膚淺,如果能親自參與一次實(shí)際的開(kāi)發(fā),也許我會(huì)跟大家分享更多有價(jià)值的東西。