1. 程式人生 > >建立一套MySQL及Redis搭建統一的KV儲存服務

建立一套MySQL及Redis搭建統一的KV儲存服務

一、MySQL+Redis 常用部署方式

1.1  拓撲


1.2  特點

業務層通過雙寫同時寫MySQL及Redis。讀通常在Redis,若讀取不到,則從MySQL讀取,然後將資料同步到Redis,Redis通常設定expire或者預設LRU進行資料淘汰。

這種使用方式會有如下問題:

1)MySQL及Redis存在資料不一致風險,尤其是長時間執行的系統

2)業務層需要處理MySQL sql schema與Redis kv資料結構上的邏輯差異

3)無統一運維

4)無法方便擴容/縮容

二、KV 化的儲存使用理念

2.1  MySQL Is great NoSQL

參考文件:

http://www.aviransplace.com/2015/08/12/Mysql-is-a-great-nosql/

為什麼要用MySQL:

“在可擴充套件系統構建時,一個很重要的考量是使用的技術是否成熟,選擇成熟的技術意味著出錯時能夠迅速恢復。當然,開發者也可以在專案中使用最新最牛的NoSQL資料庫,而這個資料庫在理論上也可以良好地執行,然而在生產環境中出現了問題恢復需要多久?技術上已有的知識和經驗積累對於問題緩解至關重要,當然這個積累也包括了Google可以搜尋到的內容。

相比之下,關係型資料庫已經存在了超過四十年,業界對於關係型資料庫的維護也積累了大量的經驗。基於這些考慮,在新專案做技術選型時通常會選擇Mysql,而不是NoSQL資料庫,除非NoSQL真的有非常非常明顯的優勢。”

2.2  KV理念

對於億級規模的資料儲存,尤其是涉及到水平拆分跨機分庫分表的情況下,線上對資料庫的訪問只能做的越簡單越好,group by/order by/分頁/通用join/事務等等的支援 在這個量級下的MySQL系統都是不合適的。

基本上目前所有的類proxy的MySQL方案真正上規模線上應用只能使用按拆分鍵進行讀寫操作,實際上也是一個用拆分鍵做的一個kv系統。

若想使用複雜的sql處理,最合理的部署方案是將Mysqlbinlog流水同步服務抽象出來,通過實時同步到OLAP類的系統進行處理。

所以面向海量儲存服務,MySQL從一開始就設計為一個KV系統是可行的。value使用mediumblob儲存xml/json/protobuf/thrift格式化資料序列化之後的資料。

2.3  MySQL KV化的使用方式

1、用MySQL原來的主鍵或者索引鍵當做key

2、其他所有的非主鍵非索引鍵,全部包裝到value裡面,value使用mediumblob儲存xml/json/protobuf/thrift格式化資料序列化之後的資料。

3、資料讀寫操作,均基於key一整行資料做讀寫,由業務層對裡面value的結構做解析及對內部結構做增刪改差,而不用變更 MySQL 本身的schema.

2.4  不適用場景

1、資料量和訪問量不大並且業務邏輯依賴 MySQL 資料庫進行處理的業務場景

2、涉及到多表join等的處理

對於此限制,也可以通過將關聯表加工成基於關聯條件的一張寬表進行KV化。

3、涉及到事務等的處理。

三、將MySQL+Redis設計為統一的KV儲存服務

3.1  目標

1)業務層通過統一方式訪問MySQL及Redis,不再使用MySQL客戶端及Redis客戶端訪問

2)MySQL叢集化/Redis叢集化部署

3)將業務雙寫改為MySQL到Redis底層binlog資料同步方式完成同步

4)異構資料儲存支援最終一致性資料讀寫服務

5)支援儲存層面擴容縮容、failover且業務無感知

6)單機群日百億次QPS/TPS支援(大類業務適度拆分到不同叢集中)

3.2  最終實現

基於MySQL+Redis的統一儲存服務(UniStore) =

MySQL跨機分庫分表叢集

+ Redis叢集

+ MySQL->Redis實時資料同步服務

+ 統一的對外資料訪問介面

+ 內在的完整運維支援系統(支援線上擴容/縮容、failover等)

3.3  架構圖


3.4  架構說明-將儲存設計為一種服務

1、將MySQL+Redis做成統一KV儲存服務

2、通過acc proxy提供統一的資料訪問介面,通過統一協議支援跨語言資料訪問

訪問協議(自定義協議,protobuf協議,thrift協議等)

3、MySQL cluster支援跨機的分庫分表,schemaless設計,所有業務表KV化設計

4、Redis cluster支援跨機的例項拆分

5、Sync資料同步服務提供統一的Mysql到Redis 跨IDC/不跨IDC資料同步服務,小於100ms延時

6、整個系統不涉及到分散式事務處理

3.5  三種部署方式

1、純MySQL叢集部署

此種部署方式等同於其他MySQL proxy跨機分庫分表方案,讀寫均在MySQL

2、純Redis叢集部署

此種部署方式等同於其他Redis proxy跨機分庫分表方案,讀寫均在Redis

3、MySQL+Redis異構部署

寫在MySQL,讀可以從MySQL讀或者Redis讀,取決於業務對最新資料的讀取要求。

3.6  介面說明

1、int get(int appid, string key,string& value)

Redis讀操作專用

2、int get_with_version(int appid,string key, string& value, int64& version)

MySQL 讀操作專用,自帶版本號,防止寫覆蓋

3、int set(int appid, string key,string value, int64 version)

通過appid區分 MySQL 還是Redis,均支援寫操作

4、int delete(int appid, string key)

通過appid區分 MySQL 還是Redis, 不支援批量刪除

5、int multiget(int appid,vector<string> keys, map<string, string>& key_value_pairs)

支援批量讀操作,內部的資料路由及資料合併不用關心

6、intmultiset(int appid, map<string, string>& key_value_pairs)

不建議支援,涉及到跨機事務問題,無法保證ACID

7、int Redis_op(string cmd, ……)

Redis其他原生介面封裝(incr/expire/list/setnx等)

四、Cluster Manager服務

4.1  Cluster Manager 是一個service

cluster manager主要由如下幾種功能

1)MySQL/Redis分片路由資訊的管理

1、 MySQL 分庫分表路由資訊

2、Redis Slot路由資訊

3、路由資訊變更管理

2)Redis例項的探活及Redis擴容及縮容資料的遷移

比如連續3次,每次間隔30sRedis ping失敗,認為例項掛掉,發出報警或者自動切換

3)Cluster manager不建議參與Mysql group主備層面的管理

MySQL 主備層面的叢集管理方案:

1、MHA+VIP (網際網路公司最常用)

2、微信phxsql系統:https://github.com/tencent-wechat/phxsql   金融級可靠性

五、 MySQL 叢集方案

5.1  架構圖


5.2  設計原則

1)統一的schemaless表結構


2)跨機的資料分佈

支援將單邏輯表水平拆分到多個Mysql伺服器中

3)其他說明

1、資料儲存可靠性高,所有業務資料通過序列化儲存到value列

2、每行資料自帶版本號,業務通過cas方式防止業務層多例項同時寫造成寫覆蓋

全域性唯一版本號實現:本機微秒時間戳+server_id+proccess_id

3、固定百庫百表/百庫十表的資料拆分方式,多機跨Mysql例項部署

5.3  路由策略

1) 一致性hash


2) 路由計算演算法

crc32/md5/基於字串的各類hash演算法

3) 路由資訊格式

CREATETABLE `Mysql_shard_info` (

`appid` int(32) NOT NULL,

`begin` int(32) NOT NULL,

`end` int(32) NOT NULL,

`ip` varchar(20) NOT NULL DEFAULT '',

`port` int(11) NOT NULL DEFAULT '0',

`user` varchar(50) NOT NULL DEFAULT '',

`pwd` varchar(50) NOT NULL DEFAULT '',

PRIMARY KEY (`appid`,`begin`)

)ENGINE=InnoDB DEFAULT CHARSET=utf8;

5.4  資料遷移/自動擴充套件

資料遷移:

STEP1:利用 MySQL 主備複製機制進行資料複製

STEP2:資料差異小於某一臨界值,停止老分片寫操作(read-only)

STEP3:等待新分片資料更新完畢

STEP4:更路由規則路由規則,Cluster Manager向所有access proxy更新路由資訊

STEP5:刪除老分片

自動擴充套件:

過程類似於資料遷移


六、Redis 叢集方案

6.1  部署方式

1、異構讀寫分離-MySQL寫,Redis讀

1) 資料寫操作在 MySQL ,讀操作在Redis

2) 資料通過Sync系統對binlog進行解析從Mysql同步到Redis

3) 資料有同步延遲(小於100ms),實現最終一致性

適用場景:要求資料高可靠,且讀量比較大,允許讀資料短時間不一致,若期望一直讀到最新資料,請使用get_with_version()介面從 MySQL 讀取

2、獨立的Redis叢集服務

1)讀寫均在Redis,提供獨立的KV儲存服務

2) 使用者不用關注擴容/縮容/故障恢復等問題

3) 叢集內多業務混存,提高記憶體的使用率

適用場景:獨立的Redis叢集服務,類似twenproxy/codis

6.2  設計要點

1、一致性hash

支援資料跨Redis例項拆分,固定Slot數進行拆分

2、單機多例項部署

1)每個物理機支援多Redis例項

2)每個Redis例項只服務單個業務

3)Redis例項記憶體大小取決於業務需求,同時考慮業務訪問量和資料量

以RedisIP+port標示唯一例項,對於128G記憶體機器,

可配置3 Redis例項*每例項30G

或10 Redis例項*每例項10G

或20 Redis例項*每例項5G

拆分原則:單例項最大記憶體使用 < 本機剩餘記憶體

3、以Slot為單位的平滑擴容/縮容

4、以Redis例項為單位的failover處理

6.3  平滑擴容/縮容

主要步驟如下:

STEP1:確認擴容/縮容

Cluster manager通過對系統負載和資料量進行告警,進而確認進行擴容或者縮容

STEP2:修改路由表

1)修改路由表,將對應shard的狀態修改為migrate狀態,並將新路由推送到所有接入層

2)acc proxy會將寫操作轉到新的Redis例項中,讀操作預設先讀新Redis例項,key不存在會繼續從老的Redis例項中讀取

STEP3:資料遷移

1)Cluster manager通過自動資料遷移工具開始資料遷移,計劃依賴Redis的scan命令將相關的key掃出來,通過MIGRATE進行資料遷移

2)多次掃描執行該過程,確認Slot中所有資料遷移完成

STEP4:修改路由表,遷移完成

Cluster manager將讀寫均切到新Redis例項,不再從老Redis中進行操作

七、 Sync 資料同步服務

7.1  架構


7.2  應用場景

該服務完全可以抽象成獨立的資料同步分發服務,對於因為KV化而丟失的sql處理完全可以通過該服務同步到偏OLAP類的系統中進行處理。除了同步到Redis還可以同步到ElasticSearch或者hbase或者寫hdfs檔案基於hadoop生態去實現複雜計算和分析。

7.3  設計要點

1、叢集對叢集的實時資料同步

MySQL 統一要求binlog日誌為row格式

2、不涉及DDL處理

由於 MySQL schemaless的設計,不用考慮DDL處理,簡化同步服務(跨/不跨IDC)

3、基於時間戳的同步延遲監控

MySQL binlog row格式日誌自帶時間戳,基於此時間戳進行同步延遲監控

4、基於binlog檔名+offset的同步位置管理

定時定量持久化儲存當前同步的binlog檔名及offset,用於各種場景下的同步恢復

5、基於行的並行同步

多執行緒同步模式,主執行緒通過對tableid或者key做hash,將binlogevent時間分發到對應worker執行緒的佇列中,worker執行緒依次從佇列中獲取binlog event執行

7.4  實現原理


原理相對比較簡單:

1)Sync同步工具模擬Mysql slave的互動協議,偽裝自己為 MySQL slave,向Mysqlmaster傳送dump協議

2)Mysqlmaster收到dump請求,開始推送binary log給slave(也就是同步工具)

3)Sync同步工具解析binary log物件(原始為byte流),並轉換成Redis或其他儲存(hdfs/hbase/ES等資料庫)相應資料操作介面或者作為訊息儲存到MQ中(rocketmq或者kafka)

7.5  ROW 格式events

MySQL 5.5 Binlog的事件型別有多種,這裡只介紹與ROW模式相關的事件

1) QUERY_EVENT:與STATEMENT模式處理相同,儲存的是SQL,主要是一些與資料無關的操作,eg: begin、drop table

2) TABLE_MAP_EVENT:記錄了下一條事件所對應的表資訊,在其中儲存了資料庫名和表名

3) WRITE_ROWS_EVENT:操作型別為insert

4) UPDATE_ROWS_EVENT:操作型別為update

5) DELETE_ROWS_EVENT:操作型別為delete

6) XID_EVENT, 用於標識事務提交(commit)

典型的insert語句有如下4個events組成: