大數據量下,58同城mysql實踐

1、基本概念mysql

大數據量下,搞mysql,如下概念須要先達成一致web

1)單庫,很少說了,就是一個庫sql


2)分片(sharding),水平拆分,用於解決擴展性問題
數據庫


3)複製(replication)與分組(group),用於解決可用性問題
緩存


4)分片+分組,這是大數據量下,mysql架構的實際狀況
架構

 

2、大數據量下,mysql常見問題及解決思路函數

1)常見問題性能

如何保證可用性?大數據

各色各異的讀寫比,怎麼辦?優化

如何作無縫倒庫,加字段,擴容?

數據量大,怎麼解決?


2)解決思路

2.1)可用性解決思路:複製

讀庫可用性

從庫複製多個,例如:1主2從

從庫掛了讀主庫,例如:1主1從

寫庫可用性

雙主模式

「雙主」當「主從」用

2.2)讀寫比解決思路-針對特性作設計

讀多些少場景:提高讀性能,3種常見方案:

a)新建索引提升讀性能,什麼小技巧?

b)讀寫分離,增長從庫擴展讀性能

c)增長緩存來擴展讀性能

a)b)c)方案存在什麼問題?

如何解決這些問題?

讀寫相近場景:不要使用緩存,考慮水平切分

寫多讀少場景:不要使用緩存,考慮水平切分

2.3)無縫倒庫[擴容,增長字段,數據遷移]

追日誌方案

a)記錄寫日誌


b)倒庫

c)倒庫完畢

d)追日誌

e)追日誌完畢+數據校驗

f)切庫

雙寫方案


a)服務雙寫

b)倒庫

c)倒庫完畢+數據校驗

d)切庫

2.4)數據量大解決思路:拆庫

 

3、58同城數據庫拆庫實戰

四類場景覆蓋99%拆庫業務

a)「單key」場景,用戶庫如何拆分: user(uid, XXOO)

b)「1對多」場景,帖子庫如何拆分: tiezi(tiduid, XXOO)

c)「多對多」場景,好友庫如何拆分: friend(uidfriend_uid, XXOO)

d)「多key」場景,訂單庫如何拆分:order(oidbuyer_idseller_id, XXOO)

 

1)用戶庫如何拆分

用戶庫,10億數據量

user(uid, uname, passwd, age, sex, create_time);

業務需求以下

a)1%登陸請求 => where uname=XXX and passwd=XXX

b)99%查詢請求 => where uid=XXX

結論:「單key」場景使用「單key」拆庫

 

2)帖子庫如何拆分

帖子庫,15億數據量

tiezi(tiduid, title, content, time);

業務需求以下

a)查詢帖子詳情(90%請求)

SELECT * FROM tiezi WHERE tid=$tid

b)查詢用戶全部發帖(10%請求)

SELECT * FROM tiezi WHERE uid=$uid

結論:「1對多」場景使用「1」分庫,例如帖子庫1個uid對應多個tid,則使用uid分庫,tid生成時加入分庫標記

 

3)好友庫如何拆分

好友庫,1億數據量

friend(uidfriend_uid, nick, memo, XXOO);

業務需求以下

a)查詢個人好友(50%請求) => 用於界面展現

SELECT friend_uid FROM friend WHERE uid=$my_uid

b)查詢加我爲好友的用戶(50%請求) => 用戶反向通知

SELECT uid FROM friend WHERE friend_uid=$my_uid

結論:「多對多」場景,使用數據冗餘方案,多份數據使用多種分庫手段

 

4)訂單庫如何拆分

訂單庫,10億數據量

order(oidbuyer_idseller_id, order_info, XXOO);

業務需求以下

a)查詢訂單信息(80%請求)

SELECT * FROM order WHERE oid=$oid

b)查詢我買的東東(19%請求)

SELECT * FROM order WHERE buyer_id=$my_uid

c)查詢我賣出的東東(1%請求)

SELECT * FROM order WHERE seller_id=$my_uid

結論:「多key」場景通常有兩種方案

a)方案一,使用2和3綜合的方案

b)方案二,1%的請求採用多庫查詢

 

4、分庫後業務實戰

分庫後出現的問題:單庫時mysql的SQL功能再也不支持了

 

1)海量數據下,mysql的SQL怎麼玩

不會這麼玩

a)各類聯合查詢

b)子查詢

c)觸發器

d)用戶自定義函數

e)「事務」都用的不多

緣由:對數據庫性能影響極大

 

2)分庫後,IN查詢怎麼玩

用戶庫如何進行uid的IN查詢

user(uid, uname, passwd, age, sex, photo, create_time, …);

Partition key:uid

查詢需求:IN查詢:WHERE uid IN(1,2,3,4,5,6)


解決方案:服務作MR

方案一:直接分發

方案二:拼裝成不一樣SQL,定位不一樣的庫

 

3)分庫後,非Partition key的查詢怎麼玩

方案一:業務方不關心數據來自哪一個庫,能夠只定位一個庫

例如:有頭像的用戶查詢

 

方案二:結果集只有一條數據,業務層作分發,只有一條記錄返回就返回

例如:用戶登陸時,使用userName和passwd的查詢

 

4)分庫後,誇庫分頁怎麼玩?

問題的提出與抽象:ORDER BY xxx OFFSET xxx LIMIT xxx

a)按時間排序

b)每頁100條記錄

c)取第100頁的記錄

 

單機方案

ORDER BY time OFFSET 10000 LIMIT 100

 

分庫後的難題:如何確認全局偏移量

 

分庫後傳統解決方案,查詢改寫+內存排序

a)ORDER BY time OFFSET 0 LIMIT 10000+100

b)對20200條記錄進行排序

c)返回第10000至10100條記錄

 

優化方案一:增長輔助id,以減小查詢量

a)技術上,引入特殊id,做爲查詢條件(或者帶入上一頁的排序條件)

b)業務上,儘可能禁止跨頁查詢

單庫狀況


a)第一頁,直接查

b)獲得第一頁的max(id)=123(通常是最後一條記錄)

c)第二頁,帶上id>123查詢:WHERE id>123 LIMIT 100

多庫狀況

a)將WHERE id>xxx LIMIT 100分發

b)將300條結果排序

c)返回前100條

優勢:避免了全局排序,只對小量記錄進行排序

 

優化方案二:模糊查詢

a)業務上:禁止查詢XX頁以後的數據

b)業務上:容許模糊返回 => 第100頁數據的精確性真這麼重要麼?

 

優化方案三:終極方案,查詢改寫與兩段查詢

方案一和方案二在業務上都有所折衷,前者不容許跨頁查詢,後者數據精度有損失,解決誇庫分頁問題的終極方案是,將order by + offset + limit進行查詢改寫,分兩段查詢。

因爲wot2015大會時間優先,這個方案待到dtcc2015數據庫大會上,58同城的架構師再與你們細講

 

5、總結

《概念》

單庫、分片、複製、分組

 

《常見問題及解決思路》

1)可用性,解決思路是冗餘(複製)

2)讀寫比

2.1)讀多些少:用從庫,緩存,索引來提升讀性能

2.2)業務層控制強制讀主來解決從庫不一致問題

2.3)雙淘汰來解決緩存不一致問題

2.4)讀寫相近,寫多讀少:不要使用緩存,該怎麼整怎麼整

3)無縫導庫

3.1)寫日誌追數據

3.2)雙寫

4)數據量大,解決思路是分片(拆庫)

 

《四大類拆庫思路》

1)用戶庫,「單key」場景使用「單key」拆庫

2)帖子庫,「1對多」場景使用「1」分庫,例如帖子庫1個uid對應多個tid,則使用uid分庫,tid生成時加入分庫標記

3)好友庫,「多對多」場景,使用數據冗餘方案,多份數據使用多種分庫手段

4)訂單庫,「多key」場景通常有兩種方案

4.1)方案一,使用2和3綜合的方案

4.2)方案二,1%的請求採用多庫查詢

 

《拆庫後業務實戰》

1)不這麼玩:聯合查詢、子查詢、觸發器、用戶自定義函數、誇庫事務

2)IN查詢怎麼玩

2.1)分發MR

2.2)拼裝成不一樣SQL語句

3)非partition key查詢怎麼玩

3.1)定位一個庫

3.2)分發MR

4)誇庫分頁怎麼玩

4.1)修改sql語句,服務內排序

4.2)引入特殊id,減小返回數量

4.3)業務優化,禁止跨頁查詢,容許模糊查詢

4.4)終極方案,dtcc2015數據庫大會揭曉

相關文章
相關標籤/搜索