点击下方“IT牧场”,选择“设为星标”

来源:juejin.cn/post/7000263632151904293

  • 前言

  • 设计示例

    • Redis结合本地缓存

    • 后记


前言

我们开发中经常用到Redis作为缓存,将高频数据放在Redis中能够提高业务性能,降低MySQL等关系型数据库压力,甚至一些系统使用Redis进行数据持久化,Redis松散的文档结构非常适合业务系统开发,在精确查询,数据统计业务有着很大的优势。

但是高频数据流处理系统中,Redis的压力也会很大,同时I/0开销才是耗时的主要原因,这时候为了降低Redis读写压力我们可以用到本地缓存,Guava为我们提供了优秀的本地缓存API,包含了过期策略等等,编码难度低,个人非常推荐。

设计示例

Redis懒加载缓存

数据在新增到MySQL不进行缓存,在精确查找进行缓存,做到查询即缓存,不查询不缓存

流程图

图片

代码示例

// 伪代码示例 Xx代表你的的业务对象 如User Goods等等
public class XxLazyCache {@Autowiredprivate RedisTemplate<String, Xx> redisTemplate;@Autowiredprivate XxService xxService;// 你的业务service/*** 查询 通过查询缓存是否存在驱动缓存加载 建议在前置业务保证id对应数据是绝对存在于数据库中的*/public Xx getXx(int id) {// 1.查询缓存里面有没有数据Xx xxCache = getXxFromCache(id);if(xxCache != null) {return xxCache;// 卫语句使代码更有利于阅读}// 2.查询数据库获取数据 我们假定到业务这一步,传过来的id都在数据库中有对应数据Xx xx = xxService.getXxById(id);// 3.设置缓存、这一步相当于Redis缓存懒加载,下次再查询此id,则会走缓存setXxFromCache(xx);return xx;}}/*** 对xx数据进行修改或者删除操作 操作数据库成功后 删除缓存* 删除请求 - 删除数据库数据 删除缓存* 修改请求 - 更新数据库数据 删除缓存 下次在查询时候就会从数据库拉取新的数据到缓存中*/public void deleteXxFromCache(long id) {String key = "Xx:" + xx.getId();redisTemplate.delete(key);}private void setXxFromCache(Xx xx) {String key = "Xx:" + xx.getId();redisTemplate.opsForValue().set(key, xx);}private Xx getXxFromCache(int id) {// 通过缓存前缀拼装唯一主键作为缓存Key 如Xxx信息 就是Xxx:idString key = "Xx:" + id;return redisTemplate.opsForValue().get(key);}}
// 业务类
public class XxServie {@Autowiredprivate XxLazyCache xxLazyCache;// 查询数据库public Xx getXxById(long id) {// 省略实现return xx;}public void updateXx(Xx xx) {// 更新MySQL数据 省略// 删除缓存xxLazyCache.deleteXxFromCache(xx.getId());}public void deleteXx(long id) {// 删除MySQL数据 省略// 删除缓存xxLazyCache.deleteXxFromCache(xx.getId());}
}
// 实体类
@Data
public class Xx {// 业务主键private Long id;// ...省略
}

优点

  • 保证最小的缓存量满足精确查询业务,避免冷数据占用宝贵的内存空间

  • 对增删改查业务入侵小、删除即同步

  • 可插拔,对于老系统升级,历史数据无需在启动时初始化缓存

缺点

  • 数据量需可控,在无限增长业务场景不适用

  • 在微服务场景不利于全局缓存应用

总结

  • 空间最小化

  • 满足精确查询场景

  • 总数据量可控推荐使用

  • 微服务场景不适用

Redis结合本地缓存

微服务场景下,多个微服务使用一个大缓存,流数据业务下,高频读取缓存对Redis压力很大,我们使用本地缓存结合Redis缓存使用,降低Redis压力,同时本地缓存没有连接开销,性能更优

流程图

图片

业务场景

在流处数处理过程中,微服务对多个设备上传的数据进行处理,每个设备有一个code,流数据的频率高,在消息队列发送过程中使用分区发送,我们需要为设备code生成对应的自增号,用自增号对kafka中topic分区数进行取模,这样如果有10000台设备,自增号就是0~9999,在取模后就进行分区发送就可以做到每个分区均匀分布。

这个自增号我们使用redis的自增数生成,生成后放到redis的hash结构进行缓存,每次来一个设备,我们就去这个hash缓存中取,没有取到就使用自增数生成一个,然后放到redis的hash缓存中,这时候每个设备的自增数一经生成是不会再发生改变的,我们就想到使用本地缓存进行优化,避免高频的调用redis去获取,降低redis压力。

下面链接是关于kafka分区消费的文章,大家可以去看看

https://juejin.cn/post/6995746569580445709

代码示例

/*** 此缓存演示如何结合redis自增数 hash 本地缓存使用进行设备自增数的生成、缓存、本地缓存* 本地缓存使用Guava Cache*/
public class DeviceIncCache {/*** 本地缓存*/private Cache<String, Integer> localCache = CacheBuilder.newBuilder().concurrencyLevel(16) // 并发级别.initialCapacity(1000) // 初始容量.maximumSize(10000) // 缓存最大长度.expireAfterAccess(1, TimeUnit.HOURS) // 缓存1小时没被使用就过期.build();@Autowiredprivate RedisTemplate<String, Integer> redisTemplate;/*** redis自增数缓存的key*/private static final String DEVICE_INC_COUNT = "device_inc_count";/*** redis设备编码对应自增数的hash缓存key*/private static final String DEVICE_INC_VALUE = "device_inc_value";/*** 获取设备自增数*/public int getInc(String deviceCode){// 1.从本地缓存获取Integer inc = localCache.get(deviceCode);if(inc != null) {return inc;}// 2.本地缓存未命中,从redis的hash缓存获取inc = (Integer)redisTemplate.opsForHash().get(DEVICE_INC_VALUE, deviceCode);// 3. redis的hash缓存中没有,说明是新设备,先为设备生成一个自增号if(inc == null) {inc = redisTemplate.opsForValue().increment(DEVICE_INC_COUNT).intValue;// 添加到redis hash缓存redisTemplate.opsForHash().put(DEVICE_INC_VALUE, deviceCode, inc);}// 4.添加到本地缓存localCache.put(deviceCode, inc);// 4.返回自增数return inc;}}

优点

  • redis保证数据可持久,本地缓存保证超高的读取性能,微服务共用redis大缓存的场景能有效降低redis压力

  • guava作为本地缓存,提供了丰富的api,过期策略,最大容量,保证服务内存可控,冷数据不会长期占据内存空间

  • 服务重启导致的本地缓存清空不会影响业务进行

  • 微服务及分布式场景使用,分布式情况下每个服务实例只会缓存自己接入的那一部分设备的自增号,本地内存空间最优

  • 在示例业务中,自增数满足了分布区发送的均匀分布需求,也可以满足统计设备接入数目的业务场景,一举两得

缺点

  • 增加编码复杂度,不直接

  • 只适用于缓存内容只增不改的场景

总结

  • 本地缓存空间可控,过期策略优

  • 适用于微服务及分布式场景

  • 缓存内容不能发生改变

  • 性能优

后记

redis提供了丰富的数据类型及api,非常适合业务系统开发,统计计数(increment,decrement),标记位(bitmap),松散数据(hash),先进先出、队列式读取(list);

guava缓存作为本地缓存,能够高效的读取的同时,提供了大量api方便我们控制本地缓存的数据量及冷数据淘汰;我们充分的学习这些特性能够帮助我们在业务开发中更加轻松灵活,在空间与时间上找到一个平衡点。

干货分享最近将个人学习笔记整理成册,使用PDF分享。关注我,回复如下代码,即可获得百度盘地址,无套路领取!
•001:《Java并发与高并发解决方案》学习笔记;•002:《深入JVM内核——原理、诊断与优化》学习笔记;•003:《Java面试宝典》•004:《Docker开源书》•005:《Kubernetes开源书》•006:《DDD速成(领域驱动设计速成)》•007:全部•008:加技术群讨论
加个关注不迷路
喜欢就点个"在看"呗^_^

Redis与本地缓存组合食用,味道更佳!相关推荐

  1. 高并发技巧-redis和本地缓存使用技巧

    在这篇文章中,我主要介绍的是分布式缓存和本地缓存的使用技巧,包括缓存种类介绍,各种的使用场景,以及如何使用,最后再给出实战案例. 众所周知,缓存最主要的目的就是加速访问,缓解数据库压力.最常用的缓存就 ...

  2. 探讨下如何更好的使用缓存 —— 集中式缓存Redis的BitMap存储、管道与事务、以及与本地缓存一起构建多级缓存

    大家好,又见面了. 通过前面的文章,我们一起剖析了Guava Cache.Caffeine.Ehcache等本地缓存框架的原理与使用场景,也一同领略了以Redis为代表的集中式缓存在分布式高并发场景下 ...

  3. springboot:缓存不止redis,学会使用本地缓存ehcache

    0. 引言 随着redis的普及,更多的同学对redis分布式缓存更加熟悉,但在一些实际场景中,其实并不需要用到redis,使用更加简单的本地缓存即可实现我们的缓存需求. 今天,我们一起来看看本地缓存 ...

  4. 分布式缓存redis+本地缓存Caffeine:多级缓存架构在行情系统中的应用

    多级缓存架构在行情系统中的应用 一 为什么要有多级缓存 二 多级缓存架构 三 代码实现 @PreHeat 注解 CacheAspect 定时任务执行器PreheatTask LocalCacheSer ...

  5. Springboot本地缓存和redis缓存

    存储简介:最开始使用的存储结构是文件形式(如:操作系统),但这时就存在一个问题,比如:查一个大的文件的时候,就是需要全量IO(在全部文件堆中找到你需要的文件),受磁盘寻址(毫秒)和带宽的影响会很慢,所 ...

  6. 为什么用redis做缓存而不是mybatis自带的缓存_如何用Java设计一个本地缓存,涨姿势了...

    最近在看Mybatis的源码,刚好看到缓存这一块,Mybatis提供了一级缓存和二级缓存:一级缓存相对来说比较简单,功能比较齐全的是二级缓存,基本上满足了一个缓存该有的功能. 当然如果拿来和专门的缓存 ...

  7. java 项目做多级缓存_【开源项目系列】如何基于 Spring Cache 实现多级缓存(同时整合本地缓存 Ehcache 和分布式缓存 Redis)...

    一.缓存 当系统的并发量上来了,如果我们频繁地去访问数据库,那么会使数据库的压力不断增大,在高峰时甚至可以出现数据库崩溃的现象.所以一般我们会使用缓存来解决这个数据库并发访问问题,用户访问进来,会先从 ...

  8. 本地缓存到分布式缓存( Guava, Caffeine, Memcached, Redis)

    本地缓存:指的是在应用中的缓存组件,是应用和cache是在同一个进程内部,单应用不需要集群支持或者集群情况下各节点无需互相通知的场景下使用本地缓存较合适: 分布式缓存:应用分离的缓存组件或服务,是自身 ...

  9. 从架构上来理解redis缓存和本地缓存的关系

    redis缓存和本地缓存混用是一种非常实用的实践方式. 优点:极大地降低了redis的读写频率,特别是处理特别耗时的业务逻辑(大于1分钟). 缺点:会产生一定的延时,这个延时具体的影响将会根据业务的差 ...

最新文章

  1. 用c语言编写心里测试,求各位大神赐教!我做了一个“心理测试的答题卷”编程,总共有1...
  2. 瞬间教你学会使用java中list的retainAll方法
  3. bzoj 1058: [ZJOI2007]报表统计 (Treap)
  4. Struts2 随笔1
  5. cmake 指定编译器_我们需要懂得CMake文件
  6. Makefile,Shell command,Shell Language 之间的联系
  7. 导线怎么用计算机平差,在计算机上实现导线网的自动条件平差
  8. 删除远程桌面登录的记录(mstsc)
  9. 计算机硬盘应该什么格式化,电脑硬盘格式化方法总结 【图文】
  10. WDS桥接副路由器有线上网方法
  11. Rails项目中jRuby与Scala的交互
  12. 数据仓库系列:初识数仓
  13. 算法介绍 | 泛洪算法(Flood fill Algorithm)
  14. 对于计算机等级考试的建议
  15. 银河麒麟服务器操作系统V10搭建内网YUM源服务器
  16. JavaScript、js文件、Node.js、静态文件
  17. java 字符串处理流程_一文带你了解Java字符串处理(String,StringBuffer,StringBuild)...
  18. IOS开发学习---Fundation框架和UIKit框架
  19. 新的一年,您是否考虑转型呢?
  20. 使用echarts画树图,并设置节点为不同的图片

热门文章

  1. HTB-Nineveh
  2. [高项]资源平衡VS资源平滑
  3. Cms资源论坛网站模板
  4. 曲柄压力机的离合器和制动系统设计
  5. 全国车辆违章查询API文档及demo
  6. 德州扑克-allin主池边池,分池算法
  7. 冰点与沸点—— 我的购物记
  8. UV镜还是保护镜?差异很大啊!(附14款镜片测试结果)
  9. 国内优秀网址导航站总结 (转载)
  10. jsp服装商城购物系统