如何基于MySQL及Redis搭建統一的KV存儲服務

CarissaWild 7年前發布 | 64K 次閱讀 Redis MySQL 數據庫服務器

摘要:本文介紹基于MySQL及Redis搭建統一的kv存儲服務:常用部署方式及其特點,Cluster manager,MySQL和Redis集群方案,以及Sync數據同步服務。

秦波,8年開發及架構經驗, 之前在華為/京東/小米參與部分核心基礎服務的設計與開發工作,目前在九州證券負責大數據平臺及風控相關項目的技術研發工作。 關注高并發/高可靠/服務監控與治理/分布式存儲/大數據相關系統的架構和實現。

一、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組成:

7.6  其他開源同步方案

1. tungsten-replicator(JAVA)

http://code.google.com/p/tungsten-replicator/

2. linkedin  databus(JAVA)

https://github.com/linkedin/databus

3. Alibaba  canal(JAVA)

https://github.com/alibaba/canal /

 

 

 

來自:http://mp.weixin.qq.com/s/I_bOF5WKuTZr9PAAevY_lw

 

 本文由用戶 CarissaWild 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!