使用缓存降低数据库并发读写

前言

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

缓存设计思想及方案

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

  • 事务、
  • 应用、
  • 集群

缓存设计方案

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

缓存分层

客户端缓存:

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

服务器缓存:

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

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

缓存详细设计方案

客户端缓存

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

浏览器缓存
浏览器缓存是最靠近客户的缓存机制,当开启浏览器缓存后,客户访问同一个页面将不从服务器下载页面,也是从浏览器本地缓存目录读取页面,然后在浏览器中展示。对于不常变化资源可以使用强制缓存策略,而精彩变动资源可以禁止浏览器缓存。浏览器缓存更新问题解决:可以在资源的引用地址(路径)后面增加hash、版本号等动态字符,从而达到更新资源引用URL目的,让之前的缓存强制失效(PS:其实并未立即失效,而是不在使用)。
网关或代理服务器缓存
将网页缓存到代理服务器上,多个用户访问同一个页面时,将直接从代理服务器把页面传送给用户。常见实现如,Ngnix反向代理缓存。使用反向代理服务器缓存实现简单,通常通过简单配置便可以实现,而不需要外增加代码开发。反向代理服务器缓存适合实时性要求不高或者经常不变的页面,如果门户首页、商品详情等页面。

服务端缓存

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

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

本地缓存

本地缓存优缺点

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

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

  1. Java堆缓存
    使用Java堆内存来缓存数据。没有对象的序列化和反序列化,是最快的缓存。在编程中常用HashMap和ConcurrentHashMap来实现本地缓存。Java堆缓存应该避免大数据量缓存(可能导致GC停顿时间过长),同时可以使用软引用/弱引用来缓存对象,可以使当内存不足时,强制回收这部分对象,释放内存。Java堆内存一般用于缓存存储较热的数据。
  2. memcached/ecache
    ecache是基于java的开源高效的、进程内缓存解决方案。ecache轻量、简单,被广泛应用于其他ORM框架数据缓存的底层实现(如Hinernate)。
    memcached和ecache实现原理类似,基于K-V将数据缓存到内存,memcached支持多线程操作。相比ecache,memcached更加灵活。
  3. caffeine
    Caffeine是基于Java 8的高性能缓存库,可提供接近最佳的命中率。Caffeine与ConcurrentMap类似,但是Caffeine与ConcurrentMap最根本的区别是,ConcurrentMap会保留添加到其中的所有元素,直到将其明确删除为止,而Caffeine能自动的回收存储的元素。
    通过caffeine基准测试,可以看到caffeine在读写方面明显优与其他框架,在缓存命中率上Caffeine也不同于Guava,采用了更为优秀的Window TinyLfu算法,该算法是在LRU的基础上改进的版本。

分布式缓存

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

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

分布式缓存实现
redis/memcached
分布式缓存一致性方案
缓存一致性问题主要是数据库和缓存的读写一致性问题。

首先给缓存设置过期时间是保证缓存最终一致性解决方案,所有数据的写操作以数据库为准,对缓存尽最大努力。

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

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

缓存穿透及解决方案

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

解决方案

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

缓存击穿及解决方案

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

解决方案

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

缓存雪崩及解决方案

是指设置缓存相同的过期时间,如果一些应用初始加载缓存,采用并发写策略(多线程),导致了某一时间缓存全部失效,请求全部转发到DB,DB瞬时压力过大雪崩。高并发应用的缓存雪崩对于底层系统冲击非常可怕。

解决方案

  • 考虑加锁或者队列方式写缓存,避免缓存过期时间一致
  • 在设置缓存是在原有缓存失效时间基础加上一个随机值,降低过期时间的重复率。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容