redis和数据库同步
1. canal+Kafka实现mysql与redis数据同步
前言
上篇文章简单介绍canal概念,本文结合常见的缓存业务去讲解canal使用。在实际开发过程中,通常都会把数据往redis缓存中保存一份,做下简单的查询优化。如果这时候数据库数据发生变更操作,就不得不在业务代码中写一段同步更新redis的代码,但是这种 数据同步的代码和业务代码糅合在一起 看起来不是很优雅,而且还会出现数据不一致问题。那能不能把这部分同步代码从中抽离出来,形成独立模块呢?答案是肯定的,下面通过canal结合Kafka来实现mysql与redis之间的数据同步。
架构设计
通过上述结构设计图可以很清晰的知道用到的组件:MySQL、Canal、Kafka、ZooKeeper、Redis。
Kafka&Zookeeper搭建
首先在 官网 下载Kafka:
Kafka内部自带了zookeeper,所以暂不需要去下载搭建zookeeper集群,本文就使用Kafka自带zookeeper来实现。
通过上述zookeeper启动命令以及Kafka启动命令把服务启动,可以通过以下简单实现下是否成功:
Canal搭建
canal搭建具体可以参考上文,这里只讲解具体的参数配置:
找到/conf目录下的canal.properties配置文件:
然后配置instance,找到/conf/example/instance.properties配置文件:
经过上述配置后,就可以启动canal了。
测试
环境搭建完成后,就可以编写代码进行测试。
1、引入pom依赖
2、封装Redis工具类
在application.yml文件增加以下配置:
封装一个操作Redis的工具类:
3、创建MQ消费者进行同步
创建一个CanalBean对象进行接收:
最后就可以创建一个消费者CanalConsumer进行消费:
测试Mysql与Redis同步
mysql对应的表结构如下:
启动项目后,新增一条数据:
可以在控制台看到以下输出:
如果更新呢?试一下Update语句:
同样可以在控制台看到以下输出:
经过测试完全么有问题。
总结
既然canal这么强大,难道就没缺点嘛?答案当然是存在的啦,比如:canal只能同步增量数据、不是实时同步而是准实时同步、MQ顺序问题等; 尽管有一些缺点,毕竟没有一样技术或者产品是完美的,最重要是合适。比如公司目前有个视图服务提供宽表搜索查询功能就是通过 同步Mysql数据到Es采用Canal+Kafka的方式来实现的。
2. 使用python同步mysql到redis由于数据较多,一条一条读出来写到redis太慢,有没有可以批量操作的。
MYSQL快速同步数据到Redis
举例场景:存储游戏玩家的任务数据,游戏服务器启动时将mysql中玩家的数据同步到redis中。
从MySQL中将数据导入到Redis的Hash结构中。当然,最直接的做法就是遍历MySQL数据,一条一条写入到Redis中。这样没什么错,但是速度会非常慢。如果能够想法使得MySQL的查询输出数据直接能够与Redis命令行的输入数据协议相吻合,可以节省很多消耗和缩短时间。
Mysql数据库名称为:GAME_DB, 表结构举例:
CREATE TABLE TABLE_MISSION (
playerId int(11) unsigned NOT NULL,
missionList varchar(255) NOT NULL,
PRIMARY KEY (playerId)
);
Redis中的数据结构使用哈希表:
键KEY为mission, 哈希域为mysql中对应的playerId, 哈希值为mysql中对应的missionList。 数据如下:
[root@iZ23zcsdouzZ ~]# redis-cli
127.0.0.1:6379> hget missions 36598
"{\"10001\":{\"status\":1,\"progress\":0},\"10002\":{\"status\":1,\"progress\":0},\"10003\":{\"status\":1,\"progress\":0},\"10004\":{\"status\":1,\"progress\":0}}"
快速同步方法:
新建一个后缀.sql文件:mysql2redis_mission.sql
内容如下:
SELECT CONCAT(
"*4\r\n",
'$', LENGTH(redis_cmd), '\r\n',
redis_cmd, '\r\n',
'$', LENGTH(redis_key), '\r\n',
redis_key, '\r\n',
'$', LENGTH(hkey), '\r\n',
hkey, '\r\n',
'$', LENGTH(hval), '\r\n',
hval, '\r'
)
FROM (
SELECT
'HSET' as redis_cmd,
'missions' AS redis_key,
playerId AS hkey,
missionList AS hval
FROM TABLE_MISSION
) AS t
创建shell脚本mysql2redis_mission.sh
内容:
mysql GAME_DB --skip-column-names --raw < mission.sql | redis-cli --pipe
Linux系统终端执行该shell脚本或者直接运行该系统命令,即可将mysql数据库GAME_DB的表TABLE_MISSION数据同步到redis中键missions中去。mysql2redis_mission.sql文件就是将mysql数据的输出数据格式和redis的输入数据格式协议相匹配,从而大大缩短了同步时间。
经过测试,同样一份数据通过单条取出修改数据格式同步写入到redis消耗的时间为5min, 使用上面的sql文件和shell命令,同步完数据仅耗时3s左右。
3. redis和mysql区别是什么
1.mysql和redis的数据库类型
mysql是关系型数据库,主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。
redis是NOSQL,即非关系型数据库,也是缓存数据库,即将数据存储在缓存中,缓存的读取速度快,能够大大的提高运行效率,但是保存时间有限
2.mysql的运行机制
mysql作为持久化存储的关系型数据库,相对薄弱的地方在于每次请求访问数据库时,都存在着I/O操作,如果反复频繁的访问数据库。第一:会在反复链接数据库上花费大量时间,从而导致运行效率过慢;第二:反复的访问数据库也会导致数据库的负载过高,那么此时缓存的概念就衍生了出来。
3.缓存
缓存就是数据交换的缓冲区(cache),当浏览器执行请求时,首先会对在缓存中进行查找,如果存在,就获取;否则就访问数据库。
缓存的好处就是读取速度快
4.redis数据库
redis数据库就是一款缓存数据库,用于存储使用频繁的数据,这样减少访问数据库的次数,提高运行效率。
5.redis和mysql的区别总结
(1)类型上
从类型上来说,mysql是关系型数据库,redis是缓存数据库
(2)作用上
mysql用于持久化的存储数据到硬盘,功能强大,但是速度较慢
redis用于存储使用较为频繁的数据到缓存中,读取速度快
(3)需求上
mysql和redis因为需求的不同,一般都是配合使用。
4. 请教redis如何做到和mysql数据库的同步
者数据同步的关键在于mysql数据库中主键,方案是在redis启动时区mysql读取所有表键值存入redis中,往redis写数据是,对redis主键自增并进行读取,若mysql更新失败,则需要及时清除缓存及同步redis主键。 参考代码如下: String tbname = "login"; //获取mysql表主键值--redis启动时 long id = MySQL.getID(tbname); //设置redis主键值--redis启动时 redisService.set(tbname, String.valueOf(id)); System.out.println(id); long l = redisService.incr(tbname); System.out.println(l); Login login = new Login(); login.setId(l); login.setName("redis"); redisService.hmset(String.valueOf(login.getId()), login); boolean b = MySQL.insert("insert into login(id,name) values(" + login.getId() + ",'" + login.getName() + "')"); /** * * 队列处理器更新mysql失败: * * 清除缓存数据,同时主键值自减 */ if (!b) { redisService.delKeyAndDecr (tbname, "Login:"+String.valueOf(login.getId())); // redisService.delete("Login:"+String.valueOf(login.getId())); //redisService.decr(tbname); } System.out.println(redisService.exists("Login:"+String.valueOf(login.getId()))); System.out.println(redisService.get(tbname));
5. redis 和 mysql 数据同步问题
结构不同
先讲MySQL,MySQL中一个事务提交之后就永久写入了,同时将事务的操作写入日志。然后,slave从master中请求日志,复制这个事务的操作(注意不是sql语句)。
而Redis的主从同步和数据快照有关,Redis定期将内存中数据作快照保存在文件中,mater只要将文件发送给slave更新就可以了。
MySQL的slave需要请求从从某个事务(就是slave刚完成的那个)开始的所有日志,而redis不需要,slave只要将收到的快照排队,一个一个复制到硬盘、内存就行了。
6. redis怎么与mysql同步java代码
redis应该算是本地缓存,而mysql的话是数据库,你的意思应该是:怎么用java代码同步数据库中的数据到redis。如果是这种情况的话:目前项目中会用一个定时任务定时去读取数据库中的数据,然后放到redis,或者在项目初始化读取数据库然后再放到redis
7. 数据库db与缓存redis的数据同步
总的思路就是跑一个触发器服务,根据新增、更新选择不同的路径,进行同步数据操作。
8. 当数据库里的数据修改以后怎么和redis缓存进行同步
当数据库里的数据修改以后怎么和redis缓存进行同步?
在一台机器上启动3个redis,一个做master,两个做slave。 Master 端口:6380 Slave1 端口:6381 Slave2端口:6382
9. 如何同步到redis
在Redis中,用户可以通过执行SLAVEOF命令或者设置slaveof选项,让一个服务器去复制(replicate)另一个服务器,我们称呼被复制的服务器为主服务器(master),而对主服务器进行复制的服务器则被称为从服务器(slave),如图所示。
步骤5:发送端口信息
身份验证步骤之后,从服务器将执行命令REPLCONF listening-port <port-number>,向主服务器发送从服务器的监听端口号。
主服务器在接收到这个命令之后,会将端口号记录在从服务器所对应的客户端状态的slave_listening_port属性中:
typedefstructredisClient{
//...
//从服务器的监听端口号
intslave_listening_port;
//...
}redisClient;
slave_listening_port属性目前唯一的作用就是在主服务器执行INFO replication命令时打印出从服务器的端口号。
步骤6:同步
在这一步,从服务器将向主服务器发送PSYNC命令,执行同步操作,并将自己的数据库更新至主服务器数据库当前所处的状态。
需要注意的是在执行同步操作前,只有从服务器是主服务器的客户端。但是执行从不操作之后,主服务器也会称为从服务器的客户端:
如果PSYNC命令执行的是完整同步操作,那么主服务器只有成为了从服务器的客户端才能将保存在缓冲区中的写命令发送给从服务器执行;
如果PSYNC命令执行的是部分同步操作,那么主服务器只有成为了从服务器的客户端才能将保存在复制积压缓冲区中的写命令发送给从服务器执行;
步骤7:命令传播
当完成了同步之后,主从服务器就会进入命令传播阶段,这时主服务器只要一直将自己执行的写命令发送给从服务器,而从服务器只要一直接收并执行主服务器发来的写命令,就可以保证主从服务器一直保持一致了。
心跳检测
在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:REPLCONF ACK <replication_offset>
其中replication_offset是从服务器当前的复制偏移量。
发送REPLCONF ACK命令对于主从服务器有三个作用:
检测主从服务器的网络连接状态;
辅助实现min-slaves选项;
检测命令丢失。
检测主从服务器的网络连接状态
如果主服务器超过一秒钟没有收到从服务器发来的REPLCONF ACK命令,那么主服务器就知道主从服务器之间的连接出现问题了。
通过向主服务器发送INFO replication命令,在列出的从服务器列表的lag一栏中,我们可以看到相应从服务器最后一次向主服务器发送REPLCONF ACK命令距离现在过了多少秒:
127.0.0.1:6379>INFOreplication
#Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=12345,state=online,offset=211,lag=0
#刚刚发送过REPLCONFACK命令
slave1:ip=127.0.0.1,port=56789,state=online,offset=197,lag=15
#15秒之前发送过REPLCONFACK命令
master_repl_offset:211
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:210
在一般情况下,lag的值应该在0秒或者1秒之间跳动,如果超过1秒的话,那么说明主从服务器之间的连接出现了故障。
辅助实现min-slaves配置选项
Redis的min-slaves-to-write和min-slaves-max-lag两个选项可以防止主服务器在不安全的情况下执行写命令。
举个例子,如果我们向主服务器提供以下设置:
min-slaves-to-write3
min-slaves-max-lag10
那么在从服务器的数量少于3个,或者三个从服务器的延迟(lag)值都大于或等于10秒时,主服务器将拒绝执行写命令,这里的延迟值就是上面提到的INFO replication命令的lag值。
检测命令丢失
我们从命令:REPLCONF ACK <replication_offset>就可以知道,每发送一次这个命令从服务器都会向主服务器报告一次自己的复制偏移量。那此时尽管主服务器发送给从服务器的SET key value丢失了。也无所谓,主服务器马上就知道了。
10. redis数据如何同步到数据库
同步到数据库,这应该是直接进行授权证,应该就可以进行通话,而且应该同步上的,应该比较朴素,应该能告知这些同步的。