在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

緩存與數(shù)據(jù)庫一致性問題如何解決

jf_78858299 ? 來源:阿Q說代碼 ? 作者:阿Q 阿Q說代碼 ? 2023-03-24 14:34 ? 次閱讀

最近不是正好在研究 canal 嘛,剛巧前兩天看了一篇關(guān)于解決緩存與數(shù)據(jù)庫一致性問題的文章,里邊提到了一種解決方案是結(jié)合 canal 來操作的,所以阿Q就想趁熱打鐵,手動(dòng)來實(shí)現(xiàn)一下。

架構(gòu)

文中提到的思想是:

  • 采用先更新數(shù)據(jù)庫,后刪除緩存的方式來解決并發(fā)引發(fā)的一致性問題;
  • 采用異步重試的方式來保證“更新數(shù)據(jù)庫、刪除緩存”這兩步都能執(zhí)行成功;
  • 可以采用訂閱變更日志的方式來清除 Redis 中的緩存;

基于這種思想,阿Q腦海中搭建了以下架構(gòu)

圖片

  • APP 從 Redis 中查詢信息,將數(shù)據(jù)的更新寫入 MySQL 數(shù)據(jù)庫中;
  • Canal 向 MySQL 發(fā)送 dump 協(xié)議,接收 binlog 推送的數(shù)據(jù);
  • Canal 將接收到的數(shù)據(jù)投遞給 MQ 消息隊(duì)列;
  • MQ 消息隊(duì)列消費(fèi)消息,同時(shí)刪除 Redis 中對(duì)應(yīng)數(shù)據(jù)的緩存;

環(huán)境準(zhǔn)備

這篇文章中有 mysql 的安裝教程mysql 安裝

這篇文章中有 canal 的安裝教程以及對(duì) mysql 的相關(guān)配置:canal安裝

考慮到我們服務(wù)器之前安裝過 RabbitMQ ,所以我們就用 RabbitMQ 來充當(dāng)消息隊(duì)列吧。

Canal 配置

修改 conf/canal.properties 配置

# 指定模式
canal.serverMode = rabbitMQ
# 指定實(shí)例,多個(gè)實(shí)例使用逗號(hào)分隔: canal.destinations = example1,example2
canal.destinations = example 

# rabbitmq 服務(wù)端 ip
rabbitmq.host = 127.0.0.1
# rabbitmq 虛擬主機(jī) 
rabbitmq.virtual.host = / 
# rabbitmq 交換機(jī)  
rabbitmq.exchange = xxx
# rabbitmq 用戶名
rabbitmq.username = xxx
# rabbitmq 密碼
rabbitmq.password = xxx
rabbitmq.deliveryMode =

修改實(shí)例配置文件 conf/example/instance.properties

#配置 slaveId,自定義,不等于 mysql 的 server Id 即可
canal.instance.mysql.slaveId=10 

# 數(shù)據(jù)庫地址:配置自己的ip和端口
canal.instance.master.address=ip:port 
 
# 數(shù)據(jù)庫用戶名和密碼 
canal.instance.dbUsername=xxx 
canal.instance.dbPassword=xxx
 
# 指定庫和表
canal.instance.filter.regex=.*\\\\..*    // 這里的 .* 表示 canal.instance.master.address 下面的所有數(shù)據(jù)庫
  
# mq config
# rabbitmq 的 routing key
canal.mq.topic=xxx

然后重啟 canal 服務(wù)。

數(shù)據(jù)庫

建表語句

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

數(shù)據(jù)初始化

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開發(fā)', 87.0000, '2021-03-27 22:43:31', '2021-03-27 22:43:34');

實(shí)戰(zhàn)

項(xiàng)目引入的依賴比較多,為了不占用過多的篇幅,大家可以在公眾號(hào)【阿Q說代碼】后臺(tái)回復(fù)“canal”獲取項(xiàng)目源碼!

MySQL 和 Redis 的相關(guān)配置在此不再贅述,有不懂的可以私聊阿Q:qingqing-4132;

RabbitMQ 配置

@Configuration
public class RabbitMQConfig {

    public static final String CANAL_QUEUE = "canal_queue";//隊(duì)列
    public static final String DIRECT_EXCHANGE = "canal";//交換機(jī),要與canal中配置的相同
    public static final String ROUTING_KEY = "routingkey";//routing-key,要與canal中配置的相同

    /**
     * 定義隊(duì)列
     **/
    @Bean
    public Queue canalQueue(){
        return new Queue(CANAL_QUEUE,true);
    }

    /**
     * 定義直連交換機(jī)
     **/
    @Bean
    public DirectExchange directExchange(){
       return new DirectExchange(DIRECT_EXCHANGE);
    }

    /**
     * 隊(duì)列和交換機(jī)綁定
     **/
    @Bean
    public Binding orderBinding() {
        return BindingBuilder.bind(canalQueue()).to(directExchange()).with(ROUTING_KEY);
    }
}

商品信息入緩存

/**
 * 獲取商品信息:
 * 先從緩存中查,如果不存在再去數(shù)據(jù)庫中查,然后將數(shù)據(jù)保存到緩存中
 * @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.如果緩存中不存在,從數(shù)據(jù)庫獲取信息
 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;
}

執(zhí)行方法后,查看 Redis 客戶端是否有數(shù)據(jù)存入

圖片

更新數(shù)據(jù)入MQ

/**
 * 更新商品信息
 * @param productInfo
 * @return
 */
@PostMapping("/update")
public AjaxResult update(@RequestBody ProductInfo productInfo){
 productInfoService.updateById(productInfo);
 return AjaxResult.success();
}

當(dāng)我執(zhí)行完 update 方法的時(shí)候,去RabbitMQ Management 查看,發(fā)現(xiàn)并沒有消息進(jìn)入隊(duì)列。

問題描述

通過排查之后我在服務(wù)器中 canal 下的 /usr/local/logs/example/example.log文件里發(fā)現(xiàn)了問題所在。

圖片

原因就是meta.dat中保存的位點(diǎn)信息和數(shù)據(jù)庫的位點(diǎn)信息不一致導(dǎo)致 canal 抓取不到數(shù)據(jù)庫的動(dòng)作。

于是我找到 canal 的 conf/example/instance.properties 實(shí)例配置文件,發(fā)現(xiàn)沒有將canal.instance.master.address=127.0.0.1:3306設(shè)置成自己的數(shù)據(jù)庫地址。

解決方案

  • 先停止 canal 服務(wù)的運(yùn)行;
  • 刪除meta.dat文件;
  • 再重啟 canal,問題解決;

再次執(zhí)行 update 方法,會(huì)發(fā)現(xiàn) RabbitMQ Management中已經(jīng)有我們想要的數(shù)據(jù)了。

圖片

MQ接收數(shù)據(jù)

編寫 RabbitMQ 消費(fèi)代碼的邏輯

@RabbitListener(queues = "canal_queue")//監(jiān)聽隊(duì)列名稱
public void getMsg(Message message, Channel channel, String msg) throws IOException {
 long deliveryTag = message.getMessageProperties().getDeliveryTag();
 try {
  log.info("消費(fèi)的隊(duì)列消息來自:" + message.getMessageProperties().getConsumerQueue());

  //刪除reids中對(duì)應(yīng)的key
  ProductInfoDetail productInfoDetail = JSON.parseObject(msg, ProductInfoDetail.class);
  log.info("庫名:"+ productInfoDetail.getDatabase());
  log.info("表名: "+ productInfoDetail.getTable());
  if(productInfoDetail!=null && productInfoDetail.getData()!=null){
   List

當(dāng)我們?cè)俅握{(diào)用 update接口時(shí),控制臺(tái)會(huì)打印以下信息

圖片

從圖中打印的信息可以看出就是我們的庫和表以及消息隊(duì)列,Redis 客戶端中緩存的信息也被刪除了。

拓展

看到這,你肯定會(huì)問:RabbitMQ 是閱后即焚的機(jī)制,它確認(rèn)消息被消費(fèi)者消費(fèi)后會(huì)立刻刪除,如果此時(shí)我們的業(yè)務(wù)還沒有跑完,沒來的及刪除 Redis 中的緩存就宕機(jī)了,豈不是緩存一直都得不到更新了嗎?

首先我們要明確的是 RabbitMQ 是通過消費(fèi)者回執(zhí)來確認(rèn)消費(fèi)者是否成功處理消息的,即消費(fèi)者獲取消息后,應(yīng)該向 RabbitMQ 發(fā)送 ACK 回執(zhí),表明自己已經(jīng)處理消息了。

為了不讓上述問題出現(xiàn),消費(fèi)者返回 ACK 回執(zhí)的時(shí)機(jī)就顯得非常重要了, 而 SpringAMQP 也為我們提供了三種可選的確認(rèn)模式:

  • manual:手動(dòng) ack,需要在業(yè)務(wù)代碼結(jié)束后,調(diào)用 api 發(fā)送 ack;
  • auto:自動(dòng) ack ,由 spring 監(jiān)測(cè) listener 代碼是否出現(xiàn)異常,沒有異常則返回 ack,拋出異常則返回 nack;
  • none:關(guān)閉 ack,MQ 假定消費(fèi)者獲取消息后會(huì)成功處理,因此消息投遞后立即被刪除;

由此可知在 none 模式下消息投遞最不可靠,可能會(huì)丟失消息;在默認(rèn)的 auto 模式下如果出現(xiàn)服務(wù)器宕機(jī)的情況也是會(huì)丟失消息的,本次實(shí)戰(zhàn)中,阿Q為了防止消息丟失采用的是 manual 這種模式,配置信息如下:

spring:
  rabbitmq:
    listener:
      simple:
        acknowledge-mode: manual #開啟手動(dòng)確認(rèn)

所以在代碼中也就出現(xiàn)了

//用于肯定確認(rèn)
channel.basicAck(deliveryTag, true);
//用于否定確認(rèn)
channel.basicReject(deliveryTag ,true);

當(dāng)然此種模式雖然不會(huì)丟失消息,但是會(huì)導(dǎo)致效率變低。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 緩存
    +關(guān)注

    關(guān)注

    1

    文章

    242

    瀏覽量

    26771
  • 數(shù)據(jù)庫
    +關(guān)注

    關(guān)注

    7

    文章

    3852

    瀏覽量

    64740
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    831

    瀏覽量

    26762
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    何解數(shù)據(jù)庫緩存一致性

    緩存一致性 每次逢年過節(jié)的時(shí)候搶票非常艱難,放票的時(shí)候那么多人同時(shí)去搶票,如果所有人查詢、購票等都去訪問數(shù)據(jù)庫,那數(shù)據(jù)庫的壓力得有多大,這時(shí)候很多都會(huì)引入
    的頭像 發(fā)表于 09-25 15:25 ?1175次閱讀
    如<b class='flag-5'>何解</b>決<b class='flag-5'>數(shù)據(jù)庫</b>與<b class='flag-5'>緩存</b><b class='flag-5'>一致性</b>

    理解數(shù)據(jù)庫的事務(wù):ACID,CAP和一致性

    理解數(shù)據(jù)庫的事務(wù),ACID,CAP和一致性
    發(fā)表于 05-04 16:25

    何解決stm32 H7 DMA串口發(fā)送數(shù)據(jù)一致性問題

    何解決stm32 H7 DMA串口發(fā)送數(shù)據(jù)一致性問題
    發(fā)表于 12-06 06:05

    Cache一致性協(xié)議優(yōu)化研究

    現(xiàn)代晶體管技術(shù)在單芯片上集成多個(gè)處理器已經(jīng)成為現(xiàn)實(shí).近年來,隨著多核處理器集成核數(shù)的不斷增加,高速緩存一致性問題凸顯出來,已成為多核處理器的性能瓶頸之,亟待解決.介紹了片上多核處理器一致性
    發(fā)表于 12-30 15:04 ?0次下載
    Cache<b class='flag-5'>一致性</b>協(xié)議優(yōu)化研究

    緩存一致性問題緩存并發(fā)問題

    在高并發(fā)場(chǎng)景下,如果某個(gè)key被高并發(fā)訪問,沒有被命中,出于對(duì)容錯(cuò)性考慮,會(huì)嘗試去從后端數(shù)據(jù)庫中獲取,從而導(dǎo)致了大量請(qǐng)求達(dá)到數(shù)據(jù)庫,而當(dāng)該key對(duì)應(yīng)的數(shù)據(jù)本身就是空的情況下,這就導(dǎo)致
    的頭像 發(fā)表于 08-09 15:52 ?5301次閱讀
    <b class='flag-5'>緩存</b><b class='flag-5'>一致性問題</b>及<b class='flag-5'>緩存</b>并發(fā)問題

    干貨:解決分布式緩存數(shù)據(jù)庫的雙存儲(chǔ)雙寫

    分布式緩存是現(xiàn)在很多分布式應(yīng)用中必不可少的組件,但是用到了分布式緩存,就可能會(huì)涉及到緩存數(shù)據(jù)庫雙存儲(chǔ)雙寫,你只要是雙寫,就一定會(huì)有數(shù)據(jù)一致性
    的頭像 發(fā)表于 09-03 10:58 ?2647次閱讀
    干貨:解決分布式<b class='flag-5'>緩存</b>與<b class='flag-5'>數(shù)據(jù)庫</b>的雙存儲(chǔ)雙寫

    管理基于Cortex?-M7的MCU的高速緩存一致性

    本文檔概述了不同場(chǎng)景下的高速緩存一致性問題,并就如何管理或避免高速緩存一致性問題提供了些方法建議。
    發(fā)表于 04-01 10:12 ?5次下載
    管理基于Cortex?-M7的MCU的高速<b class='flag-5'>緩存</b><b class='flag-5'>一致性</b>

    Redis緩存更新一致性的方式

    當(dāng)執(zhí)行寫操作后,需要保證從緩存讀取到的數(shù)據(jù)數(shù)據(jù)庫中持久化的數(shù)據(jù)一致的,因此需要對(duì)緩存進(jìn)行更新
    的頭像 發(fā)表于 11-21 10:40 ?805次閱讀

    聊聊緩存數(shù)據(jù)庫一致性

    在云服務(wù)中,緩存是極其重要的點(diǎn)。所謂緩存,其實(shí)是個(gè)高速數(shù)據(jù)存儲(chǔ)層。當(dāng)緩存存在后,日后再次請(qǐng)求
    的頭像 發(fā)表于 01-30 17:41 ?834次閱讀

    異構(gòu)數(shù)據(jù)庫排序一致性填坑教程

    不同數(shù)據(jù)庫對(duì)于字符值的排序規(guī)則各不相同,要達(dá)成在不同數(shù)據(jù)庫上對(duì)于同樣數(shù)據(jù)集執(zhí)行查詢語句的輸出結(jié)果順序一致性目標(biāo),則必須進(jìn)行相應(yīng)的設(shè)置或改寫,本文通過對(duì)五種
    的頭像 發(fā)表于 03-29 13:43 ?1024次閱讀
    異構(gòu)<b class='flag-5'>數(shù)據(jù)庫</b>排序<b class='flag-5'>一致性</b>填坑教程

    緩存數(shù)據(jù)庫雙寫一致性幾種策略分析

    在高并發(fā)場(chǎng)景中,為防止大量請(qǐng)求直接訪問數(shù)據(jù)庫,緩解數(shù)據(jù)庫壓力,常用的方式般會(huì)增加緩存層起到緩沖作用,減少數(shù)據(jù)庫壓力。
    的頭像 發(fā)表于 04-21 10:27 ?705次閱讀

    虹科干貨 | 什么是數(shù)據(jù)庫一致性

    數(shù)據(jù)庫一致性(database consistency)由組值定義,數(shù)據(jù)庫系統(tǒng)中的所有數(shù)據(jù)點(diǎn)都必須與這些值保持
    的頭像 發(fā)表于 07-13 13:56 ?692次閱讀
    虹科干貨 | 什么是<b class='flag-5'>數(shù)據(jù)庫</b><b class='flag-5'>一致性</b>?

    使用MPLAB Harmony v3基于PIC32MZ MCU在運(yùn)行時(shí)使用高速緩存維護(hù)操作處理高速緩存一致性問題

    電子發(fā)燒友網(wǎng)站提供《使用MPLAB Harmony v3基于PIC32MZ MCU在運(yùn)行時(shí)使用高速緩存維護(hù)操作處理高速緩存一致性問題.pdf》資料免費(fèi)下載
    發(fā)表于 09-19 16:28 ?0次下載
    使用MPLAB Harmony v3基于PIC32MZ MCU在運(yùn)行時(shí)使用高速<b class='flag-5'>緩存</b>維護(hù)操作處理高速<b class='flag-5'>緩存</b><b class='flag-5'>一致性問題</b>

    如何保證緩存一致性

    “ 本文的參考文章是2022年HOT 34上Intel Rob Blakenship關(guān)于CXL緩存一致性篇介紹。”
    的頭像 發(fā)表于 10-19 17:42 ?1255次閱讀
    如何保證<b class='flag-5'>緩存</b><b class='flag-5'>一致性</b>

    Redis緩存與Mysql如何保證一致性

    基本流程就是客戶端A請(qǐng)求,先去刪除緩存,然后將數(shù)據(jù)寫入數(shù)據(jù)庫,此時(shí)客戶端B查詢先去查詢緩存緩存沒有返回,去查
    的頭像 發(fā)表于 12-02 14:23 ?979次閱讀
    Redis<b class='flag-5'>緩存</b>與Mysql如何保證<b class='flag-5'>一致性</b>?
    主站蜘蛛池模板: aa视频在线| 手机福利片 | 5g影院午夜伴侣 | 免费的色视频 | 亚洲成a人片77777潘金莲 | 三级精品视频在线播放 | 色偷偷亚洲男人 | 性殴美高清视频 | 992tv国产精品福利在线 | 国产精品777 | 岛国毛片一级一级特级毛片 | 8090yy理论三级在线观看 | 俺也射 | 亚洲成人综合网站 | 久久天天丁香婷婷中文字幕 | 亚洲a人片在线观看网址 | 欧美性黑人极品1819hd | 国产无套视频在线观看香蕉 | 狠狠色丁香婷婷综合欧美 | 欧美成人精品欧美一级乱黄 | 黄a视频| 四虎影视免费观看 | 你懂得福利 | 欧美在线不卡视频 | 78摸在线 | h免费在线观看 | mmmxxx69日本 | 国产视频h | 在线观看高清免费播放 | 黄床大片 | 新天堂 | 国产资源视频在线观看 | 欧美一区二区视频 | 91色吧| 卡一卡二卡三国色天香永不失联 | 在线观看二区三区午夜 | 亚洲一区二区三区在线网站 | 免费看欧美一级特黄a大片 免费看欧美一级特黄a大片一 | 久久五月女厕所一区二区 | 牛牛a级毛片在线播放 | 国模娜娜扒开嫩木耳 |