本文介紹基於MySQL及Redis搭建統一的kv存儲服務:經常使用部署方式及其特色,Cluster manager,MySQL和Redis集羣方案,以及Sync數據同步服務。git
業務層經過雙寫同時寫MySQL及Redis。讀一般在Redis,若讀取不到,則從MySQL讀取,而後將數據同步到Redis,Redis一般設置expire或者默認LRU進行數據淘汰。github
這種使用方式會有以下問題:算法
1)MySQL及Redis存在數據不一致風險,尤爲是長時間運行的系統sql
2)業務層須要處理MySQL sql schema與Redis kv數據結構上的邏輯差別數據庫
3)無統一運維json
4)沒法方便擴容/縮容性能優化
參考文檔:服務器
http://www.aviransplace.com/2015/08/12/Mysql-is-a-great-nosql/微信
爲何要用MySQL:數據結構
「在可擴展系統構建時,一個很重要的考量是使用的技術是否成熟,選擇成熟的技術意味着出錯時可以迅速恢復。固然,開發者也能夠在項目中使用最新最牛的NoSQL數據庫,而這個數據庫在理論上也能夠良好地運行,然而在生產環境中出現了問題恢復須要多久?技術上已有的知識和經驗積累對於問題緩解相當重要,固然這個積累也包括了Google能夠搜索到的內容。
相比之下,關係型數據庫已經存在了超過四十年,業界對於關係型數據庫的維護也積累了大量的經驗。基於這些考慮,在新項目作技術選型時一般會選擇Mysql,而不是NoSQL數據庫,除非NoSQL真的有很是很是明顯的優點。」
對於億級規模的數據存儲,尤爲是涉及到水平拆分跨機分庫分表的狀況下,線上對數據庫的訪問只能作的越簡單越好,group by/order by/分頁/通用join/事務等等的支持 在這個量級下的MySQL系統都是不合適的。
基本上目前全部的類proxy的MySQL方案真正上規模線上應用只能使用按拆分鍵進行讀寫操做,實際上也是一個用拆分鍵作的一個kv系統。
若想使用複雜的sql處理,最合理的部署方案是將Mysqlbinlog流水同步服務抽象出來,經過實時同步到OLAP類的系統進行處理。
因此面向海量存儲服務,MySQL從一開始就設計爲一個KV系統是可行的。value使用mediumblob存儲xml/json/protobuf/thrift格式化數據序列化以後的數據。
一、用MySQL原來的主鍵或者索引鍵當作key
二、其餘全部的非主鍵非索引鍵,所有包裝到value裏面,value使用mediumblob存儲xml/json/protobuf/thrift格式化數據序列化以後的數據。
三、數據讀寫操做,均基於key一整行數據作讀寫,由業務層對裏面value的結構作解析及對內部結構作增刪改差,而不用變動 MySQL 自己的schema.
一、數據量和訪問量不大而且業務邏輯依賴 MySQL 數據庫進行處理的業務場景
二、涉及到多表join等的處理
對於此限制,也能夠經過將關聯表加工成基於關聯條件的一張寬表進行KV化。
三、涉及到事務等的處理。
1)業務層經過統一方式訪問MySQL及Redis,再也不使用MySQL客戶端及Redis客戶端訪問
2)MySQL集羣化/Redis集羣化部署
3)將業務雙寫改成MySQL到Redis底層binlog數據同步方式完成同步
4)異構數據存儲支持最終一致性數據讀寫服務
5)支持存儲層面擴容縮容、failover且業務無感知
6)單機羣日百億次QPS/TPS支持(大類業務適度拆分到不一樣集羣中)
基於MySQL+Redis的統一存儲服務(UniStore) =
MySQL跨機分庫分表集羣
+ Redis集羣
+ MySQL->Redis實時數據同步服務
+ 統一的對外數據訪問接口
+ 內在的完整運維支持系統(支持在線擴容/縮容、failover等)
一、將MySQL+Redis作成統一KV存儲服務
二、經過acc proxy提供統一的數據訪問接口,經過統一協議支持跨語言數據訪問
訪問協議(自定義協議,protobuf協議,thrift協議等)
三、MySQL cluster支持跨機的分庫分表,schemaless設計,全部業務表KV化設計
四、Redis cluster支持跨機的實例拆分
五、Sync數據同步服務提供統一的Mysql到Redis 跨IDC/不跨IDC數據同步服務,小於100ms延時
六、整個系統不涉及到分佈式事務處理
一、純MySQL集羣部署
此種部署方式等同於其餘MySQL proxy跨機分庫分表方案,讀寫均在MySQL
二、純Redis集羣部署
此種部署方式等同於其餘Redis proxy跨機分庫分表方案,讀寫均在Redis
三、MySQL+Redis異構部署
寫在MySQL,讀能夠從MySQL讀或者Redis讀,取決於業務對最新數據的讀取要求。
一、int get(int appid, string key,string& value)
Redis讀操做專用
二、int get_with_version(int appid,string key, string& value, int64& version)
MySQL 讀操做專用,自帶版本號,防止寫覆蓋
三、int set(int appid, string key,string value, int64 version)
經過appid區分 MySQL 仍是Redis,均支持寫操做
四、int delete(int appid, string key)
經過appid區分 MySQL 仍是Redis, 不支持批量刪除
五、int multiget(int appid,vector<string> keys, map<string, string>& key_value_pairs)
支持批量讀操做,內部的數據路由及數據合併不用關心
六、intmultiset(int appid, map<string, string>& key_value_pairs)
不建議支持,涉及到跨機事務問題,沒法保證ACID
七、int Redis_op(string cmd, ……)
Redis其餘原生接口封裝(incr/expire/list/setnx等)
在此我向你們推薦一個架構學習交流羣。交流學習羣號:575745314 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
cluster manager主要由以下幾種功能
1)MySQL/Redis分片路由信息的管理
一、 MySQL 分庫分表路由信息
二、Redis Slot路由信息
三、路由信息變動管理
2)Redis實例的探活及Redis擴容及縮容數據的遷移
好比連續3次,每次間隔30sRedis ping失敗,認爲實例掛掉,發出報警或者自動切換
3)Cluster manager不建議參與Mysql group主備層面的管理
MySQL 主備層面的集羣管理方案:
一、MHA+VIP (互聯網公司最經常使用)
二、微信phxsql系統:https://github.com/tencent-wechat/phxsql 金融級可靠性
1)統一的schemaless表結構
2)跨機的數據分佈
支持將單邏輯表水平拆分到多個Mysql服務器中
3)其餘說明
一、數據存儲可靠性高,全部業務數據經過序列化存儲到value列
二、每行數據自帶版本號,業務經過cas方式防止業務層多實例同時寫形成寫覆蓋
全局惟一版本號實現:本機微秒時間戳+server_id+proccess_id
三、固定百庫百表/百庫十表的數據拆分方式,多機跨Mysql實例部署
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;
數據遷移:
STEP1:利用 MySQL 主備複製機制進行數據複製
STEP2:數據差別小於某一臨界值,中止老分片寫操做(read-only)
STEP3:等待新分片數據更新完畢
STEP4:更路由規則路由規則,Cluster Manager向全部access proxy更新路由信息
STEP5:刪除老分片
自動擴展:
過程相似於數據遷移
6、Redis 集羣方案
一、異構讀寫分離-MySQL寫,Redis讀
1) 數據寫操做在 MySQL ,讀操做在Redis
2) 數據經過Sync系統對binlog進行解析從Mysql同步到Redis
3) 數據有同步延遲(小於100ms),實現最終一致性
適用場景:要求數據高可靠,且讀量比較大,容許讀數據短期不一致,若指望一直讀到最新數據,請使用get_with_version()接口從 MySQL 讀取
二、獨立的Redis集羣服務
1)讀寫均在Redis,提供獨立的KV存儲服務
2) 用戶不用關注擴容/縮容/故障恢復等問題
3) 集羣內多業務混存,提升內存的使用率
適用場景:獨立的Redis集羣服務,相似twenproxy/codis
一、一致性hash
支持數據跨Redis實例拆分,固定Slot數進行拆分
二、單機多實例部署
1)每一個物理機支持多Redis實例
2)每一個Redis實例只服務單個業務
3)Redis實例內存大小取決於業務需求,同時考慮業務訪問量和數據量
以RedisIP+port標示惟一實例,對於128G內存機器,
可配置3 Redis實例*每實例30G
或10 Redis實例*每實例10G
或20 Redis實例*每實例5G
拆分原則:單實例最大內存使用 < 本機剩餘內存
三、以Slot爲單位的平滑擴容/縮容
四、以Redis實例爲單位的failover處理
主要步驟以下:
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中進行操做
在此我向你們推薦一個架構學習交流羣。交流學習羣號:575745314 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
7.2 應用場景
該服務徹底能夠抽象成獨立的數據同步分發服務,對於由於KV化而丟失的sql處理徹底能夠經過該服務同步到偏OLAP類的系統中進行處理。除了同步到Redis還能夠同步到ElasticSearch或者hbase或者寫hdfs文件基於hadoop生態去實現複雜計算和分析。
一、集羣對集羣的實時數據同步
MySQL 統一要求binlog日誌爲row格式
二、不涉及DDL處理
因爲 MySQL schemaless的設計,不用考慮DDL處理,簡化同步服務(跨/不跨IDC)
三、基於時間戳的同步延遲監控
MySQL binlog row格式日誌自帶時間戳,基於此時間戳進行同步延遲監控
四、基於binlog文件名+offset的同步位置管理
定時定量持久化保存當前同步的binlog文件名及offset,用於各類場景下的同步恢復
五、基於行的並行同步
多線程同步模式,主線程經過對tableid或者key作hash,將binlogevent時間分發到對應worker線程的隊列中,worker線程依次從隊列中獲取binlog event執行
原理相對比較簡單:
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)
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組成:
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 /