原文出處:http://weibo.com/p/1001643874615465508614
作者:畢建坤@bijiankun
微博平臺研發(fā)作為微博的底層數(shù)據(jù)及業(yè)務(wù)支撐部門,已經(jīng)經(jīng)歷了5年的發(fā)展歷程。伴隨著從數(shù)據(jù)及業(yè)務(wù)暴發(fā)式增長,我們在海量數(shù)據(jù)存儲方面遭遇了諸多挑戰(zhàn),與此同時也伴隨著豐富經(jīng)驗的積累。
? ?本次新兵訓(xùn)練營,受眾在于應(yīng)屆畢業(yè)生,目的在于讓新同學(xué)系統(tǒng)化并且有針對性的了解平臺的核心技術(shù)及核心業(yè)務(wù),以使新同學(xué)在新兵訓(xùn)練營結(jié)束后,能夠?qū)ζ脚_的底層架構(gòu)與業(yè)務(wù)有一定的了解。
? ?本文主要面向新同學(xué)介紹平臺的核心技術(shù)之一——海量數(shù)據(jù)存儲,主要介紹在海量數(shù)據(jù)存儲在大規(guī)模分布式系統(tǒng)下的架構(gòu)變遷與設(shè)計。
課程大綱:
1. ?了解存儲服務(wù)概況,以及RDBMS及NoSQL的差異
2. ?理解MySQL、Redis、HBase基本實現(xiàn)機制、特性、適用場景
3. ?理解幾種存儲產(chǎn)品的大規(guī)模分布式服務(wù)方案
4. ?學(xué)會使用平臺的MySQL、Redis?client組件
5. ?理解對于MySQL、Redis分布式系統(tǒng)設(shè)計想要注意的問題
6. ?了解平臺幾種典型案例
7. ?理解幾種存儲產(chǎn)品在平臺的定制修改與名詞術(shù)語
1. ?關(guān)系型數(shù)據(jù)庫是基于實體關(guān)系模型(Entity-Relationship Model)的數(shù)據(jù)服務(wù),具備以下特點。
適合存儲結(jié)構(gòu)化數(shù)據(jù)
查詢語言SQL,insert delete update select
主流關(guān)系型數(shù)據(jù)庫多是持久化存儲系統(tǒng),系統(tǒng)性能與機器性能相關(guān)性較大
幾類主流的 關(guān)系型數(shù)據(jù)庫
MySQL
Oracle
DB2
性能
局限于服務(wù)器性能,與其是磁盤性能
局限于數(shù)據(jù)復(fù)雜度
? ? 大型互聯(lián)網(wǎng)服務(wù)大多采用MySQL進行作為關(guān)系型數(shù)據(jù)庫,微博平臺的核心業(yè)務(wù)(如微博內(nèi)容用戶微博列表)也同樣如此
?? ? ? ?本次培訓(xùn)也會著重介紹MySQL及其分布式架構(gòu)方案。
2. ?NoSQL(Not only SQL)數(shù)據(jù)庫,泛指非關(guān)系型的數(shù)據(jù)庫,興起的契機在于傳統(tǒng)關(guān)系型數(shù)據(jù)庫應(yīng)對大規(guī)模、高并發(fā)的能力有限,而NoSQL的普遍性能優(yōu)勢能夠彌補關(guān)系型數(shù)據(jù)庫在這方面的不足
存儲非結(jié)構(gòu)化數(shù)據(jù)、半結(jié)構(gòu)化數(shù)據(jù)
? ? 業(yè)界使用的NoSQL多為內(nèi)存集中型服務(wù),受限于I/O及網(wǎng)絡(luò),通常請求響應(yīng)時間在毫秒級別,單機QPS在10萬級別(與數(shù)據(jù)大小及存儲復(fù)雜度相關(guān))
常見的幾類NoSQL產(chǎn)品
K-V(Memcached、Redis),這類NoSQL產(chǎn)品在互聯(lián)網(wǎng)業(yè)內(nèi)應(yīng)用范圍最廣。Memcached提供具備LRU淘汰策略的K-V內(nèi)存存儲;而Redis提供支持復(fù)雜結(jié)構(gòu)(List、Hash等)的內(nèi)存及持久化存儲
Column(HBase、Cassandra),HBase是基于列式存儲的分布式數(shù)據(jù)庫集群系統(tǒng)
Document(MongoDb)
? ?web2.0時代,NoSQL產(chǎn)品在互聯(lián)網(wǎng)行業(yè)中的重要性隨著互聯(lián)網(wǎng)及移動互聯(lián)網(wǎng)的發(fā)展而與日劇增?? ? ??大型互聯(lián)網(wǎng)應(yīng)用,為應(yīng)對大規(guī)模、高并發(fā)訪問,大多都引入了NoSQL產(chǎn)品,其中Memcached、Redis以其高成熟度、高性能、高穩(wěn)定性而被廣泛使用。微博平臺也具備千臺規(guī)模的NoSQL集群,微博核心的Feed業(yè)務(wù)、關(guān)系業(yè)務(wù)也都依賴Memcached及Redis提供高性能服務(wù)
??本次培訓(xùn),會著重介紹Redis及其分布式架構(gòu)
微博平臺核心業(yè)務(wù)的數(shù)據(jù)都存儲在MySQL上,目前具備千臺規(guī)模的集群,單個核心業(yè)務(wù)數(shù)據(jù)突破千億級,單個核心業(yè)務(wù)QPS峰值可達10萬級每秒,寫入也是萬級每秒。
在海量數(shù)據(jù)并且數(shù)據(jù)量持續(xù)增長的景下,在如何設(shè)計滿足 高并發(fā)(w/r)、低延時(10ms級別)、高可用性(99.99%)的分布式MySQL系統(tǒng)方面,我們已經(jīng)具備充足的經(jīng)驗并且依然在持續(xù)攻堅這一問題,而我們的課程也會著重介紹海量數(shù)據(jù)存儲之MySQL。
1. ?MySQL簡介
MySQL是一個關(guān)系型數(shù)據(jù)庫系統(tǒng)RDBMS
使用SQL作為查詢語言
開源
存儲引擎
Innodb?支持事務(wù)、行鎖,寫入性能稍差
MyIsam?不支持事務(wù),讀寫性能略好
滿足ACID特性
主鍵、唯一鍵、外鍵(大規(guī)模系統(tǒng)一般不用)
Transaction,事務(wù)即一系列操作,要么完全地執(zhí)行,要么完全地不執(zhí)行
服務(wù)、端口、實例,都是指 服務(wù)端啟動的一個MySQL數(shù)據(jù)庫
性能
隨著磁盤性能升高,讀寫性能也逐步升高,但成本也隨之增加
數(shù)據(jù)庫的寫入性能:寫入tps隨著并發(fā)量增加而增加,但上升到一定瓶頸,增速放緩至并發(fā)數(shù)臨界點后 tps會急劇下滑
思考:如果對性能有更高(超出上述三種存儲介質(zhì)并發(fā)量級)的要求怎么辦?
定制存儲:針對服務(wù)特點,定制存儲,定制更適合自己業(yè)務(wù)場景的存儲產(chǎn)品。然而一般業(yè)界成熟產(chǎn)品為考慮通用性而會犧牲部分性能
2. ?從單機到集群的架構(gòu)變遷
業(yè)務(wù)上線初期,web服務(wù)規(guī)模較小,一般具備以下特點
服務(wù)原型時期,用戶基數(shù)小,多種業(yè)務(wù)公用資源,日均寫入百萬級別,讀取千萬級別
數(shù)據(jù)規(guī)模小,單機性能能夠滿足需求
用戶規(guī)模小,開發(fā)重心偏向迭代速度
考慮到上述小型業(yè)務(wù)特點,為節(jié)約資源成本及開發(fā)成本,可以采用多個業(yè)務(wù)混合部署形式
當(dāng)用戶增多,數(shù)據(jù)量、訪問量升高(2倍以下),數(shù)據(jù)庫壓力較大,怎樣在有限程度提高MySQL吞吐量呢?
SQL優(yōu)化
壓力還在有限的范圍內(nèi)增長,通過簡單、低成本優(yōu)化,可以一定成都上提高有限的服務(wù)性能
業(yè)務(wù)持續(xù)發(fā)展,讀取性能出現(xiàn)瓶頸&&各業(yè)務(wù)互相影響,多個業(yè)務(wù)出 ? ? ?現(xiàn)資源搶占,如何快速解決業(yè)務(wù)搶占問題以提高服務(wù)性能?
垂直拆分——按業(yè)務(wù)進行數(shù)據(jù)拆分
?? ? ? ?按業(yè)務(wù)進行拆分,以使業(yè)務(wù)隔離,timeline的壓力增加,不會影響content數(shù)據(jù)庫服務(wù)性能;進行拆分后,資源增加,服務(wù)性能也相應(yīng)提升。
隨著業(yè)務(wù)的繼續(xù)發(fā)展,讀取性能出現(xiàn)瓶頸,讀寫互相影響,如何確保讀請求量的增加,不要影響寫入性能?相反寫入請求量增加如何確保不影響讀取性能?(寫入性能出現(xiàn)問題會造成數(shù)據(jù)丟失)
讀寫分離,寫入僅寫master,master與slave自動同步;讀取僅以slave作為來源
?? ? ? ?讀寫分離后,slave僅專注于承擔(dān)讀請求,讀取性能得到優(yōu)化;同里獨立的master服務(wù)的寫入性能也得到優(yōu)化。
一臺/一對M-S服務(wù)器性能終歸是很有限的,當(dāng)單實例服務(wù)性能無法承載線上的請求量時,如何進行優(yōu)化?
升級為一主多從架構(gòu)
一個master承載所有寫入請求,理論上master性能不變
多個slave分擔(dān)讀取請求,讀取性能提升n倍
隨著業(yè)務(wù)量的增長,服務(wù)出現(xiàn)如下變化:
數(shù)據(jù)量增長,意味著原本的存儲空間不足
寫入量增長,意味著master寫入性能存在瓶頸
如何優(yōu)化以解決上述問題?
水平拆分
?? ? ? ?業(yè)務(wù)經(jīng)歷數(shù)據(jù)量的增長、讀寫請求量的增長,數(shù)據(jù)庫服務(wù)已經(jīng)演進為分布式架構(gòu),一個業(yè)務(wù)的數(shù)據(jù),怎樣合理的分布到上述復(fù)雜的分布式數(shù)據(jù)庫是下一個需要解決的問題
3. ?如何基于上述演進到最后的架構(gòu)進行數(shù)據(jù)庫設(shè)計呢?
分布式數(shù)據(jù)庫設(shè)計
hash拆分方式,既按hash規(guī)則,將數(shù)據(jù)讀寫請求分散到多個實例上,見上述水平拆分示意圖
時間拆分方式,基于確定好的時間劃分規(guī)則,將數(shù)據(jù)按時間段分散存儲再多個實例中
數(shù)據(jù)分布到一個分布式數(shù)據(jù)庫內(nèi),一個實例存儲1/n的數(shù)據(jù),一個實例只需要一個數(shù)據(jù)庫就能夠滿足功能需求。
經(jīng)歷幾年的發(fā)展,數(shù)據(jù)規(guī)模會成倍增長,當(dāng)需要再次水平擴容(4太→8臺),需要通過程序,將數(shù)據(jù)一分為二,數(shù)據(jù)遷移成本較高,需要開發(fā)人員介入。
如果在數(shù)據(jù)庫設(shè)計時,一個就預(yù)先建好2個數(shù)據(jù)庫 ,每個數(shù)據(jù)庫存儲1/n/2的數(shù)據(jù),需要水平擴容時,即可完整遷移一個數(shù)據(jù)庫,而無需開發(fā)人員干預(yù)。
在一個數(shù)據(jù)庫實例上,建立的多個數(shù)據(jù)庫,稱為邏輯庫。
邏輯庫設(shè)計
邏輯庫是相對與物理庫而言的概念:物理庫只數(shù)據(jù)庫服務(wù)的實例;邏輯庫指在一個數(shù)據(jù)庫實例上創(chuàng)建的多個database
定義邏輯庫的目的是便于擴容。假如4臺數(shù)據(jù)庫服務(wù)器,每臺上的物理庫包含8個邏輯庫,當(dāng)系統(tǒng)出現(xiàn)容量、寫入量瓶頸時,可以新增一倍即4臺服務(wù)器,直接以同步方式同步數(shù)據(jù)庫,而不需要單獨編寫應(yīng)用程序利用進行導(dǎo)入
4. ?基于上述分布式數(shù)據(jù)庫下的表拆分設(shè)計方式
hash拆分方式:按hash規(guī)則將一個數(shù)據(jù)庫的數(shù)據(jù),分散hash到多張表中
適合數(shù)據(jù)規(guī)模有限的數(shù)據(jù)集
結(jié)合數(shù)據(jù)庫的hash模型如圖:
按時間拆分方式,按時間規(guī)則將同一時段的數(shù)據(jù)存儲在一張表,多個時段時間存儲在多張表。例如按月劃分,每個月表存儲一個月的數(shù)據(jù),如果需要獲取全部數(shù)據(jù)需要跨越多個月表
適合存儲增速較快的數(shù)據(jù)集
結(jié)合數(shù)據(jù)庫的hash模型如圖:
思考一個問題:如何能夠快速定位,一個人的第1000條到1100條數(shù)據(jù)呢?
二級索引快速定位(一級)索引位置
描述數(shù)據(jù)在以及索引中的分布狀況
用于快速定位/縮小查詢范圍
一般情況字段列表:uid, date_time, min_id, count
?? 5. ?當(dāng)一臺服務(wù)器宕機怎么辦?
Slave(一主多從)宕機?
剩余健康Slave無風(fēng)險,則無需緊急操作,例行修復(fù)
切換流量到容災(zāi)機房(如果具備容災(zāi)機房)
緊急擴容[優(yōu)先]、重啟、替換
Master宕機?
由于master數(shù)據(jù)的唯一性,致使master出現(xiàn)異常會直接造成數(shù)據(jù)寫入失敗
快速下線master
下線一臺salve的讀服務(wù)(如果slave性能有風(fēng)險,則同時快速擴容)
提升slave為master
?? 6. ?如此復(fù)雜的分布式數(shù)據(jù)庫+數(shù)據(jù)庫拆分+數(shù)據(jù)表拆分,client端如何便捷操作呢?
??多數(shù)使用分布式數(shù)據(jù)庫服務(wù)的團隊,都有各自實現(xiàn)的數(shù)據(jù)庫Client組件,微博平臺采用如下幾個層級的組建來進行分布式數(shù)據(jù)庫操作
? ?
7. ?注意事項
MySQL設(shè)計應(yīng)該注意的問題
表字符集選擇UTF8
存儲引擎使用InnoDB
使用Varchar/Varbinary存儲變長字符串
不在數(shù)據(jù)庫中存儲圖片、文件等
每張表數(shù)據(jù)量控制在20000W以下
MySQL查詢應(yīng)該遇到的問題
避免使用存儲過程、觸發(fā)器、函數(shù)等
讓數(shù)據(jù)庫做最擅長的事
避免使用大表的JOIN
MySQL最擅長的是單表的主鍵/索引查詢
避免在數(shù)據(jù)庫中進行數(shù)學(xué)運算
MySQL不擅長數(shù)學(xué)運算
減少與數(shù)據(jù)庫的交互次數(shù)
select條件查詢要利用索引
?? 8. ?MySQL練習(xí)題
設(shè)計一個每秒2000qps,1億條數(shù)據(jù)的用戶基本信息存儲數(shù)據(jù)庫。完成數(shù)據(jù)庫設(shè)計,數(shù)據(jù)庫搭建,web寫入查詢服務(wù)搭建。
定義用戶信息結(jié)構(gòu):uid,name,age,gender
給定2個mysql實例,每個實例創(chuàng)建2個數(shù)據(jù)庫
每個數(shù)據(jù)庫創(chuàng)建2長表
??微博作為web2.0時代具備代表性的SNS服務(wù),具備龐大的用戶群體和億級的活躍用戶,同時也承擔(dān)著高并發(fā)、低延遲的服務(wù)性能壓力。
??Redis作為NoSQL系列的一個典型應(yīng)用,以其高成熟度、高可用性、高性能而被用來解決web2.0時代關(guān)系型數(shù)據(jù)庫性能瓶頸問題。例如微博的計數(shù)服務(wù)的請求量以達到百萬級/s,數(shù)以百計的關(guān)系型數(shù)據(jù)庫才能應(yīng)對如此高的QPS,而且請求耗時較高且波動較大;然而使用Redis這種NoSQL產(chǎn)品,僅僅需要10臺級別的集群即可應(yīng)對,平均請求耗時5ms以下。
??這一章節(jié),為大家介紹Redis以及其大規(guī)模集群架構(gòu)。
1. ?Redis簡介
Redis是一個支持內(nèi)存存儲及持久化存儲的K-V存儲系統(tǒng)
支持復(fù)雜數(shù)據(jù)結(jié)構(gòu),相比與Memcached僅支持簡單的key-value存儲,Redis原生支持幾類常用的存儲結(jié)構(gòu),例如
hash:存儲哈希結(jié)構(gòu)數(shù)據(jù)
單線程
高性能,避免過多考慮并發(fā)、鎖、上下文切換
數(shù)據(jù)一致性好,例如對一個計數(shù)的并發(fā)操作,不會有‘讀者寫者’問題
單線程無法利用多核,單可以通過啟動多個實例方式,充分利用多核
原生支持Master-Slave
過期機制
被動過期——client訪問key時,判斷過期時間選擇是否過期
主動過期——默認使用valatile-lru
volatile-lru:從已設(shè)置過期時間的數(shù)據(jù)集中挑選最近最少使用的數(shù)據(jù)淘汰
volatile-ttl:從已設(shè)置過期時間的數(shù)據(jù)集中挑選將要過期的數(shù)據(jù)淘汰
volatile-random:從已設(shè)置過期時間的數(shù)據(jù)集中任意選擇數(shù)據(jù)淘汰
allkeys-lru:從全部數(shù)據(jù)集中挑選最近最少使用的數(shù)據(jù)淘汰
Redis的字典表結(jié)構(gòu)
Key字典表hash table結(jié)構(gòu),有hash結(jié)構(gòu)就意味著需要按需進行rehash,rehash的時間段內(nèi),對內(nèi)存是有成倍開銷的
Value結(jié)構(gòu),存儲Key對應(yīng)的value
Expire表結(jié)構(gòu),存儲key的過期時間
額外開銷60B+
持久化方式
AOF
與MC的差異
平臺的定制CounterService
修改hash table為,增量擴展式的hash tables,例如每1億個key存儲在一個table中,數(shù)據(jù)超過1億(或者一個臨界比例)則開辟下一個1億空間的table
2. ?Redis的主要數(shù)據(jù)結(jié)構(gòu)
String (key-value)
Hash (key-field-value)
List(key-values)
Set(key-members)
3. ?Redis的分布式部署方案是怎樣的?與MySQL有什么異同
Reids由于其M-S特性與MySQL類似,因此分布式部署方案同MySQL相當(dāng)
單實例——小型業(yè)務(wù) or 業(yè)務(wù)初期
主從——HA、讀寫分離
一主多從——讀取性能出現(xiàn)瓶頸
數(shù)據(jù)水平拆分——容量不足|寫入性能瓶頸
常用的分布式部署方案
?? 4. ?分布式Redis架構(gòu)如何實現(xiàn)高可用(HA)?
采用M-S高可用方案,原因也式由于其Master-Slave的特性
5. ?基本容量規(guī)劃
空間=key數(shù)量*單條占用(K-V占用+額外空間) 用戶空間=5億用戶*200B(平均)=100G 微博計數(shù)器=(500億+預(yù)期2年新增300億)*10B=800G
6. ?CounterService
????微博具備龐大的數(shù)據(jù)基數(shù),因此所需要存儲的數(shù)據(jù)量級也極其龐大
??例如微博計數(shù)器,具有百億條紀(jì)錄,全部存儲在Redis中,需要T級別的空間,成本過高
因此我們對Redis進行定制化改造,以使其適合多數(shù)數(shù)據(jù)小,大小有固定限制的數(shù)據(jù)
優(yōu)化存儲空間
采用分段哈希桶的形式,進行存儲,避免rehash (分段存儲要求key為遞增序)
空間占用優(yōu)化效果
key:8B
7. ?如何支持上述分布式架構(gòu)下的client訪問?(redis3.0+支持Redis Cluster)
Reids具有多個開源的client支持,我們所使用的是Jedis
Jedis除了提供client外,還提供了操作封裝以及M-S組件
我們所使用的Redis系列組件如下:
?? 8. ?Redis練習(xí)題
使用Redis,實現(xiàn)用戶受到的贊列表及贊計數(shù)功能
使用測試環(huán)境,啟動兩個Redis實例
使用Redis存儲用戶受到的贊列表[{uid, time}..]及贊計數(shù)uid-count
1. ?Memcache當(dāng)容量到達瓶頸會 截取LRU鏈以釋放空間。上文介紹過Redis的key過期機制,思考以下幾個問題:
Redis滿了會發(fā)生什么?如何避免發(fā)生上述問題呢?
2. ?MySQL與Redis各自適合什么樣的場景?
數(shù)據(jù)冷熱?
數(shù)據(jù)大???
數(shù)據(jù)量級?
數(shù)據(jù)增長速度?
是否持久化?
訪問量(read/write)?
請求性能要求?
新兵訓(xùn)練營簡介
微博平臺新兵訓(xùn)練營活動是微博平臺內(nèi)部組織的針對新入職同學(xué)的團隊融入培訓(xùn)課程,目標(biāo)是團隊融入,包括人的融入,氛圍融入,技術(shù)融入。當(dāng)前已經(jīng)進行4期活動,很多學(xué)員迅速成長為平臺技術(shù)骨干。
微博平臺是非常注重團隊成員融入與成長的團隊,在這里有人幫你融入,有人和你一起成長,也歡迎小伙伴們加入微博平臺,歡迎私信咨詢。
講師簡介
畢建坤,@bijiankun?微博平臺及大數(shù)據(jù)部——平臺研發(fā)系統(tǒng)研發(fā)工程師,2012年7月畢業(yè)于哈爾濱理工大學(xué),校招入職微博工作至今,先后負責(zé)微博Feed、贊、評論等底層服務(wù)研發(fā)以及方案評審等工作。聚焦大規(guī)模系統(tǒng)的架構(gòu)設(shè)計與優(yōu)化,以及大規(guī)模系統(tǒng)下的服務(wù)穩(wěn)定性保障。新兵訓(xùn)練營第一期學(xué)員。
更多建議: