這裏所說的五件套是指關係型數據庫、索引型數據庫、時序型數據庫、文檔型數據庫和緩存型數據庫。
數據庫
上圖顯示了一套讀寫服務搭配這五種類型數據庫的例子:緩存
1. 這裏只是說明了咱們能夠這麼來搭配這些類型的數據庫,不是說咱們全部的應用都須要用到這些類型的數據庫。數據結構
2. 同步寫服務負責第一時間把重要的數據落地和落緩存。架構
3. 異步寫服務經過監聽MQ來感知數據的變化,而後從新讀取最新的數據來把數據寫入其它次要數據源,好比文檔性數據庫和索引型數據庫,須要的話能夠在緩存中回寫一個狀態。併發
4. 由一個專門的數據查詢服務來根據需求作數據路由,根據需求和性能因素,從不一樣的數據源讀取數據。運維
5. 數據聚合服務根據需求從次要數據源進一步讀取數據以時間維度進行聚合,聚合到時間序列數據庫,供監控查詢服務查詢。異步
下面咱們來具體說說這些存儲系統。分佈式
毫無疑問,強事務性的數據寫入MySQL之類的關係型數據庫是最可靠的,搭配SSD盤的使用,關係型數據庫也很容易達到萬級的QPS。對於超大數據量加上超大併發的應用來講,單表的數據量過千萬伴隨着數萬的QPS很難以單體數據庫來支撐,咱們須要對數據表進行Sharding分片處理,把數據按照必定的維度切分到好比128個數據表,而後分散在8套甚至16套數據集羣,這樣每一臺MySQL的實例只須要承受1/8或1/16的請求壓力並且數據量更小。隨之帶來的問題是,咱們須要對應用進行改造,使之只能按照必定的查詢條件來查詢這個切片後的表,若是不帶條件或帶任意條件的話,咱們是沒法知道數據實際存儲在哪一個表哪一個實例上的。性能
這確實是一個比較麻煩的地方,咱們的查詢條件可能有十幾個,只能按照一個維度來查詢知足不了咱們的需求。一個折中的方式是咱們引入所謂的Index數據表,也就是在寫入實際的完整數據到Sharding的數據表的同時,咱們把數據表裏須要查詢的字段寫入一個專門的沒有通過Sharding處理的Index數據表,這個數據表裏存放的幾乎沒有varchar類型的數據,所有是各類bigint的各種業務ID或是tinyint類型的各類狀態,以及時間。因爲這個表很是親,雖然數據條數多可是表空間幾乎能夠在數據庫的緩存中容納,性能會高很多。對於實時性要求很是強的基於條件的查詢能夠從這個數據表來進行查詢。而Sharding後的數據只能用於按ShardKey來進行查詢。測試
Redis是最經常使用的分佈式緩存解決方案,幾乎在任何互聯網應用中都會用到,特色是:
1. 能持久化數據,可是個人觀點是緩存數據庫仍是僅僅做爲緩存的好,要可以承受丟失數據的風險,不然可能會死的比較難看。由於RDB或主從複製致使的一些事故也是層出不窮的。
2. 豐富的數據結構是必定要利用的,豐富的數據結構表明了能夠依賴豐富的API在服務端作複雜的運算,性能比反序列化取出後運算再序列化存入效率高的多。有的時候甚至能夠把這些數據結構和API組合在一塊兒碰撞出絕妙的方案以極高效的方式實現一個高性能的業務邏輯。能夠看看《Redis實戰》一書。
3. 超高的性能(固然了,配合一些集羣方案好比codis就更上一層樓了)足以抵擋任何業務請求的直接訪問,不少時候緩存的方案掛是掛在由於各類各樣的緣由穿透緩存而不是Redis檔不住。
4. 豐富的集羣和高可用方案以及各種各類實用的功能(管道、事務、Lua腳本),5.0的版本還推出了Stream特性來替代少有人關注的Disque值得關注。
因此Redis的應用也很普遍:
· 數據緩存
· 分佈式鎖
· 消息隊列
· 服務端運算
在上圖的架構中,咱們經過同步寫服務對數據庫和緩存進行雙寫,目的也就是爲了讓緩存中能有新鮮熱數據,無論是對內仍是對外這種單條數據的查詢能夠直接路由到緩存。
文檔型數據庫的表明就是耕耘多年的Mongodb,我在一些非重要業務的場景使用過Mongodb幾回,個人評價以下(最近1年多沒有碰過Mongodb,也可能評價有失偏頗):
1. 超高的寫入性能,很是不錯的讀取性能(和Redis是不能比的,性質不一樣),數據量增多後可能會有很厲害的性能衰退,不是Hbase那種無底洞型的存儲,不維護就往裏面一直堆數據進去最後的性能可能好比MySQL。
2. 由於存的是文檔,因此是弱結構的,存一些事先不能肯定的數據很是很是合適,並且之後要查的時候能夠任何加索引對須要的數據進行搜索查詢。一個很實用的場景就是做爲爬蟲的數據源,數據變化無窮並且不那麼重要,並且寫入性能很重要。
3. 不太可靠和穩定,可能會丟數據,強烈不建議做爲核心數據存儲,建議做爲一個旁路數據庫用在非關鍵的業務。好比在上圖的架構圖中,咱們可能會拿到核心數據後再從其它地方去補一些數據而後進行適當的加工,保存到Mongodb做爲一個監控數據庫或者面向後臺的數據庫來用(MEAN套件之一,能夠想象對於簡單的應用來講配合腳本語言用起來多舒服了),掛了也就掛了,沒掛的話能夠分擔不少MySQL的壓力。
4. 玩法雖然多,什麼Sharding、複製、集羣都有,但隨着數據量的增多運維多是一個大坑,極可能遇到集羣全軍覆沒沒法啓動的狀況,數據的恢復耗時很長。內存的使用至關瘋狂,對硬件的使用總感受性價比不高。
ElasticSearch做爲其表明是最近幾年的黑馬。ELK集羣各大互聯網公司都有使用,只要集羣配置得當,每秒幾十萬的寫入不是大問題,畢竟完全的分佈式化理論上能夠有無限高的寫入能力。ES的特色以下:
1. 很是豐富的查詢API,不只僅是全文索引查詢,普通的查詢API豐富多樣,組合起來能夠在服務端完成各類業務邏輯,基本上SQL+MySQL能夠實現的,ES查詢均可以實現,並且還多了更強大的全文搜索。固然,查詢的語法稍顯晦澀確定沒有SQL來的直掛。
2. 相似於Mongodb的schema-free,無需實現定義表結構。
3. 還算強大的寫入和讀取能力,固然,索引多的話寫入文檔的效率確定會下降。這也是圖中對於ES的寫入由專門的異步流程進行的緣由。
4. ES天生的分佈式配置決定了,在寫入億、十億的數據量以後,還能在至關能夠接受的時間內(好比10秒)完成一個多條件複雜查詢,對於MySQL這個量級下這樣的查詢可能須要10分鐘甚至100分鐘的時間來執行,徹底不能接受。
5. ES對嵌套型數據的查詢支持不錯,通過測試咱們傾向於把多標關聯的數據做爲一個大的嵌套的JSON拍扁了直接存入ES,好比咱們能夠把用戶我的惟獨的基本信息+充值訂單+提現訂單+投資訂單,一人一個JSON存進去,而後對於嵌套的下層JSON數據也是能夠方便的利用查詢API進行查詢。
由於這些特色,在這個架構圖上,咱們把ES也做爲了查詢服務的數據源,對於知足下面這些條件的查詢,咱們能夠走ES:
· 對數據延遲不敏感,能夠接受一段時間查不到新鮮數據
· 查詢特別複雜,或是全文搜索,不能走Sharding後的RouteKey,Index表也沒法知足需求
· 查詢的結果也不只僅是單表的數據而是比較豐富的數據,查詢數據庫須要查詢多個表屢次
索引型數據庫和文檔型數據庫的底層存儲結構是大相徑庭的,雖然如今有不少人使用ES來徹底替代Mongodb,可是我的以爲ES適合存比Mongodb更大的一個數據量,分佈式不利用起來發揮不了ES,Mongodb仍是適合中型數據非Sharding的存儲。
InfluxDb是時序型數據庫的表明。對於按照時間段進行Group By查詢的話,無論是ES仍是MySQL仍是Mongodb在API層面固然都是支持的,可是查詢效率不堪入目。所以對於諸以下面的需求首當其中能夠考慮時序型數據庫:
· 監控圖表
· 按時間維度聚合
· 查詢的時間維度能夠跨度很長
· 須要按期歸檔
若是使用傳統方案的話,咱們每每會以固定的時間維度來聚合保存數據,若是咱們要查1小時和1年的維度,都使用5秒的聚合粒度顯然不合適,咱們須要在寫入數據到時候針對不一樣的粒度進行聚合,須要必定的工做量,使用時間序列數據庫能夠少一些這樣的煩惱。並且InfluxDb之類的數據庫的性能是很是高的,寫入數據的性能堪比Redis,單節點甚至能夠承受十萬指標的寫入,基本能夠知足大部分應用場景的需求。對於一些業務指標的監控,業務事件的打點,業務數據的時間維度聚合,咱們徹底能夠考慮引入專門的時序型數據庫。
綜上所述,這裏的架構圖只是體現了幾個重要思想:
1. 使用專門的服務來作數據的寫入和讀取,方便進行路由。
2. 合理規劃好Sharding的方式,以及想好RDBMS在Sharding後的全套查詢方案。
3. 數據的寫入區分主要數據源的同步寫入和次要數據源的異步寫入,讓主流程更快。
4. 合理利用不一樣數據源的特性,組合使用發揮所長,避免所短。
5. 數據的加工能夠是一個層級的關係,能夠由專門業務中間件來進行數據加工。
6. RDBMS之外的數據庫若是打算做爲主核心存儲引擎的話千萬慎重思考。
7. 採用豐富的數據源意味着維護成本的增多,數據不一樣步的問題在所不免,須要考慮一下咱們是否能夠接受必定層度的數據不一致。