后续文章: 通过Canal保证某网站的Redis与MySql的数据自动同步
1.编写目的
某网站项目引入了redis缓存技术,如何保证Redis与MySql的数据一致性是开发人员需要首要解决的问题。
本文主要包括以下内容:
- Redis与MySql的数据一致性方案汇总与选取
- Canal解析binlog方案简介
- 其他Redis开发原则
2.方案汇总与选取
下面展示了几种常见的Redis与MySql数据一致性的方案:
序号 | 方案 | 方案简述 | 评价 |
---|---|---|---|
1 | 手动同步一 | 对于读操作,先读redis,有则返回,无则读取MySql,并插入Redis。对于写操作,先写MySql,再读Redis。 | 直观简单,但是每次数据操作都需要手动维护缓存和数据库的一致性 |
2 | 手动同步二 | 对于读操作,先读redis,有则返回,无则读取MySql,并插入Redis。对于插入操作,先插入MySql,再写入cache。对于更新和删除操作,先删除cache,再操作MySql。 | 直观简单,但是每次数据操作都需要手动维护缓存和数据库的一致性。高并发情况下,会出现db与cache的不一致 |
3 | MySql的UDF | 通过数据库中的触发器(Trigger)调用UDF(user defined function,自定义的函数库),来触发对Redis的相应操作 | 自定义的函数库需要我们基于MySql的API进行开发(C++)(阿里早期做法) |
4 | Gearman+PHP+MySql UDF | 通过借用已经比较成熟的MySql UDF,将MySql数据首先放入Gearman中,然后通过一个自己编写的PHP Gearman Worker,将数据同步到Redis | 一般使用在PHP的开发中 |
5 | Open-Replicator解析binlog | Open Replicator是一个用Java编写的MySql binlog分析程序。Open Replicator 首先连接到MySql,然后接收和分析binlog,根据binlog的分析结果进行缓存操作。 | 主动读取binlog,实时性保证不够,整体解决方案不够成熟 |
6 | Canal解析binlog | Canal主要是基于数据库的日志解析,获取增量变更进行同步,由此衍生出了增量订阅&消费的业务,核心基本就是模拟MySql中Slave节点请求。 | 阿里开源项目,比较成熟的解决方案。 |
方案分析与选取:
- 方案1和2都需要开发人员去手动维护Reids和MySql之间的同步。
- 方案3需要编写UDF。
- 方案4一般用在PHP开发中。
- 方案5实时性较差。
- 本项目采用方案6:通过Canal解析binlog。
3.Canal解析binlog简介
2.2.binlog
binlog,全称binary log,即MySql的二进制日志文件。
binlog用于记录mysql的数据更新或者潜在更新(比如DELETE语句执行删除而实际并没有符合条件的数据),在mysql主从复制中就是依靠的binlog。
2.3.MySql主从复制
下图是对MySql的主从复制(Master/Slave)的简单说明:
原理:
- Master将数据库增量更新记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events,可以通过show binlog events进行查看);
- Slave将Master的binary log events拷贝到它的中继日志(relay log);
- Slave重做中继日志中的事件,将数据库增量更新反映到自己的数据库中。
2.4.Canal原理
下图是对MySql的主从复制(Master/Slave)的简单说明:
原理:
1. Canal模拟MySql Slave的交互协议,伪装自己为MySql Slave,向MySql Master发送dump协议
2. MySql Master收到dump请求,开始推送binary log给Slave(也就是Canal)
3. Canal解析binary log对象(原始为byte流)
4.其他Redis开发原则
下面列出一些已经确定的Redis开发原则:
- 所有的写操作(插入、更新、删除)都访问MySql。
- 所有的读操作都访问cache。
- 通过Canal解析MySql的binlog同步Redis来保持数据一致性。
- 提供一个初始化全部缓存数据的方法:initCache。
- Redis的KEY命名规范:项目名称-模块名称-对象名称-主键id。例如:baidu-news-user-0000000001。
5.注意事项
通过一段时间的使用,现将使用Canal解析binlog方案过程中的注意事项进行说明:
- MySql需要开启binlog模式,此模式下导致MySql性能下降。
- MySql需要开启binlog模式,此模式下导致MySql的binlog文件激增。
- 在处理blob数据类型时,需要进行转码。
说明:
- 如果MySql本身需要使用主从复制,则必须开启binlog。所以此种情况下,第一条无需在意。
- 为了防止因binlog文件激增导致数据库服务器磁盘激增,可以设置MySql日志的自动清理。可以参考:《MySql自动清除binary logs日志》
- Canal在读取了binlog的数据之后,会进行判断属于那种数据类型。这时,如果此字段属于blob字段,则进行转码即可,伪代码如下:
//判断每个字段
for (Column column : columns) {
//如果字段类型为blob,则进行转码
if ("blob".equals(column.getMysqlType())) {
json.put(column.getName(), new String(column.getValue().getBytes("ISO-8859-1"),"gbk"));
}else{//其他字段直接将字段名和值放到json串中
json.put(column.getName(), column.getValue());
}
}
具体转换成何种编码,请根据项目情况进行调节。