说明

前言

J2Cache的一二级缓存支持自定义,一级缓存支持Caffeine、Ehcache2 和 Ehcache3,二级缓存支持redis、memcached
消息通知支持JGroups、Redis、RabbitMQ、RocketMQ
目前提供Hibernate、Mybatis、Session、Spring Cache、Spring Boot适配

单机版可灵活配置设置是否采用二级缓存而减少环境安装的配置,如单机版可能使用Caffeine即可,而不用Redis集中式缓存。

微服务Redis也是不二的选择,J2Cache 可以降低你至少 95% 以上的 Redis 读操作。因为 J2Cache 在进程内增加了一个一级的内存缓存,这并不会增加太多的内存消耗,因为你可以设置内存中缓存数据的数量。

微服务使用:https://my.oschina.net/javayou/blog/1827480

源码地址:https://gitee.com/ld/J2Cache

Spring boot版:https://gitee.com/ld/J2Cache/tree/master/modules/spring-boot2-starter

一、为什么使用J2Cache缓存框架?

解决如下问题:

  1. 使用内存缓存时,一旦应用重启后,由于缓存数据丢失,缓存雪崩,给数据库造成巨大压力,导致应用堵塞
  2. 使用内存缓存时,多个应用节点无法共享缓存数据
  3. 使用集中式缓存,由于大量的数据通过缓存获取,导致缓存服务的数据吞吐量太大,带宽跑满。现象就是 Redis 服务负载不高,但是由于机器网卡带宽跑满,导致数据读取非常慢

在遭遇问题1、2 时,很多人自然而然会想到使用 Redis 来缓存数据,因此就难以避免的导致了问题3的发生。

当发生问题 3 时,又有很多人想到 Redis 的集群,通过集群来降低缓存服务的压力,特别是带宽压力。

但其实,这个时候的 Redis 上的数据量并不一定大,仅仅是数据的吞吐量大而已。

咱们假设这样一个场景

有这么一个网站,某个页面每天的访问量是 1000万,每个页面从缓存读取的数据是 50K。缓存数据存放在一个 Redis 服务,机器使用千兆网卡。那么这个 Redis 一天要承受 500G 的数据流,相当于平均每秒钟是 5.78M 的数据。而网站一般都会有高峰期和低峰期,两个时间流量的差异可能是百倍以上。我们假设高峰期每秒要承受的流量比平均值高 50 倍,也就是说高峰期 Redis 服务每秒要传输超过 250 兆的数据。请注意这个 250 兆的单位是 byte,而千兆网卡的单位是“bit” ,你懂了吗? 这已经远远超过 Redis 服务的网卡带宽。

所以如果你能发现这样的问题,一般你会这么做:

  1. 升级到万兆网卡 —— 这个有多麻烦,相信很多人知道,特别是一些云主机根本没有万兆网卡给你使用(有些运维工程师会给这样的建议)
  2. 多个 Redis 搭建集群,将流量分摊多多台机器上

如果你采用第2种方法来解决上述的场景中碰到的问题,那么你最好准备 5 个 Redis 服务来支撑。在缓存服务这块成本直接攀升了 5 倍。你有钱当然没任何问题,但是结构就变得非常复杂了,而且可能你缓存的数据量其实不大,1000 万高频次的缓存读写 Redis 也能轻松应付,可是因为带宽的问题,你不得不付出 5 倍的成本。

那么 J2Cache 的用武之处就在这里。

如果我们不用每次页面访问的时候都去 Redis 读取数据,那么 Redis 上的数据流量至少降低 1000 倍甚至更多,以至于一台 Redis 可以轻松应付。

J2Cache 其实不是一个缓存框架,它是一个缓存框架的桥梁。它利用现有优秀的内存缓存框架作为一级缓存,而把 Redis 作为二级缓存。所有数据的读取先从一级缓存中读取,不存在时再从二级缓存读取,这样来确保对二级缓存 Redis 的访问次数降到最低。

有人会质疑说,那岂不是应用节点的内存占用要飙升?我的答案是 —— 现在服务器的内存都是几十 G 打底,多则百 G 数百 G,这点点的内存消耗完全不在话下。其次一级缓存框架可以通过配置来控制在内存中存储的数据量,所以不用担心内存溢出的问题。

剩下的另外一个问题就是,当缓存数据更新的时候,怎么确保每个节点内存中的数据是一致的。而这一点算你问到点子上了,这恰恰是 J2Cache 的核心所在。

J2Cache 目前提供两种节点间数据同步的方案 —— Redis Pub/Sub 和 JGroups 。当某个节点的缓存数据需要更新时,J2Cache 会通过 Redis 的消息订阅机制或者是 JGroups 的组播来通知集群内其他节点。当其他节点收到缓存数据更新的通知时,它会清掉自己内存里的数据,然后重新从 Redis 中读取最新数据。

这就完成了 J2Cache 缓存数据读写的闭环。

二、为什么不用 Ehcache 的集群方案?

对 Ehcache 比较熟悉的人还会问的就是这个问题,Ehcache 本身是提供集群模式的,可以在多个节点同步缓存数据。但是 Ehcache 的做法是将整个缓存数据在节点间进行传输。如咱们前面的说的,一个页面需要读取 50K 的缓存数据,当这 50K 的缓存数据有更新时,那么需要在几个节点间传递整个 50K 的数据。这也会造成应用节点间大量的数据传输,这个情况完全不可控。

补充:当然这个单个数据传输量本身并不比使用 J2Cache 多,但是 ehcache 利用 jgroups 来同步数据的做法,在实际测试过程中发现可靠性还是略低,而且 jgroups 的同步数据在云主机上无法使用。

而 J2Cache 传输的仅仅是缓存的 key 而已,因此相比 Ehcache 的集群模式,J2Cache 要传输的数据极其小,对节点间的数据通信完全不会产生大的影响。

三、J2Cache两级缓存结构

L1: 进程内缓存(ehcache\caffeine)
L2:集中式缓存(Redis\Memcached)

数据读取:

  1. 读取顺序 -> L1 -> L2 -> DB

  2. 数据更新

    1 从数据库中读取最新数据,依次更新 L1 -> L2 ,发送广播清除某个缓存信息
    2 接收到广播(手工清除缓存 & 一级缓存自动失效),从 L1 中清除指定的缓存信息

1.配置

###基础配置

键名 缺省值 说明
j2cache.l1-cache caffeine 可选缓存ehcache;ehcache3;caffeine
j2cache.l1-config-location config/caffeine.properties 一级缓存配置文件路径
j2cache.l2-cache-open true 二级缓存开关
j2cache.redis.hosts 127.0.0.1:6379 redis链接地址
j2cache.redis.password redis密码
j2cache.redis.database 0 database

###YML

  #当j2cache二级缓存关闭 redis配置读这里redis:host: 172.16.10.106port: 6379password: 1234database: 8
j2cache:#一级缓存默认ehcache ->可选缓存ehcache;ehcache3;caffeinel1-cache: caffeinel1-config-location: cache/caffeine.properties#二级缓存开关l2-cache-open: true#j2cache redis优先于spring redis配置redis:hosts: 172.16.10.106:6379password: 1234database: 7

Q:已经有一个J2cacheUtils为什么还要写一个RedisUtils ?

A:J2cache二级缓存虽然使用Redis,但是我们发现它可以说是没有TTL的概念,也就是说,缓存过期时间我们都在一级缓存配置中编写(caffeine.properties、ehcache.xml)综合上述说明表示,那么我们项目中有些功能需要比较灵活一点的使用缓存过期怎么办?例如在线配置登录异常锁定时间,用户验证码过期时间等等,这个时候我们就可以使用RedisUtils就非常方便了

tips:

spring boot cache默认使用的是j2cache缓存,如果我们没有开启j2cache二级缓存而又需要用RedisUtils则需要如上YML配置spring redis;如果开启了j2cache二级缓存则spring redis配置失效

结论:j2cache redis > spring redis

2.使用

常用注解

@Cacheable;@CachePut;@CacheEvict

示例

字典缓存

一级缓存

caffeine.properties

#########################################
# Caffeine configuration
# [name] = size, xxxx[s|m|h|d]
#########################################dictCache=10000, 1d

业务层

所有的更新操作使用spring boot的缓存注解

@Service
public class DictDataServiceImpl extends BaseServiceImpl<DictDataMapper, DictData> implements DictDataService {public static final String DICT_CACHE = "dictCache";@Override@CacheEvict(value = DICT_CACHE, key = "#entity.dictcode")@Transactional(rollbackFor = Exception.class)public boolean save(DictData entity) {return super.save(entity);}
}

缓存使用强一致性

Q:Service层我们继承了Mybatis Plus的基类,那么Mybatis Plus的方法只和数据库打交道,我们如何保证多人开发时,程序员调用某个更新方法而出现脏数据?

A:最笨最实用的方法,整理出来了Mybatis Plus所有的CRUD方法,我们所需要做的就是重写它,添加缓存的处理,这样就能保证所有方法同步缓存

save、saveBatch、saveOrUpdate、saveOrUpdateBatch、removeById、removeByMap、remove、removeByIds、updateById、update、updateBatchById、deleteLogic

例子:

@Override
@CacheEvict(value = DICT_CACHE, key = "#entity.dictcode")
@Transactional(rollbackFor = Exception.class)
public boolean saveOrUpdate(DictData entity) {return super.saveOrUpdate(entity);
}

最简单的方法是,每次更新清除该缓存空间所有内容,不需要考虑key(数据量大慎用)

@Override
@CacheEvict(value = DICT_CACHE, allEntries = true)
@Transactional(rollbackFor = Exception.class)
public boolean updateBatchById(Collection<DictData> entityList, int batchSize) {return super.updateBatchById(entityList, batchSize);
}
    @Override@CacheEvict(value = DICT_CACHE, allEntries = true)@Transactional(rollbackFor = Exception.class)public boolean updateBatchById(Collection<DictData> entityList, int batchSize) {return super.updateBatchById(entityList, batchSize);}

Tips:

J2cacheUtils所有方法和spring注解操作相同

J2Cache缓存的使用相关推荐

  1. SpringBoot整合(四)整合Ehcache、Redis、Memcached、jetcache、j2cache缓存

    ​ 企业级应用主要作用是信息处理,当需要读取数据时,由于受限于数据库的访问效率,导致整体系统性能偏低. ​ 为了改善上述现象,开发者通常会在应用程序与数据库之间建立一种临时的数据存储机制,该区域中的数 ...

  2. SpringBoot整合j2cache缓存

    jetcache可以在限定范围内构建多级缓存,但是灵活性不足,不能随意搭配缓存,本节介绍一种可以随意搭配缓存解决方案的缓存整合框架,j2cache.下面就来讲解如何使用这种缓存框架,以Ehcache与 ...

  3. 【Java笔记+踩坑】SpringBoot基础3——开发。热部署+配置高级+整合NoSQL/缓存/任务/邮件/监控

      导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 ...

  4. SpringBoot整合第三方技术学习笔记(自用)

    SpringBoot整合第三方技术学习笔记 搬运黑马视频配套笔记 KF-4.数据层解决方案 KF-4-1.SQL 回忆一下之前做SSMP整合的时候数据层解决方案涉及到了哪些技术?MySQL数据库与My ...

  5. springboot 进阶

    KF-1.热部署 ​ 什么是热部署?简单说就是你程序改了,现在要重新启动服务器,嫌麻烦?不用重启,服务器会自己悄悄的把更新后的程序给重新加载一遍,这就是热部署. ​ 热部署的功能是如何实现的呢?这就要 ...

  6. 黑马SpringBoot --开发篇

    目录 9.热部署 9.1手动启动热部署 9.2自动启动热部署 9.3热部署范围配置 9.4关闭热部署 10.配置高级 10.1@ConfigurationProperties✳ 10.2@Enable ...

  7. SpringBoot课程笔记

    黑马程序员SpringBoot2课程笔记 一.基础篇 略 二.运维实用篇 1.SpringBoot运行与部署 略 2. SpringBoot配置 2.1 临时属性配置 可以在启动Boot程序时添加临时 ...

  8. easy-captcha

    easy-captcha是生成图形验证码的Java类库,支持gif.中文.算术等类型,可用于Java Web.JavaSE等项目.参考地址:https://gitee.com/whvse/EasyCa ...

  9. springboot使用j2cache框架和aspectj自定义缓存

    文章目录 依赖和工具介绍 项目代码 spring上下文工具类: 自定义缓存注解 缓存生成键工具类 自定义缓存拦截器 缓存处理器 缓存结果和缓存信息实体封装 开启声明式注解 controller层使用缓 ...

  10. j2cache两级缓存框架

    j2cache介绍 j2cache是OSChina目前正在使用的两级缓存框架. j2cache的两级缓存结构: L1: 进程内缓存 caffeine/ehcache L2: 集中式缓存 Redis/M ...

最新文章

  1. java iso8583 socket 服务_JAVA客户端amp;服务器的socket通信
  2. 积少成多 Flash(ActionScript 3.0 Flex 3.0) 系列文章索引
  3. Java 转型问题(向上转型和向下转型)
  4. django请求与响应(HttpRequest对象和HttpResponse对象)
  5. python基础入门(8)之集合
  6. 同步、异步的使用场景及好处
  7. bzoj千题计划152:bzoj3405: [Usaco2009 Open]Grazing2 移动牛棚
  8. python turtle画小狗_python-turtle-画雪花
  9. 无线接入中的移动技术
  10. 如何让Low Poly好看
  11. win10插上耳机还外放解决解决方法
  12. 层次分析法(AHP)模型的应用案例
  13. wps底板颜色怎么去掉_怎么去除WPS表格的背景颜色
  14. error CS0227: Unsafe code may only appear if compiling
  15. 重定向和请求转发的区别
  16. 记一次监控录像断续摄像头时而在线问题
  17. 利用autossh反向代理实现内网穿透
  18. StarlingX 前世今生 -- (汇总了网上的一些资料)
  19. python两列时间间隔计算器_python时间差计算器时分秒_python 实现日期计算器
  20. 苹果三代耳机_华强北airpods2 华强北三代耳机 airpodspro可调通透 主动降噪 定位改名 苹果airpodspro...

热门文章

  1. 基于R语言的DynNom包绘制动态列线图
  2. 素数筛普通筛法全解(C/C++)
  3. 物联网行业系列深度报告 附下载
  4. jq-ui-multiselect插件的使用
  5. kali linux中文版安装
  6. 纯CSS的导航下拉菜单
  7. unity 2d文字跟随主角移动_用Unity制作GalGame/视觉小说游戏的模型素材与插件推荐...
  8. 摄影测量学习总结(较全面易懂)
  9. 【STM32F407的DSP教程】第13章 DSP快速计算函数-三角函数和平方根
  10. Python获取FW150R无线路由器的客户端列表