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

2024-06-09 07:20

本文主要是介绍使用缓存降低数据库并发读写方案探索,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 缓存设计思想
    • 缓存划分
    • 缓存应用时机
  • 客户端缓存
    • 浏览器缓存
    • 网关或代理服务器缓存
    • 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瞬时压力过大雪崩。高并发应用的缓存雪崩对于底层系统冲击非常可怕。缓存雪崩主要还是代码设计不合理导致,例如批量写入数据库并缓存的场景,在批量写入循环外层设置一个固定缓存时间,这样就会导致批量写入的数据缓存会在同一时点过期。

解决方案

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

这篇关于使用缓存降低数据库并发读写方案探索的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1044532

相关文章

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来,无需把原生代码转换为uniapp,可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录,原生入口组件的路径 4、manifest.json中配置分包,使用原生组件 5、需要把原生代码包里的页面修改成组件的方

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

Lipowerline5.0 雷达电力应用软件下载使用

1.配网数据处理分析 针对配网线路点云数据,优化了分类算法,支持杆塔、导线、交跨线、建筑物、地面点和其他线路的自动分类;一键生成危险点报告和交跨报告;还能生成点云数据采集航线和自主巡检航线。 获取软件安装包联系邮箱:2895356150@qq.com,资源源于网络,本介绍用于学习使用,如有侵权请您联系删除! 2.新增快速版,简洁易上手 支持快速版和专业版切换使用,快速版界面简洁,保留主

如何免费的去使用connectedpapers?

免费使用connectedpapers 1. 打开谷歌浏览器2. 按住ctrl+shift+N,进入无痕模式3. 不需要登录(也就是访客模式)4. 两次用完,关闭无痕模式(继续重复步骤 2 - 4) 1. 打开谷歌浏览器 2. 按住ctrl+shift+N,进入无痕模式 输入网址:https://www.connectedpapers.com/ 3. 不需要登录(也就是

关于如何更好管理好数据库的一点思考

本文尝试从数据库设计理论、ER图简介、性能优化、避免过度设计及权限管理方面进行思考阐述。 一、数据库范式 以下通过详细的示例说明数据库范式的概念,将逐步规范化一个例子,逐级说明每个范式的要求和变换过程。 示例:学生课程登记系统 初始表格如下: 学生ID学生姓名课程ID课程名称教师教师办公室1张三101数学王老师101室2李四102英语李老师102室3王五101数学王老师101室4赵六103物理陈

数据库期末复习知识点

A卷 1. 选择题(30') 2. 判断范式(10') 判断到第三范式 3. 程序填空(20') 4. 分析填空(15') 5. 写SQL(25') 5'一题 恶性 B卷 1. 单选(30') 2. 填空 (20') 3. 程序填空(20') 4. 写SQL(30') 知识点 第一章 数据库管理系统(DBMS)  主要功能 数据定义功能 (DDL, 数据定义语

给数据库的表添加字段

周五有一个需求是这样的: 原来数据库有一个表B,现在需要添加一个字段C,我把代码中增删改查部分进行了修改, 比如insert中也添入了字段C。 但没有考虑到一个问题,数据库的兼容性。因为之前的版本已经投入使用了,再升级的话,需要进行兼容处理,当时脑子都蒙了,转不过来,后来同事解决了这个问题。 现在想想,思路就是,把数据库的表结构存入文件中,如xxx.sql 实时更新该文件: CREAT