Redis和MySQL同步
- 页面并发量和访问量并不多,MySQL
足以支撑自己逻辑业务的发展。那么其实可以不加缓存。最多对静态页面进行缓存即可。 - 页面的并发量显著增多,数据库有些压力,并且有些数据更新频率较低
反复被查询或者查询速度较慢。那么就可以考虑使用缓存技术优化。对高命中的对象存到key-value形式的Redis中,那么,如果数据被命中,那么可以不经过效率很低的db。从高效的redis中查找到数据。
MySQL同步到ES的解决方案
1.代码实现
2. AOP
3. canal (java)
阿里巴巴开源MySQL binlog 增量订阅&消费组件
基于binlog 订阅 数据同步中间件
4. logstash
数据迁移
一般解决方案是使用类似Sqoop的工具,直连MySQL去Select数据存储到HDFS,然后把HDFS数据Load到Hive中。这种方法简单易操作,但随着业务规模扩大,不足之处也逐步暴露出来:
- 直连MySQL查询,对于数据库压力较大(如订单表、支付表等),可能直接影响在线业务
- 数据整体就位时间(尤其大表)不满足下游生产需求
- 扩展性较差,对于分表、字段增减、变更等的支持较弱
- 拉取的数据是该时刻的镜像,无法获取中间变化情况

整体数据流程如上图所示,数据收集部分使用定制化Canal组件(基于阿里开源项目)收集binlog日志并做格式转换,然后通过消息队列传输并落地到HDFS,最后对HDFS上的binlog进行清洗还原入库。
如果是增量接入,上述操作就完成了一次入库流程。针对全量接入或者回溯历史数据,因为缺少历史binlog日志(发起采集时才开始收集)无法还原历史数据,此时需要借助离线一次性拉取,流程如下:
- 按照上述流程采集binlog日志增量入HDFS
- 使用离线一次性拉取一份历史全量数据,按字段还原到Hive作为基点(即第一个接入周期的数据)
- 使用前一个接入周期的全量数据和本周期的增量binlog做merge形成该周期内的数据。
相比一般解决方案,其优点比较明显,主要表现在:
- 基于Binlog日志的数据还原,与在线业务解耦
- 采集通过分布式队列实时传递,还原操作在集群上实现,及时性及可扩展性强
- Binlog日志包括了增、删、改等明细动作,支持定制化的ET
DATAx
https://github.com/alibaba/DataX
Binlog从发起采集的一刻起才会在整个链路上存在,即以增量的方式传递,那么对于历史数据如何获取?实际场景中包括全量接入或增量历史数据回溯。
目前实现方式为通过DataX工具直连MySQL离线库,拉取一份截至到当前时间的全量数据,然后按列还原到Hive表的首个分区中。
全量采集场景下,下个分区的数据基于上个分区的数据和当前周期内的增量Binlog日志merge,即可产生该分区内的数据。
上面介绍了基于Binlog数据接入的整体流程,下面列举两个实际解决的业务问题。
canal
- canal模拟mysql slave的交互协议,伪装自己为mysql slave,向master发送dump协议
- mysql master收到dump请求,开始推送binary log到canal
- canal解析binary log对象,并将解析的结果编码成JSON格式的文本串
- 把解析后的文本串发送到消息队列并上报发送情况(如Kafka、DDMQ)

格式:
{"binlog": "25521@mysql-bin.000070","time": 1450236307000,"canalTime": 1450236308279,"db": "TestCanal","table": "g_order_010","event": "u","columns": [{"n": "order_id", "t": "bigint(20)", "v": "126", "null": false, "updated": false},{"n": "driver_id", "t": "bigint(20)", "v": "123456", "null": false, "updated": false},{ "n": "passenger_id", "t": "bigint(20)", "v": "654321", "null": false, "updated": false},{"n": "current_lng", "t": "decimal(10,6)", "v": "39.021400", "null": false, "updated": false},{"n": "current_lat", "t": "decimal(10,6)", "v": "120.423300", "null": false, "updated": false},{ "n": "starting_lng", "t": "decimal(10,6)", "v": "38.128000", "null": false, "updated": false},{ "n": "starting_lat", "t": "decimal(10,6)", "v": "121.445000", "null": false, "updated": false},{ "n": "dest_name", "t": "varchar(100)", "v": "Renmin University", "origin_val": "知春路", "null": false, "updated": true}],"keys": ["order_id"]}{"binlog": "25521@mysql-bin.000070","time": 1450236307000,"canalTime": 1450236308279,"db": "TestCanal","table": "g_order_010","event": "u","columns": [{"n": "order_id", "t": "bigint(20)", "v": "126", "null": false, "updated": false},{"n": "driver_id", "t": "bigint(20)", "v": "123456", "null": false, "updated": false},{ "n": "passenger_id", "t": "bigint(20)", "v": "654321", "null": false, "updated": false},{"n": "current_lng", "t": "decimal(10,6)", "v": "39.021400", "null": false, "updated": false},{"n": "current_lat", "t": "decimal(10,6)", "v": "120.423300", "null": false, "updated": false},{ "n": "starting_lng", "t": "decimal(10,6)", "v": "38.128000", "null": false, "updated": false},{ "n": "starting_lat", "t": "decimal(10,6)", "v": "121.445000", "null": false, "updated": false},{ "n": "dest_name", "t": "varchar(100)", "v": "Renmin University", "origin_val": "知春路", "null": false, "updated": true}],"keys": ["order_id"]}
