缓存一致性和跨服务器查询的数据异构解决方案canal
? ? 当你的项目数据量上去了之后,通常会遇到两种情况,第一种情况应是最大可能的使用cache来对抗上层的高并发,第二种情况同样也是需要使用分库 分表对抗上层的高并发。。。逼逼逼起来容易,做起来并不那么乐观,由此引入的问题,不见得你有好的解决方案,下面就具体分享下。
? ? ? ?比如在我们的千人千面系统中,会针对商品,订单等维度为某一个商家店铺自动化建立大约400个数据模型,然后买家在淘宝下订单之后,淘宝会将订单推 送过来,订单会在400个模型中兜一圈,从而推送更贴切符合该买家行为习惯的短信和邮件,这是一个真实的业务场景,为了应对高并发,这些模型自然都是缓 存在Cache中,模型都是从db中灌到redis的,那如果有新的模型进来了,我如何通知redis进行缓存更新呢???通常的做法就是在添加模型的时候,顺便更新 redis。。。对吧,如下图: 说的简单,我把自己的手头代码写好就可以了,我要高内聚,所以你必须碰一鼻子灰。 除了一鼻子灰之后,也许你还会遇到更新database成功,再更新redis的时候失败,可人家不管,而且错误日志还是别人的日志系统里面,所以你很难甚至 无法保证这个db和cache的缓存一致性,那这个时候能不能换个思路,我直接写个程序订阅database的binlog,从binlog中分析出模型数据的CURD操作,根 据这些CURD的实际情况更新Redis的缓存数据,第一个可以实现和web的解耦,第二个实现了高度的缓存一致性,所以新的架构是这样的。 上面这张图,相信大家都能看得懂,重点就是这个处理binlog程序,从binlog中分析出CURD从而更新Redis,其实这个binlog程序就是本篇所说的canal。。。 一个伪装成mysql的slave,不断的通过dump命令从mysql中盗出binlog日志,从而完美的实现了这个需求。
? ? ? ?本篇开头也说到了,数据量大了之后,必然会存在分库分表,甚至database都要分散到多台服务器上,现在的电商项目,都是业务赶着技术跑。。。 谁也不知道下一个业务会是一个怎样的奇葩,所以必然会导致你要做一些跨服务器join查询, 不过如果你的业务真的很重要,可能DBA会给你做数据异构,所谓的数据异构,那就是 将需要join查询的多表按照某一个维度又聚合在一个DB中。让你去查询。。。。。 那如果用canal来订阅binlog,就可以改造成下面这种架构。
? ? ?好了,canal的应用场景给大家也介绍到了,最主要是理解这种思想,人家搞不定的东西,你的价值就出来了。
? ? ? ? 开启binlog,并且将binlog的格式改为Row,这样就可以获取到CURD的二进制内容, log-bin=mysql- binlog-format= server_id=
?
? ? ? ?使用命令验证,并且开启binlog的过期时间为30天,默认情况下binlog是不过期的,这就导致你的磁盘可能会爆满,直到挂掉。 show variables like
show variables like expire_logs_days=;
CREATE USER canal IDENTIFIED BY 'canal';
GRANT SELECT,REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;
show grants for 'canal'
?github的地址: https://github.com/alibaba/canal/releases canal [root@localhost myapp]# ls
apache-maven-3.5.0-bin.tar.gz dubbo-monitor-simple-2.5.4-SNAPSHOT.jar nginx tengine-2.2.0.tar.gz
gearmand nginx-1.13.4.tar.gz tengine_st
gearmand-1.1.17 nginx_st tomcat
dubbo gearmand-1.1.17.tar.gz redis zookeeper
dubbo-monitor-simple-2.5.4-SNAPSHOT maven redis-4.0.1.tar.gz zookeeper-3.4.9.tar.gz
dubbo-monitor-simple-2.5.4-SNAPSHOT-assembly.tar.gz mysql-5.7.19-linux-glibc2.12-x86_64.tar.gz tengine
[root@localhost myapp]# cd canal
[root@localhost canal]# ls
bin conf lib logs
[root@localhost canal]# cd conf
[root@localhost conf]# ls
example logback.xml spring
[root@localhost conf]# cd example
[root@localhost example]# ls
meta.dat
[root@localhost example]#
? ? ?canal的模式是这样的,一个canal里面可能会有多个instance,也就说一个instance可以监控一个mysql实例,多个instance也就可以对应多台服务器 的mysql实例。也就是一个canal就可以监控分库分表下的多机器mysql。
? ? ? 它是全局性的canal服务器配置,具体如下,这里面的参数涉及到方方面面。 #################################################
######### common argument #############
#################################################
canal.id= 1
canal.ip=
canal.zkServers=
# flush data to zk
canal.zookeeper.flush.period = 1000
# flush meta cursor/parse position to file
canal.file.data.dir = ${canal.conf.dir}
canal.file.flush.period = 1000
## memory store RingBuffer size,should be Math.pow(2,n)
canal.instance.memory.buffer.size = 16384
## memory store RingBuffer used memory unit size,default 1kb
canal.instance.memory.buffer.memunit = 1024
## meory store gets mode used MEMSIZE or ITEMSIZE
canal.instance.memory.batch.mode = MEMSIZE
detecing configcanal.instance.detecting.enable = false canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()canal.instance.detecting.sql = select 1 support maximum transaction size,more than the size of the transaction will be cut into multiple transactions deliverycanal.instance.transaction.size = 1024 mysql fallback connected to new master should fallback timescanal.instance.fallbackIntervalInSeconds = 60 network configcanal.instance.network.receiveBufferSize = 16384 binlog filter configcanal.instance.filter.query.dcl = false binlog format/image checkcanal.instance.binlog.format = ROW,STATEMENT,MIXED binlog ddl isolationcanal.instance.get.ddl.isolation = false ################################################# conf root dircanal.conf.dir = ../conf auto scan instance dir add/remove and start/stop instancecanal.auto.scan = true canal.instance.global.mode = spring canal.instance.global.manager.address = 127.0.0.1:1099canal.instance.global.spring.xml = classpath:spring/memory-instance.xmlcanal.instance.global.spring.xml = classpath:spring/file-instance.xml canal.instance.global.spring.xml = classpath:spring/default-instance.xml################################################# mysql serverIdcanal.instance.mysql.slaveId = 1234 position info,需要改成自己的数据库信息canal.instance.master.address = 127.0.0.1:3306 canal.instance.standby.address =canal.instance.standby.journal.name =canal.instance.standby.position =canal.instance.standby.timestamp =username/password,需要改成自己的数据库信息canal.instance.dbUsername = root table regex<span style="color: #ff0000;">canal.instance.filter.regex = ... ################################################# ? ? ? ? 由于是全局性的配置,所以上面三处标红的地方要注意一下: canal.port= 22222 ? ? ? ? ? 当前canal的服务器端口号 canal.destinations= example ? 当前默认开启了一个名为example的instance实例,如果想开多个instance,用","逗号隔开就可以了。。。 canal.instance.filter.regex = .*..* ? mysql实例下的所有db的所有表都在监控范围内。
? ? ? 这个就是具体的某个instances实例的配置,未涉及到的配置都会从canal.properties上继承。 #################################################
## mysql serverId
canal.instance.mysql.slaveId = 1234
position info<span style="color: #ff0000;">canal.instance.master.address = 192.168.23.1:3306 canal.instance.master.journal.name = canal.instance.master.position = canal.instance.master.timestamp = canal.instance.standby.address =canal.instance.standby.journal.name =canal.instance.standby.position =canal.instance.standby.timestamp =username/password<span style="color: #ff0000;">canal.instance.dbUsername = canal canal.instance.defaultDatabaseName =<span style="color: #ff0000;">datamip canal.instance.connectionCharset = UTF-8 table regex<span style="color: #ff0000;">canal.instance.filter.regex = ... table black regexcanal.instance.filter.black.regex = ################################################# ? ? 上面标红的地方注意下就好了,去偷binlog的时候,需要知道的mysql地址和用户名,密码。
? ? ? 大家要记得把/canal/bin 目录配置到 /etc/profile 的 Path中,方便快速开启,通过下图你会看到22222端口已经在centos上开启了。 [root@localhost bin]# ls
canal.pid startup.bat startup.sh stop.sh
[root@localhost bin]# pwd
/usr/myapp/canal/bin
[root@localhost example]# startup.sh
cd to /usr/myapp/canal/bin for workaround relative path
LOG CONFIGURATION : /usr/myapp/canal/bin/../conf/logback.xml
canal conf : /usr/myapp/canal/bin/../conf/canal.properties
CLASSPATH :/usr/myapp/canal/bin/../conf:/usr/myapp/canal/bin/../lib/zookeeper-3.4.5.jar:/usr/myapp/canal/bin/../lib/zkclient-0.1.jar:/usr/myapp/canal/bin/../lib/spring-2.5.6.jar:/usr/myapp/canal/bin/../lib/slf4j-api-1.7.12.jar:/usr/myapp/canal/bin/../lib/protobuf-java-2.6.1.jar:/usr/myapp/canal/bin/../lib/oro-2.0.8.jar:/usr/myapp/canal/bin/../lib/netty-all-4.1.6.Final.jar:/usr/myapp/canal/bin/../lib/netty-3.2.5.Final.jar:/usr/myapp/canal/bin/../lib/logback-core-1.1.3.jar:/usr/myapp/canal/bin/../lib/logback-classic-1.1.3.jar:/usr/myapp/canal/bin/../lib/log4j-1.2.14.jar:/usr/myapp/canal/bin/../lib/jcl-over-slf4j-1.7.12.jar:/usr/myapp/canal/bin/../lib/guava-18.0.jar:/usr/myapp/canal/bin/../lib/fastjson-1.2.28.jar:/usr/myapp/canal/bin/../lib/commons-logging-1.1.1.jar:/usr/myapp/canal/bin/../lib/commons-lang-2.6.jar:/usr/myapp/canal/bin/../lib/commons-io-2.4.jar:/usr/myapp/canal/bin/../lib/commons-beanutils-1.8.2.jar:/usr/myapp/canal/bin/../lib/canal.store-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.sink-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.server-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.protocol-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.parse.driver-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.parse.dbsync-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.parse-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.meta-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.instance.spring-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.instance.manager-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.instance.core-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.filter-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.deployer-1.0.24.jar:/usr/myapp/canal/bin/../lib/canal.common-1.0.24.jar:/usr/myapp/canal/bin/../lib/aviator-2.2.1.jar:
cd to /usr/myapp/canal/conf/example for continue
[root@localhost example]# netstat -tln
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
tcp6 0 0 :::111 :::* LISTEN
tcp6 0 0 :::22 :::* LISTEN
tcp6 0 0 ::1:631 :::* LISTEN
tcp6 0 0 ::1:25 :::* LISTEN
[root@localhost example]#
? ?canal driver 需要在maven仓库中获取一下:http://www.mvnrepository.com/artifact/com.alibaba.otter/canal.client/1.0.24,不过依赖还是蛮多的。
? ? ? 下面的代码对table的CURD都做了一个基本的判断,看看是不是能够智能感知,然后可以根据实际情况进行redis的更新操作。。。 <span style="color: #0000ff;">import<span style="color: #000000;"> java.awt.Event;
<span style="color: #0000ff;">import<span style="color: #000000;"> java.net.InetSocketAddress; <span style="color: #0000ff;">import<span style="color: #000000;"> java.util.List; <span style="color: #0000ff;">import<span style="color: #000000;"> com.alibaba.otter.canal.client.CanalConnector; <span style="color: #0000ff;">public <span style="color: #0000ff;">class<span style="color: #000000;"> App {
<span style="color: #000000;"> connector.subscribe();
<span style="color: #000000;"> connector.ack(batchID);
<span style="color: #000000;">
<span style="color: #000000;">
} Update操作 Insert操作 Delete 操作 ? ? ?从结果中看,没毛病,有图有真相,好了,本篇就说到这里,对于开发的你,肯定是有帮助的~~~ (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |