使用缓存降低数据库并发读写方案探索

文章目录

  • 前言
  • 缓存设计思想
    • 缓存划分
    • 缓存应用时机
  • 客户端缓存
    • 浏览器缓存
    • 网关或代理服务器缓存
    • CDN
    • PCDN
  • 服务端缓存
    • 本地缓存
      • 本地缓存实现
        • Java堆缓存
        • memcached/ecache
        • caffeine
        • ORM框架一级/二级缓存
    • 分布式缓存
      • 分布式缓存优缺点
      • 分布式缓存实现
      • 分布式缓存实施过程可能遇到问题
        • 分布式缓存数据一致性问题
        • 缓存穿透
        • 缓存击穿
        • 缓存雪崩

前言

随着系统的并发量增加,数据库的并发读写最终将成为整个提供的瓶颈,甚至压垮整个数据库,导致系统卡死等严重问题。通过缓存是缓解数据库压力的重要手段,通过缓存把绝大多数请求在读写数据库前拦截掉,大大降低数据库压力。同时缓存也是网站加速数据访问的重要手段。

缓存设计思想

缓存设计最核心的原则就是让数据离用户更近。优秀的缓存设计直接影响到系统的高并发性能和响应速度,甚至影响客户体验。缓存是改善软件应用性能的第一手段。缓存有三个作用范围:

  • 事务、
  • 应用、
  • 集群

缓存划分

缓存按照存放位置不同可以分为客户端缓存和服务端缓存。
缓存分层
客户端缓存:

  • 浏览器缓存
  • 网关及代理服务器缓存
  • CDN

服务器缓存:

  • 本地缓存:
  • 分布式缓存:
  • 数据库缓存:

缓存应用时机

一个好的缓存设计方案需要综合考虑缓存的存储、使用时机、优缺点、以及分布式高并发下缓存一致性、缓存命中、缓存击穿/雪崩等问题。

使用缓存有两个前提条件,一是数据访问热点不均,某些数据应该被放在缓存中;二是数据在某个时间段内有效,不会很快过期。

客户端缓存

客户端缓存通常指web前端缓存,可以分为:浏览器缓存和代理服务器缓存。是目前网站前端加速的主要方式,其实现基本方式是:将制定的网站资源(整体页面、静态文件(js、css、图片)等)周期性缓存起来,缓存时间可以从几秒到几天不等,极大减少了网站应用服务器和数据库负荷。

浏览器缓存

浏览器缓存是最靠近客户的缓存机制,当开启浏览器缓存后,客户访问同一个页面将不从服务器下载页面,也是从浏览器本地缓存目录读取页面,然后在浏览器中展示。对于不常变化资源可以使用强制缓存策略。浏览器缓存更新问题解决:可以在资源的引用地址(路径)后面增加hash、版本号等动态字符,从而达到更新资源引用URL目的,让之前的缓存强制失效(PS:其实并未立即失效,而是不在使用)。

网关或代理服务器缓存

将网页缓存到代理服务器上,多个用户访问同一个页面时,将直接从代理服务器把页面传送给用户。常见实现如,Ngnix反向代理缓存。使用反向代理服务器缓存实现简单,通常通过简单配置便可以实现,而不需要外增加代码开发。反向代理服务器缓存适合实时性要求不高或者经常不变的页面,如果门户首页、商品详情等页面。在生产级别网站,用户对网站的数据请求访问时,最先访问到的就是反向代理服务器,因此通过反向代理服务器的静态资源无需继续访问应用服务器便可返回给用户。

CDN

CDN是内容分发网络,其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输得更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度。如电商网站、视频网站、门户网站等会将用户访问量大的热点内存缓存在CDN。
CDN是网站提供跨区域服务优化网站响应速度、改善客户体验的重要手段。

PCDN

PCDN 是以 P2P 技术为基础,通过挖掘利用边缘网络海量碎片化闲置资源而构建的低成本、高品质内容分发网络服务。许多云盘、视频播放厂商经常使用该技术来进行内容分发。该手段非常好用,不过许多非法厂商在不告知个人用户的情况下白嫖用户带宽,给用户带来损失。

服务端缓存

在服务端编程中,缓存主要是将数据库中数据加载到内存中,之后对该数据的读写都是在内存中完成,减少对数据库的访问,是解决高并发场景数据库并发读写瓶颈的主要手段之一。同时基于内存的读写处理速度高于磁盘I/O,缓存也是提高服务响应速度和性能重要手段。
根据缓存是否与应用在同一进程,可以将缓存分为本地缓存和分布式缓存:

  • 本地缓存:应用同一进程内存空间缓存数据,数据读写都在同一进程。
  • 分布式缓存:独立部署的进程,通常与应用进行部署在不同机器,缓存的读写需要通过网络来完成数据的传输。

本地缓存

本地缓存优缺点:

  • 访问速度快,但无法缓存大量数据:本地缓存不需要跨网络传输,性能更好,但是由于本地缓存使用应用进程的内存空间,不能进行大数据存储。
  • 集群数据更新问题:本地缓存只支持本地进程应用访问,其他进程应用无法访问,因此需要额外的机制来保证数据的一致性,实现复杂度高且容易出错。比如通过redis或zookeeper实现分布式同步。
  • 数据随应用进程重启而丢失。

适用场景
本地缓存适用于缓存只读数据,如字典、统计类数据,以及进程独立数据,如本地长连接服务。

本地缓存实现

Java堆缓存

使用Java堆内存来缓存数据。没有对象的序列化和反序列化,是最快的缓存。在编程中常用HashMap和ConcurrentHashMap来实现本地缓存。Java堆缓存应该避免大数据量缓存(可能导致GC停顿时间过长),同时可以使用软引用/弱引用来缓存对象,可以使当内存不足时,强制回收这部分对象,释放内存。Java堆内存一般用于缓存较热的数据。

memcached/ecache

ecache是基于java的开源高效的、进程内缓存解决方案。ecache轻量、简单,被广泛应用于其他ORM框架数据二级缓存的底层实现(如Hinernate)。
memcached和ecache实现原理类似,基于K-V将数据缓存到内存,memcached支持多线程操作。相比ecache,memcached更加灵活。

caffeine

Caffeine是基于Java 的高性能缓存库,可提供接近最佳的命中率。Caffeine与ConcurrentMap类似,但是Caffeine与ConcurrentMap最根本的区别是,ConcurrentMap会保留添加到其中的所有元素,直到将其明确删除为止,而Caffeine能自动的回收存储的元素。
通过caffeine基准测试,可以看到caffeine在读写方面明显优与其他框架,在缓存命中率上Caffeine也不同于Guava,采用了更为优秀的Window TinyLfu算法,该算法是在LRU的基础上改进的版本。

ORM框架一级/二级缓存

许多ORM本身带缓存功能,比如Mybatis、JPA、Hibernate都支持一级缓存和二级缓存。一级缓存是默认开启的,其中Mybatis是针对namespace、JPA是针对与entityManager、Hibernate针对单Session。ORM框架缓存对于小型单体应该还是可以使用,不过对于大型生产级尤其是使用容器化部署分布式微服务场景建议关闭ORM框架缓存,单纯使用ORM框架就好。

分布式缓存

分布式缓存也叫进程外缓存,通常是独立于应用部署,通过网络进行缓存读写的数据传输。

分布式缓存优缺点

  • 支持大量数据存储,不受应用进行重启影响:分布式缓存是独立部署的进程,拥有独立的内存空间,并且一般以集群的方式拓展,故而可以进行大数据储存。
  • 数据集中存储,保证数据一致性:当应用采用集群部署时,集群每个节点通过统一的分布式缓存服务进行数据的读写操作,不存在本地缓存中数据更新问题,保证不同节点应用进行的数据一致性问题。
  • 数据读写分离、高性能、高可用:分布式缓存一般支持数据副本机制,可以实现读写分离,可以解决高并发场景中数据读写性能问题。并且由于在多节点缓存冗余数据,提高了存储数据的可用性,避免某个节点宕机导致数据不可用。
  • 数据基于网络传输,性能低于本地缓存。

分布式缓存实现

目前项目中用到的分布式缓存主要还是Redis、memcached。Redis因其高性能和高可用性,常被用于业务缓存,有效地减少数据库读取次数和压力。Memcached则因其简单高效,常用于需要高并发读写操作的场景。选择合适的分布式缓存技术需要根据具体的应用场景、数据类型、性能要求以及成本等因素综合考虑。

分布式缓存实施过程可能遇到问题

分布式缓存数据一致性问题

我们经常说到的分布式缓存一致性问题主要是数据库和缓存的读写一致性问题。 我们在项目中解决该问题主要还是采用最终一致性解决方案。首先给缓存设置过期时间是保证缓存最终一致性解决方案,其次所有数据的写操作以数据库为准,对缓存尽最大努力。

缓存更新策略:
先更新数据库再失效缓存

  • 失效:应用先从缓存获取数据,如果没有从数据库读取,成功后放入缓存。
  • 命中:应用从缓存读取数据,命中后返回
  • 更新:先更新数据库,然后失效缓存(延时双删)
缓存穿透

缓存穿透是指key对应的数据源不存在,导致每次针对key的请求都无法从存储层获取数据并写入到缓存,从而每次请求都落到数据库,失去了缓存意义。流量大时可能就拖垮了DB。

解决方案

  • 方案一:对于查询返回为空的数据,仍存储到缓存(需要设置缓存过期时间尽可能短)
  • 方案二:使用布隆过滤器,将可能存在的数据hash到足够大bitmap中,一个一定不存在的数据可以通过布隆过滤器拦截掉。

不过实际项目上还是较少使用布隆过滤器解决缓存穿透,因为布隆过滤器一旦创建便无法删除元素,当某个key已经存在数据源时无法直接从布隆过滤器删除key,要更新key需要重建整个布隆过滤器。布隆过滤器本身应用场景还是url去重、垃圾邮件过滤、黑白名单、敏感词等更多。

缓存击穿

缓存击穿主要出现在高并发的热点数据访问场景。导致缓存击穿原因主要是同一时间发生消除读写(删),导致并发下缓存失效。或者是并发读取缓存时,恰巧达到缓存失效还来不及从数据库读取并写入缓存。

解决方案

  1. 比较常见的方法是使用使用互斥锁(mutex)机制,当缓存失效时,不是立即去load DB,而是先执行set mutex(比如redis的setnx),如果操作成功,则load DB并写入缓存,如果操作失败则重试get缓存。
  2. 另外可以对某些静态热点数据使用永不过期策略或者长期有效策略。
缓存雪崩

大范围设置缓存相同的过期时间,如果一些应用初始加载缓存,采用并发写策略(多线程),导致了某一时间缓存全部失效,请求全部转发到DB,DB瞬时压力过大雪崩。高并发应用的缓存雪崩对于底层系统冲击非常可怕。缓存雪崩主要还是代码设计不合理导致,例如批量写入数据库并缓存的场景,在批量写入循环外层设置一个固定缓存时间,这样就会导致批量写入的数据缓存会在同一时点过期。

解决方案

  • 考虑加锁或者队列方式写缓存,避免缓存过期时间一致
  • 在设置缓存是在原有缓存失效时间基础加上一个随机值,降低过期时间的重复率。

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

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

相关文章

【模拟-BM100 设计LRU缓存结构】

题目 BM100 设计LRU缓存结构 描述 设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 capacity ,操作次数是 n ,并有如下功能: Solution(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存get(key)&am…

【C#】WinForm关闭新(二级)界面使主程序关闭

参考视频:https://www.bilibili.com/video/BV1JY4y1G7jo?p14&vd_source1c57ab1b2e551da5b65c0dfb0f05a493 1.背景介绍 主程序界面,点击弹出二级界面(同时隐藏主界面),不做任何设置,这时关闭二级界面…

SpringCloud-OpenFeign拓展-连接池、最佳使用方法、日志输出

目录 1 OpenFeign连接池 1.1 常见连接类型 1.2 连接池使用方法 1.2.1 引入依赖 1.2.2 开启连接池功能 1.2.3 配置完成,重启实例即可,底层将更改设置。 2 OpenFeign最佳使用方法 2.1 每个微服务都是单独的project,内部有三个独立模块 …

脖子以下是人机交互,脖子以上是人机融合智能

“脖子以下是人机交互,脖子以上是人机融合智能”这句话是当前人与人工智能配合技术发展的一种形象描述,一个是生理物理,一个是人脑电脑: 1、人机交互的重要性 脖子以下的人机交互在当前的人工智能系统中扮演着重要的角色。人机交互…

Leetcode1161. 最大层内元素和

Every day a Leetcode 题目来源:1161. 最大层内元素和 解法1:层序遍历 每次以「层」为单位进行拓展,统计该层的元素和,维护处理过程中的最大值层数和,以及层深度。 代码: /** lc appleetcode.cn id116…

Unity 编辑器扩展,获取目录下所有的预制件

先看演示效果 实现方案 1创建几个用于测试的cube 2,创建一个Editor脚本 3,编写脚本内容 附上源码 using UnityEditor; using UnityEngine;public class GetPrefeb : EditorWindow {private string folderPath "Assets/Resources"; // 指定预…

两款好用的IOS、Android图片处理应用

GIF 小助手 GIF工具包是一个简单实用的GIF动画编辑器,目前仅支持IOS平台。 使用该软件,可以将多个图像、视频和现场照片创建为gif。 主要功能: 多种输入源:用户可以将多个图片、视频或Livephoto转换成GIF动图。 编辑功能&#…

深度解析:ChatGPT全面测评——功能、性能与用户体验全景剖析

从去年底至今,由 OpenAI 发布的大规模语言模型 ChatGPT 引发了几乎所有科技领域从业者的高度关注。据瑞银集团的报告显示,自 2023 年 1 月起,仅两个月内,ChatGPT 的月活用户数便超过了 1 亿。 ChatGPT 被誉为“最强 AI”&#xff…

【C++】用红黑树封装map、set

用红黑树封装map、set 1. 红黑树1.1 模板参数的控制1.1.1 Value1.1.2 KeyOfValue 1.2 正向迭代器1.2.1 构造函数1.2.2 begin()end()1.2.3 operator()1.2.4 operator--()1.2.5 operator*()1.2.6 operator->()1.2.7 operator()1.2.8 operator!()1.2.9 总代码 1.3 反向迭代器1.…

vue2的element的table组件使用form校验

1.需求描述 vue2有时候做自增表格el-table&#xff0c;希望能够带一些校验&#xff0c;但又不想手搓校验逻辑&#xff0c;可以借用el-form的校验逻辑。 2.代码处理 1. html <template><div class"sad-cont"><el-form ref"form" :model&…

WPF视频学习-基础知识篇

1.简介WPF&#xff1a; C# 一套关于windows界面应用开发框架 2.WPF和winform的差别 &#xff0c;(WPF比较新) 创建新项目使用模板&#xff1a; WPF使用.xaml后缀&#xff0c;双击可查看操作界面和设置代码&#xff0c;其文件展开之后中有MainWindow.xaml.cs为程序交互逻辑。…

1.Vue2使用ElementUI-初识及环境搭建

目录 1.下载nodejs v16.x 2.设置淘宝镜像源 3.安装脚手架 4.创建一个项目 5.项目修改 代码地址&#xff1a;source-code: 源码笔记 1.下载nodejs v16.x 下载地址&#xff1a;Node.js — Download Node.js 2.设置淘宝镜像源 npm config set registry https://registry.…

Python实现连连看9

&#xff08;2&#xff09;标识选中的图片 在判断出玩家选中的是哪一张图片之后&#xff0c;接下来就可以标识选中的图片了&#xff0c;即在该选中的图片外围画矩形。代码如下所示。 FIRSTCLICK True #FIRSTCLICK是全局变量 if(click_col>0 and click_row>0) and \(no…

GUI编程-01

组件 窗口 弹窗 面板 文本框 列表框 按钮 图片 监听事件 鼠标 键盘事件 破解工具 Java提供了丰富的图形用户界面&#xff08;Graphics User Interface&#xff0c;GUI&#xff09;的类库&#xff0c;基于这些类库可以编写窗口程序。 Java关于图形界面的类库主要放在…

uniapp自定义的下面导航

uniapp自定义的下面导航 看看效果图片吧 文章目录 uniapp自定义的下面导航 看看效果图片吧 ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/6aa0e964741d4dd3a58f4e86c4bf3247.png) 前言一、写组件、我这里就没有写组件了直接写了一个页面&#xff1f;总结 前言 在…

JWT 快速入门

什么是 JWT JSON Web Token&#xff08;JWT&#xff09;是目前最流行的跨域身份验证解决方案 JSON Web Token Introduction - jwt.ioLearn about JSON Web Tokens, what are they, how they work, when and why you should use them.https://jwt.io/introduction 一、常见会…

Vue13-计算属性的简写

一、计算属性的简写 注意&#xff1a; 当计算属性只有get&#xff0c;没有set的时候&#xff0c;才能用简写形式&#xff01;&#xff01;&#xff01;

端午与高考的交汇点:家的温暖与梦想的起点

当端午节的粽香弥漫在街头巷尾&#xff0c;高考的脚步也悄然而至。这两个看似毫无关联的时刻&#xff0c;却在每年的六月&#xff0c;奇妙地交汇在一起&#xff0c;为我们带来了一段特别的记忆。这不仅是家的温暖与梦想的起点相遇的时刻&#xff0c;更是传统文化与现代追求共融…

Rust-06-所有权

所有权&#xff08;系统&#xff09;是 Rust 最为与众不同的特性&#xff0c;它让 Rust 无需垃圾回收即可保障内存安全&#xff0c;下面是所有权以及相关功能&#xff1a;借用&#xff08;borrowing&#xff09;、slice 以及 Rust 如何在内存中布局数据。 通过所有权系统管理内…

Java版工程项目管理平台:以源码驱动,引领工程企业数字化转型

在当今数字化时代&#xff0c;随着企业的扩张和业务的增长&#xff0c;传统的工程项目管理方法已显不足。为了提升管理效率、减轻工作负担、增强信息处理的快速性和精确度&#xff0c;工程企业亟需借助数字化技术进行转型升级。本文将向您展示一款基于Spring Cloud、Spring Boo…