文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

四种缓存的避坑总结

2024-12-01 14:26

关注

JVM 堆内缓存

JVM 堆内缓存因为可以避免 Memcached、Redis 等集中式缓存网络通信故障问题,目前还在项目中广泛使用。

堆内缓存需要注意 GC 的问题。假如我们的设计是定时的从远程来拉取数据更新本地缓存。一定要注意两点:第一不要全量拉取覆盖,第二不要把一个大对象整体替换为新对象。

先说全量拉取覆盖。全量拉取会有很大的网络开销,会造成网络流量尖刺。有人说没事,我们带宽很足,内网访问,不怕不怕。但是稳定性需要修炼的一项是削峰填谷。让系统在平稳的环境中运行。不然,在拉取大缓存新数据的数据突然来了个突发流量?根据墨菲定律,凡是有几率会发生的事情就一定会发生。编程需谨慎。

再说大对象整体替换的问题,这会造成 GC 问题。伪代码如下:

List<POJO> oldList = initList();

public void refresh() {

List<POJO> newList = dataFromNetworkService.getAll();

oldList = new List();

for(POJO pojo : newList) {

oldList.add(pojo);

}

}

如果从网上拉取的数据和在缓存里存储的数据,对象类型没有发生改变。引起的转换开销还稍微小点。因为比如对象 POJO 存在一个列表里。这个列表虽然很大,但是里面存的都是对象的引用。实际的 POJO 并没有发生变化。上面伪代码虽然新建一个 List 对象,遍历添加新对象比直接 oldList=newList 要傻些。但是遍历过程实际上 POJO  对象没有发生改变。所以这里影响 GC 的只是 oldList 这个对象(不包括从网络上拉取回来数据的过程)。

但是如果代码这样写:

List<POJO2> oldList = initList();

public void refresh() {

List<POJO1> newList = dataFromNetworkService.getAll();

oldList = new List();

for(POJO2 pojo : newList) {

oldList.add(Beanutils.copy(new POJO2(), pojo));

}

}

遍历过程将会将原来的 POJO1 全部新建一遍,这些对象一般情况下全部先进入堆内存的新生代,再经过数次 Young GC 后进入老年代。会造成GC频繁。

我所做过的项目,一般认为一天一到两次 Full GC 为合理值。这样,如果比如预先知道某个时间点有大促,可通过提前触发 GC 等方式避免高峰期爆发 Full GC。Young GC 至少是 5 分钟一次,甚至更久触发认为是正常。这样可以通过控制避过秒杀等场景。

JVM 堆外缓存

堆外缓存的内存回收原理使用的是 Java 的虚引用 。这个设计可以避免 JVM 的 GC 问题,但是处理不好可能会造成更严重的后果:整个机器内存被打满,机器可能会挂掉。 其实挂掉一台在一般企业的生产环境还好,因为一般都会有容灾的冗余机器。 但是更常见的一种情况是机器忙于 swap 内存交换,机器活着但是响应很慢。 属于半死不活。 这个问题我没在线上遇到过,但是我同事之前在超级大厂的时候遇到过。

有的同学说那我严格算好内存,做好监控。这里面要就要依赖人为的因素来做紧急处理。而人是稳定性中最不可靠的。因为问题通常不发生在人清醒、手里事情很少的时候。而是一种雪上加霜的存在。比如大促时,流量上来了,线程数会增多,每个线程都会申请线程栈资源,系统处理 IO,这时候系统会申请更多的 buffers/cached 内存。

Linux 的 buffers/cached

Linux 系统上运行一下 top 命令或者 free 命令,都能够看到 buffers 和 cached 相关的数据。需要注意的是通常我们看到的监控数据空闲内存百分比,并非是下面显示的 free/total,而是 (free+buffers+cached)/total。

buffers 在 Linux 系统中通常被作为与块存储的 IO 缓存使用。所谓块存储可简单理解为将数据直接写到裸磁盘。而 cached 则一般会用于文件系统的 IO 缓存。比如 page cache 这种内存换页功能。

听不明白也没关系,因为事实上它们两个经常配合使用。比如与磁盘交换数据、进行网络通信时都会用。buffers 和 cached 是实实在在被操作系统的系统进程在使用的,但是如果用户进程需要可以很快释放。所以通常会将它算到剩余可用内存里。

但是这个也要注意了。比如在 IO 密集型的系统,如果 buffers/cached 被大幅占用,会降低 IO 速度,进而降低系统吞吐。甚至有可能一个请求几秒才能到达应用程序,造成请求超时。

集中式缓存

Redis 缓存其实也有本机代理,可以缓存一些活跃的数据在本机上,本机可以在取 不 到数据时不需要跨网络通信。但是因为 Redis 本质是 key-value 的结构。如果需要根据通配符取数据全量,如果网络出现故障,可能会影响数据的完整性。

但是 Redis 缓存最让人担心的是不规范的使用方法。比如存一个很大的 value。具体这个对网络和存储造成的问题就不详细说了。可以想象下马桶堵了的情景。

总结

贝尔实验室的面向对象编程专家 Tom Cargill 说:

最初 90% 的开发工作将会用去你最初 90% 的开发时间,剩下的 10% 的开发量将会用去你另外一个 90% 的开发时间。

我理解剩下 10% 占用了 90% 的时间是由于超出了原有知识贮备,需要临时抱佛脚,甚至需要拿着锤子找钉子造成的。所以或者也可以这样做:

每周持续投入 5% 的学习时间,10% 的思考时间,再用 100% 的时间去完成 100% 的开发。

来源:编程一生内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯