分布式之缓存详解

news/2024/4/28 14:08:30/文章来源:https://blog.csdn.net/jbjmh/article/details/137026777

缓存设计

导流:将原本复杂的操作请求(sql 大堆),引导到简单的请求上。前人栽树后人乘凉。

缓存:空间换时间的一个做法。

redis, memcached,localcache guava,客户端缓存,

user_info_xxxx : 姓名,年龄,xxx。getKey 内存操作

select * from user where id = xxx。 硬盘IO

缓存的收益

成本,收益。

读、写。

位置:介于 请求方和提供方之间。

收益:节省了响应时间。

成本:

kv

计算key的时间,查询key的时间,转换值的时间。命中率P。

所有数据的查询时间=计算key的时间+查询key的时间+转换值的时间+(1-p) * 原始查询时间

计算key的时间+查询key的时间+转换值的时间+(1-p) * 原始查询时间 <<<< 所有数据 的原始查询时间

适合:耗时特别长的查询(复杂sql),读多写少。

缓存键的设计

kv

单向函数:给定输入,很容易,很快能计算出结果,但是给你结果,很难计算出输入。

正向快速,逆向困难,输入敏感,冲突避免。

sha-256

冲突的概率 极低。

查询key的速度 取决于:物理位置 (内存,硬盘)。

值:

序列化

对象

总结:

无碰撞。高效生成。高效查询,高效转换。

上面所有:都被中间件提供的api 封装了。

实际中:前缀_业务关键信息_后缀。 公司统一制定规范

user_order_xxxx:

user+order+xxxx:

user-order-xxxx:

$

缓存的更新机制

被动更新

调用方 暂存方(缓存) 数据提供方

被动:有效期到后,再次写入。

1。客户端 查数据,缓存中没有,从提供方获取,写入缓存(有一个过期时间t)。

2。在t内,所有的查询,都由缓存提供。所有的写,直接写数据库。

3。当 缓存数据 t 到点了,缓存 数据 变没有。后面的查询,回到了第1步。

适合:对数据准确性和实时性要求不高的场景。比如:商品 关注的人数。

主动更新

主动:被其他操作直接填充。

数据库:更新数据库

缓存:更新缓存,删除缓存

保持一个定量,考虑围绕它的变量,这样才不会有异常的遗漏。

更新缓存,更新数据库

数据不一致的风险比较高,所以一般不采用。

更新数据库,更新缓存

一般也不采用。

请求被阻塞,

业务要求:修改数据库,然后经过大量的计算,才能得出缓存的值。浪费了性能。如果缓存还没用,更浪费。

删除缓存,为了节省计算时间。

删除缓存,更新数据库

一般不采用,因为大概率 读比写快。

延时双删,休眠多久,系统吞吐量下降。

昨天被高德一个面试问:说,你这个延时双删有这么几步操作。如果其中某一步失败了这么办?

删除缓存

更新数据库:事务,回滚就OK。

第二次删除缓存

重试删除:当你前面的操作,无法回滚时,为了保证后续数据的一致性,

(最便宜的做法)硬着头皮往前走,重试。

借用中间件:消息队列,重发消息。

系统外订阅:canal。binlog。

二次删除key,和我们的业务代码解耦。

更新数据库,删除缓存

经常采用的方式。

cache-aside模式。

异常流程:

前提:缓存无数据。数据库有数据。

A:查询,B:更新

A查缓存,无数据,去读数据库,旧值。-----查

B更新数据库 新值

B删除缓存

A 将旧值写入缓存。

脏数据。

就是说这个方案也有问题?这次是读的速度慢了?

读比写慢 概率很低,极低。

缓存无数据。

如果非要解决,延时双删。再删除一次。

Read/Write Through

程序启动时,将数据库 的数据, 放到缓存中,不能等启动完成,再放缓存中。

Write Behind

降低了写操作的时间,提高了系统吞吐量。

双写一致性。

缓存清理机制

如何提升缓存命中率:尽可能多的缓存。所有数据都放缓存,命中率 100%。

我们需要用有限的缓存空间,发挥最大的作用。

如何判断 一个数据 在未来被访问的次数呢?

读的时间频繁:当清理一个数据的时候,发现,它一直被访问,那我就认为他 马上的未来,也会被访问。

写入时间的时间节点。

我是问代码怎么实现:当清理数据时,发现他一直被访问。

读一次,记录一次 ,时间。阈值。

读:

getKey, k =0 ttl 1min , incr

if(!getK > 1){

delete k

}

时效性清理

给缓存设置一个过期时间,到期 缓存 自动 清理。

缓存中的数据 有 一个 生存时间:ttl。过期时间。set k v ex 10 s

set cookie   过期时间。

k v 10s

定时任务轮询。delete

自动清理机制: cookie redis expire .。(本质:轮询)

数目阈值式清理机制

判断缓存中的缓存的数量 达到一定值 ,对缓存进行清理。

阈值:根据自己的业务来定。1g,1m,1024个, 800 80%。

采取什么策略去清理:

fifo: 先进先出

package com.example.cachetest;import java.util.LinkedList;
import java.util.Queue;/*** 数据阈值式清理*/
public class CacheThresholdTest {public static void main(String[] args) {Queue<String> queue = new LinkedList<>();for (int i = 0; i < 4; i++) {setCache(queue,""+i);}}public static void setCache(Queue<String> queue,String cache){int size = queue.size();if (size >= 3){queue.poll();}queue.add(cache);System.out.println("缓存中的值如下:");for (String q: queue) {System.out.println(q);}}
}

random:随机

lru:规律:

LinkedHashMap 套。fifo,lru。

map:存 键值对。

顺序:插入顺序 fifo,访问顺序 lru。

removeEldestEntry。

package com.example.cachetest;import org.junit.jupiter.api.Test;import java.util.LinkedHashMap;
import java.util.Map;
public class TestCache {@Testpublic void testLinkedHashMap() {// 在介绍accessOrder属性的时候说accessOrder设置为false时,按照插入顺序,设置为true时,按照访问顺序LinkedHashMap<String, String> map = new LinkedHashMap<String, String>(5, 0.75F, true) {@Overrideprotected boolean removeEldestEntry(Map.Entry<String, String> eldest) {//当LinkHashMap的容量大于等于5的时候,再插入就移除旧的元素return this.size() >= 5;}};map.put("1", "bb");map.put("2", "dd");map.put("3", "ff");map.put("4", "hh");System.out.println("原始顺序:");print(map);map.get("2");System.out.println("2 最近访问:");print(map);map.get("3");System.out.println("3 最近访问:");print(map);map.put("5","oo");System.out.println("加元素");print(map);}void print(LinkedHashMap<String, String> source) {source.keySet().iterator().forEachRemaining(System.out::println);}
}   

实现:k v。 map 一台服务器上能用。redis。

软引用清理

用空间换时间的模块。尽量用空间,用以提高缓存 命中率p。

适时的释放空间,gc。

识别出要清理的缓存,然后清除。

gc root引用。

强:哪怕自己oom,不清理。(不用)

软:当空间不足的时候,会被回收。√。

空间不足时,进行缓存清理。软引用。

把值 放到 SoftReference 包装中。

package com.example.cachetest;import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.*;/*** 软引用 缓存 实验*/
public class CacheSoftReferenceTest {public static void main(String[] args) throws InterruptedException {soft();}static void soft(){// 缓存Map<Integer, SoftRefedStudent> map = new HashMap<Integer, SoftRefedStudent>();ReferenceQueue<Student> queue = new ReferenceQueue<Student>();int i = 0;while (i < 10000000) {Student p = new Student();map.put(i, new SoftRefedStudent(i, p, queue));//p = null;SoftRefedStudent pollref = (SoftRefedStudent) queue.poll();if (pollref != null) {//找出被软引用回收的对象//以key为标志,从map中移除System.out.println("回收"+pollref.key);map.remove(pollref.key);System.out.println(i+"新一轮================================================");Iterator<Map.Entry<Integer, SoftRefedStudent>> iterator = map.entrySet().iterator();while (iterator.hasNext()){Map.Entry entry = iterator.next();if ((int)entry.getKey() == pollref.key){System.out.println("见鬼了");}}System.out.println(i+"新一轮================================================");}i++;}System.out.println("done");}
}class Student{private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}class SoftRefedStudent extends SoftReference<Student> {public int key;// 第3个参数叫做ReferenceQueue,是用来存储封装的待回收Reference对象的/*** 当Student对象被回收后,SoftRefedStudent对象会被加入到queue中。*/public SoftRefedStudent(int key, Student referent, ReferenceQueue<Student> q) {super(referent, q);this.key = key;}
}

缓存清理机制总结

时效式清理+数目阈值:防止:短期内,密集查询,导致缓存空间的急剧增大。

–自己的完整思路。

lru+软引用:保证热数据,最大限度的提高 缓存命中率,p。

不建议:仅仅使用 软引用。因为我们失去了对它的控制。

目的:提高缓存命中率,节省空间,=》提升性能。

缓存风险概述

在系统中,每增加一个环节,就多一份风险。用是不得已。

缓存穿透

缓存中没有,数据库也没有。

方案:在第一次调用的时候,数据提供方返回一个空值,将空值放到缓存中。

缓存雪崩

大量缓存突然失效,导致大量的请求,倾泻到数据库上,引起数据库压力骤增。

时效式清理:批量缓存,统一时间到期。缓存ttl=(固定时间,结合业务)+随机时间。

软引用清理:某个时间点,空间突然紧张,常用的缓存用强引用,不常用的用软引用。

缓存击穿

高频率的缓存,突然失效,大量请求倾泻到数据库上。

lru:

read write through or write behind.更新机制:无所谓。数据永远留在缓存当中。

缓存预热

read write through or write behind

预热:高频访问的,提前准备。

计价规则,提前加载到缓存中。

系统启动前:加载缓存,不让缓存统一时间过期。

电商系统:热门商品,提前加入缓存。网约车中,计价规则提前加入缓存。

热门数据,加到缓存。

缓存风险的总结

遇到风险,分析原因,解决之。

原因:更新机制,清理机制。

缓存的位置

缓存来源:L1 L2 L3。

缓存的读取过程:

思考:如何避免cpu浪费时间。

减少我的等待时间----缓存。

我尽量多做事情-----多线程。

目的:降本增效。

级联系统缓存位置

要想系统性能好,缓存一定要趁早。

客户端缓存位置

1

2 秒杀系统,商品详情页就是静态文件(扣一块动态的)。

降级。

代码:storage。

浏览器:cookie。失效时间。如果非必要,不要用cookie做缓存。

静态缓存

1。静态页面。apache。录个视频,apache静态页。

2。通过数据库查出来的。

如果每个用户查出来的都一样。 物流信息:省市区。

凡是与用户个体无关的具有较强通用性的数据,都可以作为静态数据缓存。

已经有缓存页面,后台更改数据之后,如何让数据快速生效。cache aside。

不适合缓存通用性很差的数据。

服务缓存

个性化的动态的不值得缓存。但是 这些数据的生成 都有一个过程。

数据库本身的缓存

aside。

数据库耗时比较久。

怎么做?

冗余字段。订单表里 id,有用户姓名,商品名称。

中间表:学生表,课程表,排课表。

查询缓存:建议不用。mysql8以上,抛弃了。query cache.

select * from user_info

SELECT * from user_info.

指定规范,大小写该统一就统一。my.ini my.cnf。

清理碎片,flush query cache., reset query cache.

历史表:将数据放到 历史表中,以后的操作比如说 统计,可以延迟操作。而中间的数据存储 ,相当于一次缓存。

coder学员:新老数据,还在一起,统计数据剥离。

写缓存

目的:削峰。

数据处理方的 处理速率是固定的 ,为了 防止请求 洪峰 压垮系统。采用写缓存。

写缓存收益

只要能给数据进行更改的操作,都叫写。

数据处理方时间。10s

引入缓存后:写缓存时间 2s,从缓存读取数据的时间,传递时间,数据处理方时间。

收益在于:用户。-8s。减少了用户响应时间,提升了系统吞吐量。

读缓存和写缓存:

读缓存:用缓存的命中率,替换数据提供方的操作。能减少用户的请求时间,能减少系统的总处理时间。

写缓存:花费额外的时间。来延迟数据处理方的操作,减少用户的等待。只能减少请求响应的时间,反而会增加系统的总处理时间。

image.png

是。

1s 0.1s(1s) 10倍。

image.png

i like u(you)

4(for) u

2(to) B

log4j log for java

C#。

day day up:

cache aside。更新完数据库,删除缓存。 迁移到: 修改完页面,删除静态页。io.write(“d:/apache/www/x.html”)

写缓存实践

利用redis 发布订阅。

MQ

数据库。(先写数据,剩下的和主业务无关的操作,后置)

目的:只要能减少用户的响应时间。就OK。

适合场景:请求峰谷值变化明显、对实时性要求不高的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1027498.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Micron 256 GB DDR5-8800 MCR DIMM:适用于大型服务器的大型内存

美光本周宣布&#xff0c;它已经开始对其 256 GB multiplexer combined &#xff08;MCR&#xff09; DIMM 进行采样&#xff0c;这是该公司迄今为止容量最大的内存模块。这些全新的基于 DDR5 的 MCRDIMM 面向下一代服务器&#xff0c;特别是那些由英特尔至强可扩展“Granite R…

TrackballControls是Three.js中的一个相机控件,它允许用户通过鼠标拖拽、滚轮缩放以及键盘移动相机,实现类似于球形的相机旋转操作。

demo案例 TrackballControls是Three.js中的一个相机控件&#xff0c;它允许用户通过鼠标拖拽、滚轮缩放以及键盘移动相机&#xff0c;实现类似于球形的相机旋转操作。这个控件可以用于3D场景中&#xff0c;以提供更好的用户体验。以下是对TrackballControls的入参、出参、方法…

pulsar: kafka on pulsar之把pulsar当kafka用

一、下载协议包&#xff08;要和pulsar版本比较一致&#xff09; https://github.com/streamnative/kop/releases?q2.8.0&expandedtrue二、在pulsar的根目录创建一个protocols目录&#xff0c;将上述包放到这个目录里 三、编辑broker.conf(如果是集群)或者standalone.con…

振弦采集仪在预防地质灾害监测中的作用与应用前景

振弦采集仪在预防地质灾害监测中的作用与应用前景 振弦采集仪&#xff08;String Vibrating Sensor&#xff0c;简称SVM&#xff09;是一种用于地质灾害监测的重要仪器&#xff0c;它通过测量地面振动信号来预测和预警地质灾害的发生。SVM的作用在于提供实时、准确的地质灾害监…

最优算法100例之10-数组中重复出现多次的数

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不…

QT环境搭建

学习QT 一、QT环境搭建二、QT的SDK下载三、认识QT SDK 中自带的一些程序 一、QT环境搭建 QT开发环境&#xff0c;需要安装三个部分。 c编译器&#xff08;gcc、cl.exe……不是visual studio&#xff09;QT SDK&#xff08;QT SDK里面已经内置了C编译器&#xff1b;SDK就是软件…

009_lhs_rhs_in_Matlab中的左值和右值约定

Matlab中的左值和右值约定 1. 左值和右值 我们在把Matlab作为计算器来使用时&#xff0c;有些时候会直接列出一个表达式&#xff0c;等着Matlab打印出计算结果。就这个简单的举动&#xff0c;在计算机科学中&#xff0c;也有一个高大上的名字&#xff0c;叫什么REPL&#xff…

OpenCV 如何使用 XML 和 YAML 文件的文件输入和输出

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;如何利用OpenCV4.9离散傅里叶变换 下一篇: 目标 本文内容主要介绍&#xff1a; 如何使用 YAML 或 XML 文件打印和读取文件和 OpenCV 的文本条目&#xff1f;如何对 OpenCV …

mysql--事务四大特性与隔离级别

事务四大特性与隔离级别 mysql事务的概念事务的属性事务控制语句转账示例 并发事务引发的问题脏读脏读场景 不可重复读幻读幻读场景 事务的隔离级别读未提交读已提交可重复读&#xff08;MySQL默认&#xff09; 总结 mysql事务的概念 事务就是一组操作的集合&#xff0c;他是一…

Unbtun-arach64架构安装PySide2(python3.6)

aarch平台是无法通过pip安装PySide2的&#xff0c;同时利用源码下载一直报错 1. 我是python3.6.9&#xff0c;在官网上找到对应的PySide2版本 5.15.2.所以首先在官网下载Qt5.15.2的源码&#xff1a;https://download.qt.io/archive/qt/5.15/5.15.2/single/ 2. 编译qt环境 aar…

win11蓝牙图标点击变灰,修复过程

问题发现 有一天突然心血来潮想着连接蓝牙音响放歌来听,才发现win11系统右下角菜单里的蓝牙开关有问题。 打开蓝牙设置,可以正常直接连上并播放声音,点击右下角菜单里的蓝牙开关按钮后,蓝牙设备也能正常断开,但是按钮直接变深灰色,无法再点击打开。 重启电脑,蓝牙开关显…

Parade Series - SVG Resource

iconfont https://www.iconfont.cn/?spma313x.search_index.i3.2.74e53a819tkkcG音符 <div class"form-group"><a href"Javascript:reload();" class"btn btn-icon btn-outline-light btn-block" style";"><svg t&q…

Docker命令及部署Java项目

文章目录 简介Docker镜像镜像列表查找镜像拉取镜像删除镜像镜像标签 Docker容器容器启动容器查看容器停止和重启后台模式和进入强制停止容器清理停止的容器容器错误日志容器别名及操作 Docker部署Java项目 简介 Docker是一种容器化技术&#xff0c;可以帮助开发者轻松打包应用…

学透Spring Boot — [二] Spring 和 Spring Boot的比较

欢迎关注我们的专栏 学透 Spring Boot 一、创建一个简单Web应用 本篇文章&#xff0c;我们将会比较 Spring 框架和 Spring Boot 的区别。 什么是 Spring? 也许你在项目中已经可以很熟练的使用 Spring 了&#xff0c;但是当被问到这个问题时&#xff0c;会不会犹豫一下&#…

SQLyog连接MySQL8.0+报错:错误码2058的解决方案

最近把mysql从5.7迁移到8.3.0发现连接不上 因为 MySQL 从 8.0 版本开始&#xff0c;新增了caching_sha2_password授权插件 技术博客 http://idea.coderyj.com/ 1.更换sqlyog 更新到13.1.3之后的版本 2.取消mysql8的加密授权机制 mysql> ALTER USER sqlyog% IDENTIFIED WIT…

Nginx【概述:网页服务器 并发能力强】【常见命令】【部署实战】【反向代理】

Nginx-概述 介绍下载和安装下载安装重点目录和文件如下 Nginx-命令常用命令1). 查看版本2). 检查配置文件3). 启动4). 停止5). 重新加载 环境变量配置 Nginx-应用配置文件结构部署静态资源介绍测试1). 将静态资源上传到 /usr/local/nginx/html 目录2). 启动nginx3). 访问4). 配…

栈和队列——c语言实现栈

本节复习栈和队列中栈的增删查改。 首先回顾一下栈的性质&#xff1a; 栈的存储数据的原则是“后入先出”&#xff0c; 先入的在栈底&#xff1b; 后入的在栈顶。&#xff0c;弹出数据时在栈顶弹出。 目录 准备文件 创建栈的结构体蓝图 栈的初始化 入栈 出栈 获取栈顶元素 获…

MoonBit MeetUp回顾——张正、宗喆:编程语言在云原生与区块链领域的技术探索

宗喆和张正分别给我们带了 KCL 相关的最新进展&#xff0c;由蚂蚁集团开发的 Rust 编写的开源 DSL&#xff0c;目标是优化云原生策略配置和用户体验。它通过引入动态配置管理、配置校验和基础设施抽象等核心概念&#xff0c;解决开发者认知负担、配置膨胀和标准化工具缺乏的问题…

目标检测的相关模型图:YOLO系列和RCNN系列

目标检测的相关模型图&#xff1a;YOLO系列和RCNN系列 前言YOLO系列的图展示YOLOpassthroughYOLO2YOLO3YOLO4YOLO5 RCNN系列的图展示有关目标检测发展的 前言 最近好像大家也都在写毕业论文&#xff0c;前段时间跟朋友聊天&#xff0c;突然想起自己之前写画了一些关于YOLO、Fa…

自己编译SQLite或将SQLite移植到新的操作系统(六)

返回&#xff1a;SQLite—系列文章目录 上一篇:SQLite中的动态内存分配&#xff08;五&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 1.0 引言 对于大多数应用程序&#xff0c;推荐的构建方法 SQLite是使用合并代码 文件 sqlite3.c 及其相应的头文件 sqlite3.…