文档章节

J2Cache 和普通缓存框架有何不同,它解决了什么问题?

红薯
 红薯
发布于 08/21 14:15
字数 1676
阅读 4598
收藏 40

不少人看到 J2Cache 第一眼时,会认为这就是一个普普通通的缓存框架,和例如 Ehcache、Caffeine 、Spring Cache 之类的项目没什么区别,无非是造了一个新的轮子而已。事实上完全不是一回事!

目前缓存的解决方案一般有两种:

  • 内存缓存(如 Ehcache) —— 速度快,进程内可用
  • 集中式缓存(如 Redis)—— 可同时为多节点提供服务

现有的缓存框架已经非常成熟而且优秀,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 要传输的数据极其小,对节点间的数据通信完全不会产生大的影响。

--------

更详细的介绍请参考 https://gitee.com/ld/J2Cache 项目的 Readme ,以及 Readme 里的视频讲解。

© 著作权归作者所有

共有 人打赏支持
红薯

红薯

粉丝 20493
博文 126
码字总数 43860
作品 8
深圳
产品经理
加载中

评论(62)

从今开始
我就问一个问题,在重构微信秒杀模块(20万+并发请求),集群环境下,原来只使用一台redis,redis没撑住。j2cache可以保证各节点数据同步的准确性和实时性吗?
xiaour
xiaour
Redis的Pub和Sub是相对可靠地,目前我们日均二十多万的量没有出现丢失的情况。
rommelzhan
rommelzhan

引用来自“Raphael_goh”的评论

引用来自“rommelzhan”的评论

引用来自“Raphael_goh”的评论

引用来自“rommelzhan”的评论

@红薯 redis官方介绍pub/sub的时候,明确说了是不可靠的,会有数据丢失。你在J2Cache里面是如何应对这个问题的。

我们在一个产品中也准备基于redis的pub/sub来维持分布式缓存能够同步,事实上发现他是不可靠的,而且官方也明确说明了

引用来自“红薯”的评论

这里用到的 pub/sub 本身就不需要要求专业级的消息服务,redis 的 pub/sub 既轻量级又满足 j2cache 的要求。我们已经用了多年了,毫无问题哦

引用来自“rommelzhan”的评论

三个问题
1. j2cache,你用下来毫无问题的标准是什么?理论上如何证明的?
2. 前面回复的连接里面介绍的redis pubsub不可靠,丢消息的case测试过吗?
3. j2cache当缓存不同步的时候,怎么解决一致性的问题的,CAP是如何满足的。

@红薯 ,很想交流探讨一下
redis pubsub本来就不具备可靠性,丢失也是在所难免的。

但问题的前提是,这是一个二级缓存框架,而涉及的缓存主要是针对很少改动的场景。
本来就很少改动,redis也只是在改动数据的时候做通知,压力就更小了,然后redis出故障的概率又低,所以综合考虑是可以忽略不计的(除非你的这个redis还有其他高频用途)

如果你非要纠结可靠性问题的话,即使替换成了MQ也只能保证AP,要保证真正的C只能通过一致性协议(paxos、raft...) 或者 最终一致性解决,但都非常麻烦。

我无意diss j2cache,我们指出他可能潜在的问题并不是出于恶意的诋毁,而是我们可以在讨论之后,弄清楚他什么情况下比较适用。我们都是成年人,我们都知道这个世界上没有万能药,但是我们也知道某些病有特效药。

@红薯 的回答我非常满意,我们了解了,它在什么场景很好用。这也是对用户负责。

曾经我用某中国大型上市公司的c++ event loop网络库,因为他的测试报告看起来不错,并且在文档说经过了大量测试。

在用这个基础网络库做好产品之后,长期使用发现,一个tcp长连接,莫名其妙的就会不再处理read事件。而且底层对ipv4和ipv6的封装简直就是瞎搞。这就是典型的不负责任,我有理由相信在他们的特定环境里面,是工作的很好的,但是在我们这种维持长连接的环境下是没有测试过的。然后笼统的说,非常可靠,测试覆盖率高,这都是耍流氓。

这直接导致我们要把网络通讯的昨天粘合代码全部换掉。假如一开始我们没有多一点心机,没有在他们的网络库上面再做一层适配的话,那么我们就要整个软件重写了。

搞清楚适用场景,并且描述清楚并不是什么坏事,反而会有更多人来用,更有可能有人来解决他的不足
可能我的口吻有点问题,我从没有说你在diss j2cache。如果我说了什么令你生气的话,我道歉。我只是说针对j2cache的场景,确实问题不大,但你要用来做非常敏感的要确保一致性的,那肯定还是不行的。

您误解了,我是怕我之前提出问题的方式太直接了,怕你们会认为我是在找茬,��
Raphael_goh
Raphael_goh

引用来自“rommelzhan”的评论

引用来自“Raphael_goh”的评论

引用来自“rommelzhan”的评论

@红薯 redis官方介绍pub/sub的时候,明确说了是不可靠的,会有数据丢失。你在J2Cache里面是如何应对这个问题的。

我们在一个产品中也准备基于redis的pub/sub来维持分布式缓存能够同步,事实上发现他是不可靠的,而且官方也明确说明了

引用来自“红薯”的评论

这里用到的 pub/sub 本身就不需要要求专业级的消息服务,redis 的 pub/sub 既轻量级又满足 j2cache 的要求。我们已经用了多年了,毫无问题哦

引用来自“rommelzhan”的评论

三个问题
1. j2cache,你用下来毫无问题的标准是什么?理论上如何证明的?
2. 前面回复的连接里面介绍的redis pubsub不可靠,丢消息的case测试过吗?
3. j2cache当缓存不同步的时候,怎么解决一致性的问题的,CAP是如何满足的。

@红薯 ,很想交流探讨一下
redis pubsub本来就不具备可靠性,丢失也是在所难免的。

但问题的前提是,这是一个二级缓存框架,而涉及的缓存主要是针对很少改动的场景。
本来就很少改动,redis也只是在改动数据的时候做通知,压力就更小了,然后redis出故障的概率又低,所以综合考虑是可以忽略不计的(除非你的这个redis还有其他高频用途)

如果你非要纠结可靠性问题的话,即使替换成了MQ也只能保证AP,要保证真正的C只能通过一致性协议(paxos、raft...) 或者 最终一致性解决,但都非常麻烦。

我无意diss j2cache,我们指出他可能潜在的问题并不是出于恶意的诋毁,而是我们可以在讨论之后,弄清楚他什么情况下比较适用。我们都是成年人,我们都知道这个世界上没有万能药,但是我们也知道某些病有特效药。

@红薯 的回答我非常满意,我们了解了,它在什么场景很好用。这也是对用户负责。

曾经我用某中国大型上市公司的c++ event loop网络库,因为他的测试报告看起来不错,并且在文档说经过了大量测试。

在用这个基础网络库做好产品之后,长期使用发现,一个tcp长连接,莫名其妙的就会不再处理read事件。而且底层对ipv4和ipv6的封装简直就是瞎搞。这就是典型的不负责任,我有理由相信在他们的特定环境里面,是工作的很好的,但是在我们这种维持长连接的环境下是没有测试过的。然后笼统的说,非常可靠,测试覆盖率高,这都是耍流氓。

这直接导致我们要把网络通讯的昨天粘合代码全部换掉。假如一开始我们没有多一点心机,没有在他们的网络库上面再做一层适配的话,那么我们就要整个软件重写了。

搞清楚适用场景,并且描述清楚并不是什么坏事,反而会有更多人来用,更有可能有人来解决他的不足
可能我的口吻有点问题,我从没有说你在diss j2cache。如果我说了什么令你生气的话,我道歉。我只是说针对j2cache的场景,确实问题不大,但你要用来做非常敏感的要确保一致性的,那肯定还是不行的。
红薯
红薯
@rommelzhan 已经增加了使用 RabbitMQ 作为消息通知的方法,详情请看 readme 增加的说明部分 :) 非常感谢你提的问题
rommelzhan
rommelzhan

引用来自“Raphael_goh”的评论

引用来自“rommelzhan”的评论

@红薯 redis官方介绍pub/sub的时候,明确说了是不可靠的,会有数据丢失。你在J2Cache里面是如何应对这个问题的。

我们在一个产品中也准备基于redis的pub/sub来维持分布式缓存能够同步,事实上发现他是不可靠的,而且官方也明确说明了

引用来自“红薯”的评论

这里用到的 pub/sub 本身就不需要要求专业级的消息服务,redis 的 pub/sub 既轻量级又满足 j2cache 的要求。我们已经用了多年了,毫无问题哦

引用来自“rommelzhan”的评论

三个问题
1. j2cache,你用下来毫无问题的标准是什么?理论上如何证明的?
2. 前面回复的连接里面介绍的redis pubsub不可靠,丢消息的case测试过吗?
3. j2cache当缓存不同步的时候,怎么解决一致性的问题的,CAP是如何满足的。

@红薯 ,很想交流探讨一下
redis pubsub本来就不具备可靠性,丢失也是在所难免的。

但问题的前提是,这是一个二级缓存框架,而涉及的缓存主要是针对很少改动的场景。
本来就很少改动,redis也只是在改动数据的时候做通知,压力就更小了,然后redis出故障的概率又低,所以综合考虑是可以忽略不计的(除非你的这个redis还有其他高频用途)

如果你非要纠结可靠性问题的话,即使替换成了MQ也只能保证AP,要保证真正的C只能通过一致性协议(paxos、raft...) 或者 最终一致性解决,但都非常麻烦。

我无意diss j2cache,我们指出他可能潜在的问题并不是出于恶意的诋毁,而是我们可以在讨论之后,弄清楚他什么情况下比较适用。我们都是成年人,我们都知道这个世界上没有万能药,但是我们也知道某些病有特效药。

@红薯 的回答我非常满意,我们了解了,它在什么场景很好用。这也是对用户负责。

曾经我用某中国大型上市公司的c++ event loop网络库,因为他的测试报告看起来不错,并且在文档说经过了大量测试。

在用这个基础网络库做好产品之后,长期使用发现,一个tcp长连接,莫名其妙的就会不再处理read事件。而且底层对ipv4和ipv6的封装简直就是瞎搞。这就是典型的不负责任,我有理由相信在他们的特定环境里面,是工作的很好的,但是在我们这种维持长连接的环境下是没有测试过的。然后笼统的说,非常可靠,测试覆盖率高,这都是耍流氓。

这直接导致我们要把网络通讯的昨天粘合代码全部换掉。假如一开始我们没有多一点心机,没有在他们的网络库上面再做一层适配的话,那么我们就要整个软件重写了。

搞清楚适用场景,并且描述清楚并不是什么坏事,反而会有更多人来用,更有可能有人来解决他的不足
Raphael_goh
Raphael_goh

引用来自“rommelzhan”的评论

@红薯 redis官方介绍pub/sub的时候,明确说了是不可靠的,会有数据丢失。你在J2Cache里面是如何应对这个问题的。

我们在一个产品中也准备基于redis的pub/sub来维持分布式缓存能够同步,事实上发现他是不可靠的,而且官方也明确说明了

引用来自“红薯”的评论

这里用到的 pub/sub 本身就不需要要求专业级的消息服务,redis 的 pub/sub 既轻量级又满足 j2cache 的要求。我们已经用了多年了,毫无问题哦

引用来自“rommelzhan”的评论

三个问题
1. j2cache,你用下来毫无问题的标准是什么?理论上如何证明的?
2. 前面回复的连接里面介绍的redis pubsub不可靠,丢消息的case测试过吗?
3. j2cache当缓存不同步的时候,怎么解决一致性的问题的,CAP是如何满足的。

@红薯 ,很想交流探讨一下
redis pubsub本来就不具备可靠性,丢失也是在所难免的。

但问题的前提是,这是一个二级缓存框架,而涉及的缓存主要是针对很少改动的场景。
本来就很少改动,redis也只是在改动数据的时候做通知,压力就更小了,然后redis出故障的概率又低,所以综合考虑是可以忽略不计的(除非你的这个redis还有其他高频用途)

如果你非要纠结可靠性问题的话,即使替换成了MQ也只能保证AP,要保证真正的C只能通过一致性协议(paxos、raft...) 或者 最终一致性解决,但都非常麻烦。
redraiment
redraiment

引用来自“redraiment”的评论

还有一个疑问:看文章中的图,清理缓存的步骤是
顺便吐个槽,评论想换个行结果就发送出来了,还不允许删除...这个操作好麻烦。
redraiment
redraiment
还有一个疑问:看文章中的图,清理缓存的步骤是 (1)清除Ehcache (2)清除Redis (3)广播。按照这个顺序,如果执行完第(1)步,正好另一个线程又来访问,于是在执行第(2)步之前又从Redis里读取了一次。这样就会导致,进程里的Ehcache缓存着旧的数据,而Redis里被清空了。
redraiment
redraiment
还有一个疑问:看文章中的图,清理缓存的步骤是
J2Cache 2.5.5 发布,完善对 Sentinel 的 pub/sub 支持

J2Cache 2.5.5 发布了,该版本主要改进内容包括: 完善对 Redis Sentinel 的 pub/sub 支持 修复了 json 序列化不支持 java.sql.Date 和 java.sql.Timestamp 的问题 修复 Spring Boot 模块的序...

红薯
09/06
0
0
J2Cache 2.7.0 发布了,支持 Lettuce 替代 Jedis

J2Cache 2.7.0 在周末悄没声息的发布了!!! 该版本支持使用 Lettuce 替代 Jedis 连接 Redis ,目前二者并存,以后的版本可能会考虑直接替换掉 Jedis 。我之前不喜欢 Lettuce 是因为它依赖了...

红薯
09/15
0
0
J2Cache 新增 Mybatis 支持模块,代码少到没 Bug

花了点时间撸了个 MyBatis 的 J2Cache 支持模块,含注释共八十多行代码 (J2CacheAdapter.java),再有 Bug 我就真的要退役了。 使用方法很简单,请看 https://gitee.com/ld/J2Cache/tree/mast...

红薯
05/15
0
30
J2Cache 2.3.18 发布,这一次是 Spring Boot 的锅

嗯,我又发布新版本了,我不知道该版本解决的问题算是 Bug 还是一个 Feature ! 某些用户是在 Spring Boot 中使用 J2Cache 框架,当启用 devtool 的时候会导致从缓存读取数据的时候出现 Clas...

红薯
05/22
0
0
飞特商城后台管理系统引入开源中国二级缓存 J2Cache

2018已过半,向着目标与飞特一起加油 缓存是后台系统中必不可少的组件,灵活的缓存配置,可以使我们开发,运维变的更简单。这次我们整合了J2Cache ,它是 OSChina 目前正在使用的两级缓存框架...

18356087258
06/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Windows 下双 Python 开发环境配置

Windows 下双 Python 开发环境配置作者:老农民(刘启华)QQ: 46715422Email: 46715422@qq.com微信: 46715422 本人曾经在 Windows 下被两个版本环境折腾够呛,现在总结两个 Python...

新疆老农民
昨天
1
0
CentOS7全局安装composer

1. 下载composer-setup.php到当前目录 php -r "copy('https://install.phpcomposer.com/installer', 'composer-setup.php');" 2. 安装 php composer-setup.php 3. 将composer设置成全局 mv c......

月夜中徘徊
昨天
1
0
20180920上课截图

小丑鱼00
昨天
1
0
基于TCP的远程服务调用

前言 上篇,分析了基于HTTP方式的RPC调用。本篇将在上篇的基础上,分析基于TCP方式的RPC调用。代码的整体思路是一致的,可以看作是在上篇功能上的扩展——即通信的方式。 代码:https://git...

MarvelCode
昨天
2
0
67:shell脚本介绍 | shell脚本结构 | 执行data命令用法 | shell脚本中变量

1、shell脚本介绍: shell是一种脚本语言和传统的开发语言相比,会比较简单: shell有自己语法,可以支持逻辑判断、循环等语法: 可以自定义函数,目的是减少重复的代码: shell是系统命令的集合...

芬野de博客
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部