四种缓存的避坑总结
背景
分布式、缓存、异步和多线程被称为互联网开发的四大法宝。今天我总结一下项目开发中常接触的四种缓存实际项目中遇到过的问题。
JVM堆内缓存
JVM堆内缓存因为可以避免memcache、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频繁。
我所做过的项目,一般认为一天一到2次fullgc为合理值。这样,如果比如预先知道某个时间点有大促,可通过提前触发GC等方式避免高峰期爆发fullgc。younggc至少是5分钟一次,甚至更久触发认为是正常。这样可以通过控制避过秒杀等场景。
JVM堆外缓存
堆外缓存的内存回收原理使用的是Java的虚引用(参见《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%的开发。
相关文章:
四种缓存的避坑总结
背景 分布式、缓存、异步和多线程被称为互联网开发的四大法宝。今天我总结一下项目开发中常接触的四种缓存实际项目中遇到过的问题。 JVM堆内缓存 JVM堆内缓存因为可以避免memcache、redis等集中式缓存网络通信故障问题,目前还在项目中广泛使用。 堆内缓存需要注…...
flutter开发实战-flutter二维码条形码扫一扫功能实现
flutter开发实战-flutter二维码条形码扫一扫功能实现 flutter开发实战-flutter二维码扫一扫功能实现,要使用到摄像头的原生的功能,使用的是插件:scan 效果图如下 一、扫一扫插件scan # 扫一扫scan: ^1.6.01.1 iOS权限设置 <key>NSCa…...
一篇文章了解Redis分布式锁
Redis分布式锁 什么是分布式锁? redis分布式锁是一种基于redis实现的锁机制,它用于在多并发分布式环境下控制并发访问共享资源。在多个应用程序或是进程访问共享资源时,分布式锁可以确保只有一个进程可以访问该资源,不会发生…...
记录第一次组装电脑遇到的坑
京东装机大师配置清单如下: 主板cpu安装 本次安装拆了两次主板 原因1.主板侧面有个金属板需要从内部安装 2.cpu风扇有个板需要装在主板底下 显卡比较大个要最后装,要不然可能要拆好几次 装系统时候 u盘启动认不出来,他妈的是因为机箱上的usb…...
右键pdf文件没有打印
问题描述 右键点pdf文件,弹出的菜单找不到打印选项。网上找了很多办法,然并卵啊。还是得靠自己慢慢摸索。 原因分析 新安装的win11系统,pdf文件默认可以用windows自带的edge浏览器打开。但是edge浏览器没有能力提供右键打印功能。 解决办法…...
什么是CDN?CDN的原理和作用是什么?
一:什么是CDN CDN全称Content Delivery Network,即内容分发网络。 CDN是Content Delivery Network(内容分发网络)的缩写,是一种利用分布式节点技术,在全球部署服务器,即时地将网站、应用、视频…...
链路传播(Propagate)机制及使用场景
服务间链路追踪传播机制是指在微服务架构中,通过记录和跟踪服务之间的请求和响应信息,来实现对服务间链路的追踪和监控。这种机制可以帮助开发人员快速定位服务间出现的问题,并进行优化和调整。 具体来说,服务间链路追踪传播机制…...
pytorch技巧总结1:学习率调整方法
pytorch技巧总结1:学习率调整方法 前言 这个系列,我会把一些我觉得有用、有趣的关于pytorch的小技巧进行总结,希望可以帮助到有需要的朋友。 免责申明 本人水平有限,若有误写、漏写,请大家温柔的批评指正。 目录…...
谈谈VPN是什么、类型、使用场景、工作原理
作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 前言 本文将讲解VPN是什么、以及它的类型、使用场景、工作原理。 目录 一、VPN是什么? 二、VPN的类型 1、站点对站点VPN 2、…...
windows 下载安装Redis,并配置开机自启动
windows 下载安装Redis,并配置开机自启动 1. 下载 地址:https://github.com/tporadowski/redis/releases Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择,这里我们下载 Redis-x64-xxx.zip压缩包,之后解压 打…...
2. CSS3的新特性
2.1CSS3的现状 ●新增的CSS3特性有兼容性问题, ie9才支持 ●移动端支持优于PC端 ●不断改进中 ●应用相对广泛 ●现阶段主要学习: 新增选择器和盒子模型以及其他特性 CSS3给我们新增了选择器,可以更加便捷,更加自由的选择目标元素: 1.属性选择器 2.结构伪类选择器…...
从零开始训练神经网络
用Keras实现一个简单神经网络 Keras: Keras是由纯python编写的基于theano/tensorflow的深度学习框架。 Keras是一个高层神经网络API,支持快速实验,能够把你的idea迅速转换为结果,如果有如下需 求,可以优先选择Keras&a…...
连接区块链节点的 JavaScript 库 web3.js
文章目录 前言web3.js 介绍web3.js安装web3.js库模块介绍连接区块链节点向区块链网络发送数据查询区块链网络数据 前言 通过前面的文章我们可以知道基于区块链开发一个DApp,而DApp结合了智能合约和用户界面(客户端),那客户端是如…...
js:scroll平滑滚动页面或元素到顶部或底部的方案汇总
目录 1、CSS的scroll-behavior2、Element.scrollTop3、Element.scroll()/Window.scroll()4、Element.scrollBy()/Window.scrollBy()5、Element.scrollTo()/Window.scrollTo()6、Element.scrollIntoView()7、自定义兼容性方案8、参考文章 准备知识: scrollWidth: 是…...
【Docker】Docker的部署含服务和应用、多租环境、Linux内核的详细介绍
前言 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。 📕作者简介:热…...
C国演义 [第五章]
第五章 子集题目理解步骤树形结构递归函数递归结束的条件单层逻辑 代码 子集II题目理解步骤树形结构递归函数递归结束的条件单层逻辑 代码 子集 力扣链接 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。…...
Proxy-Reflect使用详解
1 监听对象的操作 2 Proxy类基本使用 3 Proxy常见捕获器 4 Reflect介绍和作用 5 Reflect的基本使用 6 Reflect的receiver Proxy-监听对象属性的操作(ES5) 通过es5的defineProperty来给对象中的某个参数添加修改和获取时的响应式。 单独设置defineProperty是只能一次设置一…...
【Linux后端服务器开发】Shell外壳——命令行解释器
目录 一、Shell外壳概述 二、描述Shell外壳原理的生动例子 三、C语言模拟实现Shell外壳 一、Shell外壳概述 在狭义上 , 我们称Linux操作系统的内核为 Linux 在广义上 , Linux发行版 Linux内核 外壳程序 就比如市面上现在的redhat, centos, ubuntu等等我们耳熟能详的Linux发…...
【无公网IP】在外Windows远程连接MongoDB数据库
文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 转载自cpolar极点云文章:公网远程…...
mac python3 安装virtualenv
第一步,执行安装virtualenv pip3 install virtualenv 注意:如果出现WARNING: The script virtualenv is installed in ‘/home/local/bin’ which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning,…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
