一、业务场景

  Web项目开发中,为了加快数据处理的的效率,大量的使用了各种缓存,缓存技术主要使用的是redis。导致出现的小小的

问题是对redis缓存形成了一个比较强的依赖,并且有的数据暂时是没有同步到业务数据库当中进行存储的,有不少数据都是直

接从缓存中获取。这种处理方式确实加快了数据的处理效率,可是也存在一些问题。

二、需求分析

  当前由于系统要进行迁移,以前保存在一台服务器上面的redis中的数据,是不可能迁移的。即使运维人员愿意迁移,操作起来

也是相当的麻烦。还有一个问题,如果发现缓存中的数据存在异常,如何使用某种机制去自动更新缓存或者是手动更新缓存数据,让

缓存中的数据和数据库中的最终趋于一致,并且保证数据的正确性呢?这就需要做缓存恢复。

三、解决方案

  缓存恢复只针对时效性比较长的数据,如果某些缓存数据几分钟更新一次,或者十几分钟更新一次,这种缓存数据就可以考虑不用

恢复。对于某些没有失效时间限制的一些缓存数据,就需要做这种处理。需要使用的地方:一种情况是系统迁移的时候;一种情况是缓存

数据出现问题,需要采取某种措施更新缓存的时候。下面就来聊聊两种缓存更新的方式。

.方式一:通过接口请求更新缓存.

这种方式比较常规,就是写一个普通的接口,发一个请求到后台,传递对应的参数进行缓存更新操作。这种操作方式是立马全量更新

所有的缓存数据。对于数据量不大的业务比较适合,更新的时间也不会太久,预估可能就一两分钟的样子。可是当数据量很大的时候,

比如少说几十万甚至更多的数据都需要添加到缓存中,这种应该如何处理呢?

public boolean updateTest() {
Map<Integer, List<TransmitActivityTotal>> transmitActivityTotalMap = new HashMap<>(30);
List<TransmitActivityTotal> transmitActivityTotals = null;
StopWatch stopWatch = new StopWatch();
stopWatch.start();
try {
// 查询数据
for(int i = 0; i < 30; i++){
// 根据不同的分表信息查询不同的数据
transmitActivityTotals = null;
transmitActivityTotalMap.put(i, transmitActivityTotals);
}

// 处理数据
if (transmitActivityTotalMap.isEmpty()) {
return false;
}
Map<Long, Integer> idTotalMap = new HashMap<>();
Integer total = null;
for(Map.Entry<Integer, List<TransmitActivityTotal>> item : transmitActivityTotalMap.entrySet()) {
for(TransmitActivityTotal transmitActivityTotal : item.getValue()) {
total = transmitActivityTotal.getTotal() == null ? Integer.valueOf(0) : transmitActivityTotal.getTotal();
if (idTotalMap.keySet().contains(transmitActivityTotal.getId())) {
// 再次添加 原有数据 + 新数据
idTotalMap.put(transmitActivityTotal.getId(), idTotalMap.get(transmitActivityTotal.getId()) + total);
} else {
// 首次添加
idTotalMap.put(transmitActivityTotal.getId(), total);
}
}
}

for(Map.Entry<Long, Integer> item : idTotalMap.entrySet()) {
// 使用redis进行 恢复缓存 操作
log.info("id-->{}, 数量--->", item.getKey(), item.getValue());
}
stopWatch.stop();
log.info("缓存恢复耗时--->{}毫秒", stopWatch.getLastTaskTimeMillis());
return true;
} catch (Exception ex) {
stopWatch.stop();
log.error("缓存更新异常--->{}", ex);
return false;
}
}

方式二:通过数据字典表来控制缓存的更新。

自己目前所参与开发的项目,在项目启动的时候,会将所有的数据字典信息添加到缓存当中,并且会隔几分钟去更新一次数据字典数据。

就是利用这一点来增量更新缓存信息,比如每次只更新某个用户相关的操作数据,而不是一次性更新所有用户的数据。减轻了服务器的压力,

这种处理方式也更加的符合实际需求。举一个简单的示例,首先考虑兼容性问题,在设计的时候可以在数据字典中添加一个值,当这个值

为OLD的时候,就使用旧有的逻辑,直接从缓存中获取数据;如果是新系统,则可以在页面中将这个数据字典表的值设置为NEW,这时就

使用新的逻辑,先从数据库中去查询数据,然后将查询结果保存在缓存中。这样设计就能够兼容之前的系统,也可以进行系统的迁移。这里

还存在一个问题,就是使用新系统时,不可能每次都去查询数据库,然后将数据存入缓存中。这时就可以添加第二个数据字典值,称它为数

据版本吧,比如设置为100,也是先从缓存中获取这个数据字典值a,然后从缓存中获取获取数据版本值b,判断值a和值b是否一致。一致

则直接返回缓存数据。不一致则查询数据库,然后更新缓存,并且将缓存中的数据版本的值更新为数据字典的值。这样在后台管理系统中,

更新数据版本的值,就可以动态的更新缓存数据的值,并且每次更新的缓存数据量很少。

这种设计稍微有些复杂,还是需要好好理解,自己最开始的时候也是没有理解这种缓存恢复的方式。去询问负责人之后,才搞清楚是如何

进行设计的。明白之后才开始写代码,最后进行测试,测试结论通过。

redis缓存恢复-2022新项目的更多相关文章

  1. mybatis-拦截器实际应用-替换表名-2022新项目

    一.业务场景 考虑到新项目中部分与业务数据相关的表在后期数据量会比较大,架构师在最开始设计项目中与业务数据相关的表时,就已经考虑使用分表来 进行处理,给业务数据相关的每张表都添加统一批次的后缀,查询这 ...

  2. 无法访问mybatis.dto.StudengInVO-使用maven编译报错-2022新项目

    一.问题由来 最近一次拉代码后,合并代码然后进行编译时出现一个问题,使用maven在进行编译的时候报一个错,无法访问mybatis.dto.StudengInVO. 突然出现这个错误让自己感觉很奇怪, ...

  3. 项目开发中Maven的单向依赖-2022新项目

    一.业务场景 工作多年,在真实的项目开发中经常会遇到将一个项目拆分成多个工程的情况,比如将一个真实的项目拆分成controller层,service层, dao层,common公共服务层等等.这样拆分 ...

  4. Java异步记录日志-2022新项目

    一.业务场景 web项目开发中,经常会有的一个操作是记录请求日志,比如记录请求的IP地址,记录请求的路径,记录请求的参数等等. 每个系统都会根据自己的需要来记录一些请求相关的日志.一般会将记录的日志信 ...

  5. 程序包 applets.user.service.UserService 不存在-2022新项目

    一.问题由来 接上一篇文章使用maven进行打包时报中文乱码错误,经过多次尝试后最终解决问题,显示出真正的错误信息如下: 程序包 applets.user.service.UserService 不存 ...

  6. git实战-多分支开发-2022新项目

    现在开发中大多数公司中都在使用Git这个代码版本管理工具,几乎可以说是已经成为标配,刚入职不久的这家新公司也不例外. 去公司没多久,开始搭建项目,然后创建开发分支,有多少个后端人员就创建多少个开发分支 ...

  7. Java中list集合自定义排序-2022新项目

    一.业务场景 为了加快首页数据查询的效率,因此将首页查询的数据大多数都放在了缓存中,包括各种list集合数据.对这些 从缓存中获取的数据做了一个兜底处理,如果从缓存中没有获取到数据,则直接从数据库中去 ...

  8. postgresql使用group by进行数据去重-2022新项目

    一.业务场景 数据去重是web开发中经常会遇到的方式之一,数据库操作中有一个关键字distinct主要就是用来做这件事,用来进行去重. 比如进行统计查询的时候,可以这样写 select count(d ...

  9. SpringBoot微服务电商项目开发实战 --- Redis缓存雪崩、缓存穿透、缓存击穿防范

    最近已经推出了好几篇SpringBoot+Dubbo+Redis+Kafka实现电商的文章,今天再次回到分布式微服务项目中来,在开始写今天的系列五文章之前,我先回顾下前面的内容. 系列(一):主要说了 ...

随机推荐

  1. 1.为什么要从古典概率入门概率学《zobol的考研概率论教程》

    在入门概率论与数理统计这门课中,刚开始我们都会从古典概率开始学习,为什么要选择它呢?这是因为古典概率作为一种将生活中的事情简化为有限种情况,并假设它们的发生可能差不多的手段,十分的好用且简洁. 这里我 ...

  2. Elasticsearch学习系列三(搜索案例实战)

    Query DSL Es提供了基于JSON的完整查询DSL(Domain Specific Language 特定域的语言)来定义查询.将查询DSL视为查询的AST(抽象语法树).它由两种子句组成: ...

  3. 解决nginx反向代理Mixed Content和Blockable问题

    nginx配置https反向代理,按F12发现js等文件出现Mixed Content,Optionally-blockable 和 Blockable HTTPS 网页中加载的 HTTP 资源被称之 ...

  4. jieba分词原理解析:用户词典如何优先于系统词典

    目标 查看jieba分词组件源码,分析源码各个模块的功能,找到分词模块,实现能自定义分词字典,且优先级大于系统自带的字典等级,以医疗词语邻域词语为例. jieba分词地址:github地址:https ...

  5. Python快速下载商品数据,并连接数据库,保存数据

    开发环境 python 3.8 pycharm 2021.2 专业版 代码实现 发送请求 获取数据 解析数据(筛选数据) 保存数据 连接数据库 开始代码 请求数据 # 伪装 headers = { ' ...

  6. 业务可视化-让你的流程图"Run"起来

    前言 最近在研究业务可视化的问题,在日常的工作中,流程图和代码往往是分开管理的. 一个被维护多次的系统,到最后流程图和代码是否匹配这个都很难说. 于是一直有一个想法,让程序直接读流程图,根据流程图的配 ...

  7. 我是如何将一个老系统的kafka消费者服务的性能提升近百倍的

    ☞☞☞ 我是如何将一个老系统的kafka消费者服务的性能提升近百倍的 ☜☜☜ ○○○○○○○○○○○○○○○ 大家好,又见面了~ kafka作为一种高吞吐量的分布式发布订阅消息系统,在业务系统中被广泛 ...

  8. [ZJCTF 2019]NiZhuanSiWei 1

    考察知识点:反序列化.php伪协议 1.打开之后获得源码信息,如下: <?php $text = $_GET["text"]; $file = $_GET["fil ...

  9. 彻底弄清楚session,cookie,sessionStorage,localStorage的区别及应用场景(面试向)

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_94 客户端状态保持是一个老生常谈的问题了,归根结底追踪浏览器的用户身份及其相关数据无非就是以下四种方式:session,cooki ...

  10. 如何基于WPF写一款数据库文档管理工具(二)

    系列目录 基于WPF重复造轮子,写一款数据库文档管理工具(一) 本篇重点 上次发表了基于WPF重复造轮子,写一款数据库文档管理工具(一) 得到不少人支持,文章一度上到了博客园推荐表首页,看来大家对这个 ...