当前位置: 首页 > news >正文

高并发系统设计之缓存

本文已收录至Github,推荐阅读 👉 Java随想录

这篇文章来讲讲缓存。缓存是优化网站性能的第一手段,目的是让访问速度更快。

说起缓存,第一反应可能想到的就是Redis。目前比较好的方案是使用多级缓存,如CPU→Ll/L2/L3→内存→磁盘就是一个典型的例子,CPU需要数据时先从L1读取,如果没有找到,则查找L2/L3读取,如果没有,则到内存中查找,如果还没有,会到磁盘中查找。

文章目录

    • 堆缓存
    • Nginx代理缓存
    • 多级缓存
    • 热点Key自动探测

堆缓存

使用Java堆内存来存储缓存对象。使用堆缓存的好处是没有序列化/反序列化,是最快的缓存。缺点也很明显,当缓存的数据量很大时,GC(垃圾回收)暂停时间会变长,存储容量受限于堆空间大小。一般通过软引用/弱引用来存储缓存对象,即当堆内存不足时,可以强制回收这部分内存释放堆内存空间。一般使用堆缓存存储较热的数据。可以使用Caffeine Cache实现。

集成Caffeine Cache详情见我另外一片文章:本地缓存无冕之王Caffeine Cache

Nginx代理缓存

Nginx 的Proxy Cache可以实现代理缓存,特别需要说明的是,Proxy Cache机制依赖于Proxy Buffer机制,只有在Proxy Buffer机制开启的情况下Proxy Cache的配置才发挥作用,Proxy Buffer默认是开启的,缓存内容将存放在tmpfs(内存文件系统)以提升性能。

Proxy Buffer相关参数:

proxy_buffering  on;
该参数设置是否开启proxy的buffer功能,参数的值为on或者off,默认是on。proxy_buffer_size  4k;
该参数用来设置一个特殊的buffer大小的。
从被代理服务器上获取到的第一部分响应数据内容到代理服务器上,通常是header,就存到了这个buffer中。 
如果该参数设置太小,会出现502错误码,这是因为这部分buffer不够存储header信息。建议设置为4k。proxy_buffers  8  4k;
这个参数设置存储被代理服务器上的数据所占用的buffer的个数和每个buffer的大小。
所有buffer的大小为这两个数字的乘积。proxy_busy_buffer_size 16k;
在所有的buffer里,我们需要规定一部分buffer把自己存的数据传给服务器,这部分buffer就叫做busy_buffer。
proxy_busy_buffer_size参数用来设置处于busy状态的buffer有多大。proxy_temp_path
语法:proxy_temp_path  path [level1 level2 level3]
定义proxy的临时文件存在目录以及目录的层级。

proxy_buffering 与 proxy_cache的区别:

缓冲(buffer)

  • Nginx 将上游服务器的响应报文保存几秒钟,等整个接收之后,再发送给客户端。
  • 可以尽早与上游服务器断开连接,减少其负载。但是会增加客户端等待响应的时间。
  • 如果不启用缓冲,则 Nginx 收到上游服务器的一部分响应就会立即发送给客户端,通信延迟低。

缓存(cache)

  • Nginx 将上游服务器的响应报文保存几分钟,当客户端再次请求同一个响应报文时就直接回复,不必请求上游服务器。
  • 可以避免重复向上游服务器请求一些固定不变的响应报文,减少上游服务器的负载,减少客户端等待响应的时间。

Proxy Cache 相关的参数配置:

  • proxy_cache_path:Nginx 使用该参数指定缓存位置,有两个必填参数, 第一个参数为缓存目录。 第二个参数keys_zone指定缓存名称和占用内存空间的大小。
  • proxy_cache:该参数为之前指定的缓存名称。
  • proxy_cache_key:该指令用来设置web缓存的Key值。
  • proxy_cache_min_uses:指定请求至少被发送了多少次以上时才缓存,可以防止低频请求被缓存。
  • proxy_cache_methods:指定哪些方法的请求被缓存。
  • proxy_cache_valid:该指令用于对于不同返回状态码的URL设置不同的缓存时间。
  • proxy_cache_bypass:指定Nginx使用缓存的条件。

如下示例:

http {proxy_cache_path /data/nginx/cache keys_zone=one:10m max_size=10g;proxy_cache_methods GET HEAD POST PUT;proxy_cache_min_uses 1;proxy_cache_valid 200 302 10m;proxy_cache_key "$host:$server_port$uri$is_args$args";upstream www.baidu.com {server 127.0.0.1:8880;server 127.0.0.1:8881;server 127.0.0.1:8882;}server {listen 80 ;proxy_cache one ;server_name www.baidu.com;location / {proxy_pass http://www.baidu.com;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment ;}}}

多级缓存

Nginx缓存→分布式Redis缓存(可以使用Lua脚本直接在Nginx里读取Redis)→堆内存

  1. 接入 Nginx将请求负载均衡到应用Nginx,此处常用的负载均衡算法是轮询或者一致性哈希。轮询可以使服务器的请求更加均衡,而一致性哈希可以提升应用Nginx的缓存命中率。

  2. 应用Nginx读取本地缓存(本地缓存可以使用Lua Shared Dict,Nginx Proxy Cache(磁盘/内存)、Local Redis实现)。如果本地缓存命中,则直接返回,使用应用Nginx本地缓存可以提升整体的吞吐量,降低后端压力,尤其应对热点问题非常有效。

  3. 如果Nginx本地缓存没命中,则会读取相应的分布式缓存(如 Redis缓存,还可以考虑使用主从架构来提升性能和吞吐量),如果分布式缓存命中,则直接返回相应数据(并回写到Nginx本地缓存)。

  4. 如果分布式缓存也没有命中,则会回源到Tomcat集群,在回源到Tomcat 集群时,也可以使用轮询和一致性哈希作为负载均衡算法。

  5. 在 Tomcat应用中,首先读取本地堆缓存。如果有,则直接返回(并会写到主Redis集群)。

  6. 作为可选部分,如果步骤4没有命中,则可以再尝试一次读主Redis集群操作,目的是防止当从集群有问题时的流量冲击。

  7. 如果所有缓存都没有命中,则只能查询DB或相关服务获取相关数据并返回。

  8. 步骤7返回的数据异步写到主Redis集群。

整体分了三部分缓存:应用Nginx本地缓存、分布式缓存、Tomcat堆缓存。每一层缓存都用来解决相关问题,如应用Nginx本地缓存用来解决热点缓存问题,分布式缓存用来减少访问回源率,Tomcat堆缓存用于防止相关缓存失效/崩溃之后的冲击。

热点Key自动探测

热点数据其实可以分为:静态热点数据 和 动态热点数据

所谓“静态热点数据”,就是能够提前预测的热点数据。例如,我们可以通过卖家报名的方式提前筛选出来,通过报名系统对这些热点商品进行打标。另外,我们还可以通过大数据分析来提前发现热点商品,比如我们分析历史成交记录、用户的购物车记录,来发现哪些商品可能更热门、更好卖,这些都是可以提前分析出来的热点,分析出来之后,我们可以提前放入缓存中保护起来,这在技术上是可以实现的。

所谓“动态热点数据”,就是不能被提前预测到的,系统在运行过程中临时产生的热点。例如,卖家在抖音上做了广告,然后商品一下就火了,导致它在短时间内被大量购买。

所以如何动态预测热点数据就成了我们缓存系统的关键

这里我给出一个动态热点发现系统的具体实现。

  1. 构建一个异步的系统,它可以收集交易链路上各个环节中的中间件产品的热点Key,如Nginx、缓存、RPC服务框架等这些中间件(一些中间件产品本身已经有热点统计模块)。

  2. 建立一个热点上报和可以按照需求订阅的热点服务的下发规范,主要目的是通过交易链路上各个系统(包括详情、购物车、交易、优惠、库存、物流等)访问的时间差把上游已经发现的热点透传给下游系统,提前做好保护。比如,对于大促高峰期,详情系统是最早知道的,在统一接入层上 Nginx模块统计的热点URL。

  3. 将上游系统收集的热点数据发送到热点服务台,然后下游系统(如交易系统)就会知道哪些商品会被频繁调用,然后做热点保护,对于热点的统计可以很简单的对访问的商品进行访问计数,然后排序还有就是用通常的队列的淘汰算法如lru等都可以实现。

实现思路步骤如下:
1.接入Nginx将请求转发给应用Nginx。
2.应用 Nginx首先读取本地缓存。如果命中,则直接返回,不命中会读取分布式缓存、回源到Tomcat进行处理。
3.应用Nginx 会将请求上报给实时热点发现系统,如使用UDP直接上报请求,或者将请求写到本地kafka,或者使用flume订阅本地 Nginx日志。上报给实时热点发现系统后,它将进行热点统计(可以考虑storm实时计算)。
4.根据设置的阈值将热点数据推送到应用Nginx本地缓存。

我们主要是依赖前面的导购页面(包括首页、搜索页面、商品详情、购物车等)提前识别哪些商品的访问量高,通过这些系统中的中间件来收集热点数据,并记录到日志中。

我们通过部署在每台机器上的Agent把日志汇总到聚合和分析集群中,然后把符合一定规则的热点数据,通过订阅分发系统再推送到相应的系统中。你可以是把热点数据填充到Cache中,或者直接推送到应用服务器的内存中,还可以对这些数据进行拦截,总之下游系统可以订阅这些数据,然后根据自己的需求决定如何处理这些数据。

热点发现要做到接近实时(3s内完成热点数据的发现),因为只有做到接近实时,动态发现才有意义,才能实时地对下游系统提供保护。如果10s内才发送热点就没意义了,因为10s内用户可以进行的操作太多了。时间越长,不可控元素越多,热点缓存命中率越低。

京东在网上开源了热点key探测技术的具体实现:https://gitee.com/jd-platform-opensource/hotkey?_from=gitee_search


本篇文章就到这里,感谢阅读,如果本篇博客有任何错误和建议,欢迎给我留言指正。

相关文章:

高并发系统设计之缓存

本文已收录至Github,推荐阅读 👉 Java随想录 这篇文章来讲讲缓存。缓存是优化网站性能的第一手段,目的是让访问速度更快。 说起缓存,第一反应可能想到的就是Redis。目前比较好的方案是使用多级缓存,如CPU→Ll/L2/L3→…...

【N32WB03x SDK使用指南】

【N32WB03x SDK使用指南】1. 简介1.1 产品简介1.2 主要资源1.3 典型应用2. SDK/开发固件文件目录结构2.1 doc2.2 firmware2.3 middleware2.4 utilities2.5 projects Projects3. 项目配置与烧录3.1 编译环境安装3.2 固件支持包安装3.3 编译环境配置3.4 编译与下载3.5 BLE工程目录…...

pytest测试框架——pytest.ini用法

这里写目录标题一、pytest用法总结二、pytest.ini是什么三、改变运行规则pytest.inicheck_demo.py执行测试用例四、添加默认参数五、指定执行目录六、日志配置七、pytest插件分类八、pytest常用插件九、改变测试用例的执行顺序十、pytest并行与分布式执行十一、pytest内置插件h…...

KAFKA安装与配置(带Zookeeper)2023版

KAFKA安装与配置(带Zookeeper) 一、环境准备: Ubuntu 64位 22.04,三台 二、安装JDK1.8 下载JDK1.8,我这边用的版本是jdk1.8.0_2022、解压jdk tar -zxvf jdk1.8.0_202.tar.gz 3、在/usr/local创建java文件夹,并将解压的jdk移动到/usr/local/java sudo mv jdk1.8.0_202…...

深入浅出解析ChatGPT引领的科技浪潮【AI行研商业价值分析】

Rocky Ding写在前面 【AI行研&商业价值分析】栏目专注于分享AI行业中最新热点/风口的思考与判断。也欢迎大家提出宝贵的意见或优化ideas,一起交流学习💪 大家好,我是Rocky。 2022年底,ChatGPT横空出世,火爆全网&a…...

.net 批量导出文件,以ZIP压缩方式导出

1. 首先Nuget ICSharpCode.SharpZipLib <script type"text/javascript">$(function () {$("#OutPutLink").click(function () { // 单击下文件时$.ajax({ // 先判断条件时间内没有文件url: "/Home/ExistsFile?statTime" $(&q…...

数据分析:某电商优惠卷数据分析

数据分析&#xff1a;某电商优惠卷数据分析 作者&#xff1a;AOAIYI 专栏&#xff1a;python数据分析 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;AOAIYI首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可…...

性能测试流程

性能测试实战一.资源指标分析1.判断CPU是否瓶颈的方法2.判断内存是否瓶颈的方法3.判断磁盘I/O是否瓶颈的方法4.判断网络带宽是否是瓶颈的方法二.系统指标分析三.性能调优四.性能测试案例1.项目背景2.实施规划&#xff08;1&#xff09;需求分析&#xff08;2&#xff09;测试方…...

zookeeper集群的搭建,菜鸟升级大神必看

一、下载安装zookeeperhttp://archive.apache.org/dist/zookeeper/下载最新版本2.8.1http://archive.apache.org/dist/zookeeper/zookeeper-3.8.1/二、上传安装包到服务器上并且解压&#xff0c;重命名tar -zxvf apache-zookeeper-3.8.1-bin.tar.gzmv apache-zookeeper-3.8.1-b…...

C语言之习题练习集

&#x1f497; &#x1f497; 博客:小怡同学 &#x1f497; &#x1f497; 个人简介:编程小萌新 &#x1f497; &#x1f497; 如果博客对大家有用的话&#xff0c;请点赞关注再收藏 &#x1f31e; 文章目录牛客网题号&#xff1a; JZ17 打印从1到最大的n位数牛客网题号&#x…...

Buuctf [ACTF新生赛2020]Universe_final_answer 题解

1.程序逻辑 程序逻辑并不复杂: 首先输入字符串,然后对字符串进行一个判断是否满足条件的操作 如果满足则对字符串进行处理并输出,输出的就是flag 2.judge_860函数 显然根据这十个条件可以通过矩阵解线性方程组,这里对变量的命名做了一些调整,让Vi对应flag[i]方便读 ​​​​…...

【Linux】环境变量

目录背景1.概念2.常见环境变量2.1 PATH指令和自定义程序向环境变量PATH中添加路径删除PATH中的路径2.2 env&#xff1a;显示所有环境变量2.3 环境变量相关的命令3.通过代码获取环境变量1.char* envp[]2.第三方变量enciron3.getenv函数获取指定环境变量4.利用获取的环境变量自制…...

单一职责原则

单一职责原则&#xff1a; 就一个类而言&#xff0c;应该只有一个引起它变化的原因&#xff0c;如果一个类承担的职责过多就等于把这些职责耦合在一起&#xff0c;至少会造成以下两方面的问题&#xff1a; 我们要去修改该类中的一个职责可能会影响到该类的其它职责。这种耦合…...

golangの并发编程(GMP模型)

GMP模型 && channel1. 前言2. GMP模型2.1. 基本概念2.2. 调度器策略2.3. go指令的调度流程2.4. go启动周期的M0和G02.5. GMP可视化2.6. GMP的几种调度场景3. channel3.1. channel的基本使用3.2. 同步器1. 前言 Go中的并发是函数相互独立运行的体现&#xff0c;Gorouti…...

MacBook Pro错误zsh: command not found: brew解决方法

问题描述&#xff1a;本地想安装Jenkins&#xff0c;但是brew指令不存在/我的电脑型号是19款的MacBook Pro&#xff08;Intel芯片&#xff09;。解决方法MacBook Pro 重新安装homebrew&#xff0c;用以下命令安装&#xff0c;序列号选择阿里巴巴下载源。/bin/zsh -c "$(cu…...

spring中BeanFactory 和ApplicationContext

在学习spring的高阶内容时&#xff0c;我们有必要先回顾一下spring回顾spring1.什么是springspring是轻量级的&#xff0c;指核心jar包时很小的&#xff1b;非侵入式的一站式框架(数据持久层&#xff0c;web层&#xff0c;核心aop)&#xff0c;为了简化企业级开发。核心是IOC&a…...

HC32L17x的LL驱动库之dma

#include "hc32l1xx_ll_dma.h"/// //函 数: //功 能: //输入参数: //输出参数: //说 明: // uint8_t LL_DMA_DeInit(DMA_TypeDef* DMAx, uint32_t Channel) {__IO uint32_t* dmac NULL;dmac &(DMAx->CONFA0);Channel << 4;dmac …...

SSM项目 替换为 SpringBoot

一、运行SSM项目 保证项目改为SpringBoot后运行正常&#xff0c;先保证SSM下运行正常。 项目目录结构 创建数据库&#xff0c;导入sql文件 查看项目中连接数据jar版本&#xff0c;修改对应版本&#xff0c;修改数据库配置信息 配置启动tomcat 运行项目&#xff0c;测试正常…...

RL笔记:动态规划(2): 策略迭代

目录 0. 前言 (4.3) 策略迭代 Example 4.2: Jack’s Car Rental Exercise 4.4 Exercise 4.5 Exercise 4.6 Exercise 4.7 0. 前言 Sutton-book第4章&#xff08;动态规划&#xff09;学习笔记。本文是关于其中4.2节&#xff08;策略迭代&#xff09;。 (4.3) 策略迭代 基…...

2023软件测试金三银四常见的软件测试面试题-【测试理论篇】

三、测试理论 3.1 你们原来项目的测试流程是怎么样的? 我们的测试流程主要有三个阶段&#xff1a;需求了解分析、测试准备、测试执行。 1、需求了解分析阶段 我们的SE会把需求文档给我们自己先去了解一到两天这样&#xff0c;之后我们会有一个需求澄清会议&#xff0c; 我…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

ubuntu搭建nfs服务centos挂载访问

在Ubuntu上设置NFS服务器 在Ubuntu上&#xff0c;你可以使用apt包管理器来安装NFS服务器。打开终端并运行&#xff1a; sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享&#xff0c;例如/shared&#xff1a; sudo mkdir /shared sud…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

MySQL JOIN 表过多的优化思路

当 MySQL 查询涉及大量表 JOIN 时&#xff0c;性能会显著下降。以下是优化思路和简易实现方法&#xff1a; 一、核心优化思路 减少 JOIN 数量 数据冗余&#xff1a;添加必要的冗余字段&#xff08;如订单表直接存储用户名&#xff09;合并表&#xff1a;将频繁关联的小表合并成…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

Vue3中的computer和watch

computed的写法 在页面中 <div>{{ calcNumber }}</div>script中 写法1 常用 import { computed, ref } from vue; let price ref(100);const priceAdd () > { //函数方法 price 1price.value ; }//计算属性 let calcNumber computed(() > {return ${p…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...