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