范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

实现缓存和数据库一致性方案实战mysqlcanalrabbitmqredis

  最近不是正好在研究 canal 嘛,刚巧前两天看了一篇关于解决缓存与数据库一致性问题的文章,里边提到了一种解决方案是结合 canal 来操作的,所以阿Q就想趁热打铁,手动来实现一下。架构
  文中提到的思想是:采用先更新数据库,后删除缓存的方式来解决并发引发的一致性问题;采用异步重试的方式来保证"更新数据库、删除缓存"这两步都能执行成功;可以采用订阅变更日志的方式来清除 Redis 中的缓存;
  基于这种思想,阿Q脑海中搭建了以下架构
  APP 从 Redis 中查询信息,将数据的更新写入 MySQL 数据库中;Canal 向 MySQL 发送 dump 协议,接收 binlog 推送的数据;Canal 将接收到的数据投递给 MQ 消息队列;MQ 消息队列消费消息,同时删除 Redis 中对应数据的缓存;环境准备
  这篇文章中有 mysql 的安装教程:mysql 安装
  这篇文章中有 canal 的安装教程以及对 mysql 的相关配置:canal安装
  考虑到我们服务器之前安装过 RabbitMQ ,所以我们就用 RabbitMQ 来充当消息队列吧。Canal 配置
  修改 conf/canal.properties 配置# 指定模式 canal.serverMode = rabbitMQ # 指定实例,多个实例使用逗号分隔: canal.destinations = example1,example2 canal.destinations = example   # rabbitmq 服务端 ip rabbitmq.host = 127.0.0.1 # rabbitmq 虚拟主机  rabbitmq.virtual.host = /  # rabbitmq 交换机   rabbitmq.exchange = xxx # rabbitmq 用户名 rabbitmq.username = xxx # rabbitmq 密码 rabbitmq.password = xxx rabbitmq.deliveryMode = 复制代码
  修改实例配置文件 conf/example/instance.properties#配置 slaveId,自定义,不等于 mysql 的 server Id 即可 canal.instance.mysql.slaveId=10   # 数据库地址:配置自己的ip和端口 canal.instance.master.address=ip:port    # 数据库用户名和密码  canal.instance.dbUsername=xxx  canal.instance.dbPassword=xxx 	 # 指定库和表 canal.instance.filter.regex=.*..*    // 这里的 .* 表示 canal.instance.master.address 下面的所有数据库 		 # mq config # rabbitmq 的 routing key canal.mq.topic=xxx 复制代码
  然后重启 canal 服务。
  这篇文章中有 RabbitMQ 的安装教程:RabbitMQ安装
  这篇文章中有 Redis 的安装教程:Redis安装数据库
  建表语句CREATE TABLE `product_info` (   `id` bigint(20) NOT NULL AUTO_INCREMENT,   `name` varchar(255) DEFAULT NULL,   `price` decimal(10,4) DEFAULT NULL,   `create_date` datetime DEFAULT NULL,   `update_date` datetime DEFAULT NULL,   PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 复制代码
  数据初始化INSERT INTO cheetah.product_info (id, name, price, create_date, update_date) VALUES(1, "从你的全世界路过", 14.0000, "2020-11-21 21:26:12", "2021-03-27 22:17:39"); INSERT INTO cheetah.product_info (id, name, price, create_date, update_date) VALUES(2, "乔布斯传", 25.0000, "2020-11-21 21:26:42", "2021-03-27 22:17:42"); INSERT INTO cheetah.product_info (id, name, price, create_date, update_date) VALUES(3, "java开发", 87.0000, "2021-03-27 22:43:31", "2021-03-27 22:43:34"); 复制代码实战
  项目引入的依赖比较多,为了不占用过多的篇幅,大家可以在后台回复"canal"获取项目源码!
  MySQL 和 Redis 的相关配置在此不再赘述,有不懂的可以私聊阿QRabbitMQ 配置@Configuration public class RabbitMQConfig {      public static final String CANAL_QUEUE = "canal_queue";//队列     public static final String DIRECT_EXCHANGE = "canal";//交换机,要与canal中配置的相同     public static final String ROUTING_KEY = "routingkey";//routing-key,要与canal中配置的相同      /**      * 定义队列      **/     @Bean     public Queue canalQueue(){         return new Queue(CANAL_QUEUE,true);     }      /**      * 定义直连交换机      **/     @Bean     public DirectExchange directExchange(){        return new DirectExchange(DIRECT_EXCHANGE);     }      /**      * 队列和交换机绑定      **/     @Bean     public Binding orderBinding() {         return BindingBuilder.bind(canalQueue()).to(directExchange()).with(ROUTING_KEY);     } } 复制代码商品信息入缓存/**  * 获取商品信息:  * 先从缓存中查,如果不存在再去数据库中查,然后将数据保存到缓存中  * @param productInfoId  * @return  */ @Override public ProductInfo findProductInfo(Long productInfoId) { 	//1.从缓存中获取商品信息 	Object object = redisTemplate.opsForValue().get(REDIS_PRODUCT_KEY + productInfoId); 	if(ObjectUtil.isNotEmpty(object)){ 		return (ProductInfo)object; 	} 	//2.如果缓存中不存在,从数据库获取信息 	ProductInfo productInfo = this.baseMapper.selectById(productInfoId); 	if(productInfo != null){ 		//3.将商品信息缓存 		redisTemplate.opsForValue().set(REDIS_PRODUCT_KEY+productInfoId, productInfo, 				REDIS_PRODUCT_KEY_EXPIRE, TimeUnit.SECONDS); 		return productInfo; 	} 	return null; } 复制代码
  执行方法后,查看 Redis 客户端是否有数据存入
  更新数据入MQ/**  * 更新商品信息  * @param productInfo  * @return  */ @PostMapping("/update") public AjaxResult update(@RequestBody ProductInfo productInfo){ 	productInfoService.updateById(productInfo); 	return AjaxResult.success(); } 复制代码
  当我执行完 update 方法的时候,去RabbitMQ Management 查看,发现并没有消息进入队列。问题描述
  通过排查之后我在服务器中 canal 下的 /usr/local/logs/example/example.log 文件里发现了问题所在。
  原因就是meta.dat中保存的位点信息和数据库的位点信息不一致导致 canal 抓取不到数据库的动作。
  于是我找到 canal 的 conf/example/instance.properties 实例配置文件,发现没有将canal.instance.master.address=127.0.0.1:3306 设置成自己的数据库地址。
  解决方案先停止 canal 服务的运行;删除meta.dat文件;再重启 canal,问题解决;
  再次执行 update 方法,会发现 RabbitMQ Management中已经有我们想要的数据了。
  MQ接收数据
  编写 RabbitMQ 消费代码的逻辑@RabbitListener(queues = "canal_queue")//监听队列名称 public void getMsg(Message message, Channel channel, String msg) throws IOException { 	long deliveryTag = message.getMessageProperties().getDeliveryTag(); 	try { 		log.info("消费的队列消息来自:" + message.getMessageProperties().getConsumerQueue());  		//删除reids中对应的key 		ProductInfoDetail productInfoDetail = JSON.parseObject(msg, ProductInfoDetail.class); 		log.info("库名:"+ productInfoDetail.getDatabase()); 		log.info("表名: "+ productInfoDetail.getTable()); 		if(productInfoDetail!=null && productInfoDetail.getData()!=null){ 			List data = productInfoDetail.getData(); 			ProductInfo productInfo = data.get(0); 			if(productInfo!=null){ 				Long id = productInfo.getId(); 				redisTemplate.delete(REDIS_PRODUCT_KEY+id); 				channel.basicAck(deliveryTag, true); 				return; 			} 		} 		channel.basicReject(deliveryTag ,true); 		return; 	}catch (Exception e){ 		channel.basicReject(deliveryTag,false); 		e.printStackTrace(); 	} } 复制代码
  当我们再次调用 update接口时,控制台会打印以下信息
  从图中打印的信息可以看出就是我们的库和表以及消息队列,Redis 客户端中缓存的信息也被删除了。拓展
  看到这,你肯定会问:RabbitMQ 是阅后即焚的机制,它确认消息被消费者消费后会立刻删除,如果此时我们的业务还没有跑完,没来的及删除 Redis 中的缓存就宕机了,岂不是缓存一直都得不到更新了吗?
  首先我们要明确的是 RabbitMQ 是通过消费者回执来确认消费者是否成功处理消息的,即消费者获取消息后,应该向 RabbitMQ 发送 ACK 回执,表明自己已经处理消息了。
  为了不让上述问题出现,消费者返回 ACK 回执的时机就显得非常重要了, 而 SpringAMQP 也为我们提供了三种可选的确认模式:manual:手动 ack,需要在业务代码结束后,调用 api 发送 ack;auto:自动 ack ,由 spring 监测 listener 代码是否出现异常,没有异常则返回 ack,抛出异常则返回 nack;none:关闭 ack,MQ 假定消费者获取消息后会成功处理,因此消息投递后立即被删除;
  由此可知在 none 模式下消息投递最不可靠,可能会丢失消息;在默认的 auto 模式下如果出现服务器宕机的情况也是会丢失消息的,本次实战中,阿Q为了防止消息丢失采用的是 manual 这种模式,配置信息如下:spring:   rabbitmq:     listener:       simple:         acknowledge-mode: manual #开启手动确认 复制代码
  所以在代码中也就出现了//用于肯定确认 channel.basicAck(deliveryTag, true); //用于否定确认 channel.basicReject(deliveryTag ,true); 复制代码
  当然此种模式虽然不会丢失消息,但是会导致效率变低。
  今天的内容到这里就结束了,赶快动手体验一下吧!
  作者:阿Q说代码
  链接:https://juejin.cn/post/7210979444759494712
  来源:稀土掘金
  著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

国际罕见病日为何父母都健康,孩子却有遗传病我们夫妻双方都没有任何问题,所以我的宝宝也不会有任何问题!这句话可能是绝大多数家长甚至是长辈们的一句至理名言。在他们根深蒂固的观念里,爸爸妈妈只要没有任何疾病,孩子就不可能有遗传病女子生娃7个月后发现自己怀孕数月,想打掉被劝阻,孩子出生后悔我是有点后悔,后悔当时听了医生的建议,把孩子生了下来医院里,妈妈邹慧娇哽咽说道。如果时间能倒退到2019年11月,邹慧娇想,自己一定不会再做出这样的选择。图为妈妈和宇宸。来自湖南省管中窥豹,一叶知秋(论高德合烟花游戏)合烟花游戏是高德12月份上线的一款休闲游戏,一上线吸引了大批羊毛档,只因为玩它可以获取现金,第一次提现日期在今年春节期间,第二次提现在今天上午10点整。这游戏玩法很简单,就是合球得ampampquot中国足球最缺乏的是什么?ampampquot中国足球目前最缺乏的是什么?中国足球,一个充满希望与失望的话题。我想起鲁迅先生曾经说过我们的现实,就是一个深渊。是啊,中国足球似乎就是这样一个深渊,让人深感无从逃脱。作为一个长期关中国体育电影难在哪里?很多东西其实并不可以放到台面上去说,但确实中国体育电影有它的困难电影中国乒乓之绝地反击出品人陈辉说。曾被寄予票房厚望,并被期待为中国体育电影树立新坐标的中国乒乓之绝地反击,最终还是不是王皓是王浩,中国乒乓奇兵揭秘,俞灏明酷似原型中国乒乓之绝地反击上映后因票房不高被一些媒体嘲讽,但其口碑没有下降反而上扬,证明看过电影的多数观众都认为该片是超值的。这部电影从笔者角度看之所以感到超值,可能有三点原因一是故事并不博物馆里抗日故事,是什么让中国人喊出大刀向鬼子们头上砍去?大刀向鬼子们的头上砍去!全国爱国的同胞们,抗战的一天来到了!当二十九军大刀杀敌的捷报传来,与千千万万国人们一样。青年麦新欣喜若狂,备受鼓舞。兴奋之余,谱写出饱含战斗激情的大刀进行曲美版知乎为什么人们对打开中国第一位皇帝的陵墓充满恐惧?秦始皇是中国的始皇帝,他的陵墓中不仅有各种奇珍异宝,还会有许多不为人知的历史信息,如果发掘秦始皇陵,那将会是一件震撼世界考古史的大事,为什么国家却要对秦始皇陵采取保护措施,禁止发掘在一朵花开的路上作者乡人在一朵盛开的桃花里找到进入的路径沿着又一年春色的脚印开拓世外桃源花静静开放水慢慢流动我摸着跳跃的心口想象着又一年的美景阳光打在脸上在花瓣中延伸桃之夭夭,灼灼其华理想在蠢蠢欲前文化部长王蒙不要相信那些自己不做什么却要求别人冲呀冲的人愈是处在逆境下愈要争取生活的快乐与学习的长进。生活是不可战胜的,邪恶者永远不可能全部摧毁生活的乐趣。文革当中我在新疆农村,被剥夺了写作的权利与参加政治生活的权利,我的前途十分渺茫,这是一个关乎14亿多人的大项目!我是逐梦太空的航天员我是拼搏赛场的运动员我是逆行而上的守护者我是大国工程的建设者我意气风发为梦想追寻我昼夜不停为美好奔走我白衣执甲为生命护航我其实是每一个平凡的中国人在奔向美好的路
马来西亚各地舞狮团缺学员广招新生应对订单中国侨网7月27日电据马来西亚诗华日报报道,马来西亚全国各地近50舞狮团缺学员,目前正紧锣密鼓广招新生,应对源源不绝的订单。早前,在面临疫情时,许多原有的学员为了生活纷纷离队,如今这三样料,只要给牛羊兔鸡一用,清热解毒,增重又赚钱,谁都羡慕最近,在一位网友说,他饲养了700只肉鸡,350只奶山羊,80头肉牛和150只家兔,在炎热的夏天,用上这三样不值钱的料,能让牛羊兔鸡清热解毒,解渴除烦,安全度夏,更大的好处是增重快子宫癌的症状都有什么表现子宫癌症状1阴道出血不规则阴道出血,特别是接触性出血(即性生活或妇科检查后出血)和绝经后阴道出血是宫颈癌患者的主要症状。花椰菜宫颈癌出血较早,出血较多。2。阴道分泌物增多白色稀薄,关于进一步减轻义务教育阶段学生作业负担和校外培训负担的意见印发一年来习近平总书记强调,义务教育是国民教育的重中之重,要全面贯彻党的教育方针,落实立德树人根本任务,充分发挥学校教书育人主体功能,强化线上线下校外培训机构规范管理。一年前,中办国办印发关第一财经研究院2022中国宏观经济半年报且共风雨发布前言这注定是经历风雨要付出更多艰辛和努力的一年这也是我们在成长和积蓄了很久的力量需要在风险来临时发挥持续的韧性和容纳更多不确定性的时期。2022年年初以来,中国国内超预期的新冠疫情李克强会见印尼总统央广网北京7月27日消息据中央广播电视总台中国之声新闻和报纸摘要报道,国务院总理李克强7月26日下午在京会见印尼总统佐科。李克强表示,中国与印尼是友好近邻,同为本地区发展中大国。习31岁四川女子生下儿子后,男友突然失踪,竟然是回老家结婚去了四川荥经县,31岁的江心雨抱着孩子,满眼无助,而在不远处,一户贴着大红喜字的人家,大门紧闭,似乎对于她的到来十分不欢迎。江心雨江心雨怀中的孩子是她跟男友王华洪所生,然而就在她生下孩FC法国?拜仁一线队已有8位法国籍球员,马内等人也说法语直播吧7月27日讯拜仁已经官宣签下雷恩17岁前锋特尔,这也让拜仁队内的法语系进一步壮大。在赫内斯鲁梅尼格时期,拜仁奉行FC德国战略,尽力收集德国国脚。而在海纳卡恩主政之后,拜仁更趋总有一天你会明白,能治愈你的,从来都不是时间总有一天你会明白,能治愈你的,从来都不是时间,而是心里的那股释怀和淡然。我一直觉得有德报德有怨报怨才是正确的人生态度。欺负完人就让人大度了?骂两句也要骂的。人二叔也许夜里早就骂了千殷世航带新女友出席小猪婚礼,被嘲眼光越来越差,还不如套路璐小猪先生和兜儿的婚礼,昨天已经圆满礼成,兜儿努力了这么长时间,终于能被大众认可了。值得一提的是,兜儿这次的4个伴娘,有2个是男人,剩下的2个都跟殷世航有关系。殷世航作为小猪先生的兄小猪先生泪洒婚礼现场,哭得很尴尬,网友不知道的还以为是头婚小猪先生虽然是第二次结婚,可是他看起来很重视这次婚姻,感性的他泪洒婚礼现场,不过哭得很是尴尬,有网友一针见血地评论道不知道的还以为是头婚。倘若下次小猪先生没钱,就会再办一场婚礼了,