題記:本篇博客主要是對美團訂單系統分庫分表系統的一些解析和加入了自己的理解,純粹是做筆記,長知識吧,不會構成侵權吧…..
分庫分表
緣由
- 訂單系統過於龐大
- 索引混亂(索引的建立需要在識別度高一點的字段建立,老重複的就不要了)
- 查詢慢
- 表數據量大
解決辦法
垂直切分
- 垂直切分是什麼意思?
簡單來說就是豎着切,試想一下,把一個庫中很多張表豎着切,這些表就會散開,其實垂直切分就是這個意思,將不同模塊的表放到不同的數據庫中,比如支付的放在支付數據庫,用戶的放在用戶數據庫,會員的放在會員數據庫等等,可以減少耦合性。
水平切分
- 含義
將某張訪問非常頻繁的表,按照某個特定的規則(通常是某個字段進行hash),然後將數據分散到多個表,甚至是多個數據庫中,這樣每張表或者每張庫都含有一部分數據。
- 實例
從美團數據庫分片出發
(1) 查詢切分
首先數據庫分片,將sharding key記錄在一個單獨的庫中
你每次要查詢數據庫的時候,請先到mapping db裏面去查一下你應該到那個數據庫去拿數據。
思考:這個mapping db是否真的有需要,是否shading key提供一種約定,比如說根據用戶id來進行hash進行分散到不同的數據庫中。當然這只是一種分片策略,如果你覺得慢,可以把這個表結構緩存在內存中。這樣就很快了
(2)範圍切分
按照範圍來切分,比如說按照時間範圍和ID的範圍來進行切分
比如說用戶的id是0-1000000的,請到第一個數據庫中去查詢,優點是每張表的大小是可以控制的,缺點是集中寫入時候,數據庫壓力過大
(3)Hash切分
一般使用取模運算來進行切分,也就是Mod切分,圖中db mod代表db取模,tb mod代表tb取模
解釋:比如分庫分表的方案是32個數據庫實例,通過userId進行取模的話就是,將UserId後面4位模32然後丟到32個數據庫中,同時又將UserId後面4位除以32再mod32丟到32張表裏面,這樣就有1024張表,然後線上部署8個主從實例,每個實例4個數據庫。完畢。
問題: 爲什麼是32個實例,我沒有那麼大的規模怎麼辦
回答: 其實32個只是個demo,但是我們這裏hash規則一定要滿足一致性hash,而恰巧mod 2的n次方這種就是一致性hash,所以你的數據庫實例可以是2/4/8/16/32等
問題:爲什麼是取後四位
回答:因爲美團訂單把用戶後四位融到訂單號裏面了,然後訂單號方案是時間戳+用戶4位標識碼+隨機數,沒有使用單一的集羣方案
問題:爲什麼這種易於擴展?
回答:現在是8個主從實例,以後如果數據庫到瓶頸了那麼就可以部署32個集羣,甚至1024個集羣,一個表一個數據庫一臺ip****
實踐(數據遷移)
上面方案有了,接下來是怎麼實踐了。
首先垂直拆分:垂直拆分之後就會有很多的數據庫,然後代碼裏面就要配置多個數據源,然後根據要求去不同的數據源拉取數據了
然後講講水平拆分:
加入有一張微博表:
create table weibo (
id int primary key auto_increment comment '主鍵',
user_id int comment '發微博的用戶id',
create_at datetime comment '創建時間',
...其他字段
) comment '微博';
單庫情況下查詢當前最新20條微博的SQL語句爲:
select * from weibo order by create_at desc limit 20;
分庫情況下的SQL語句爲:
use db_1;
select * from weibo order by create_at desc limit 20;
use db_2;
select * from weibo order by create_at desc limit 20;
use db_3;
select * from weibo order by create_at desc limit 20;
然後你需要對這60個最新的,然後進行排序,找出個前20個最新的出來。top k問題
總而言之:水平拆分會把業務變得非常複雜,能用垂直拆分解決就儘量用垂直拆分,不要用水平拆分。儘量使用對業務影響較小的讀寫分離,垂直分庫等方案
然後還有一點是,既然在不同的數據庫中,那麼id可能會相同,所以就不要用自增了。