多级缓存设计详解 | 给数据库减负,刻不容缓!
关注我们获得更多内容
作 者 简 介
王梓晨
物流研发部架构师,GIS 技术部负责人,2012 年加入京东,多年一线团队大促备战经验,负责物流研发一些部门的架构工作,专注于低延迟系统设计与海量数据处理。曾负责青龙配送分单团队,主导重构架构设计与主要研发工作,短期内提升了服务性能数十倍。还设计研发了地址配送网点分类模型,实现了配送到路区的精准化分单,降本增效,大幅提升了自动分单准确率。目前负责物流 GIS 部门,先后主导了国标转京标、物流可视化等项目。
自古兵家多谋,《谋攻篇》,“故上兵伐谋,其次伐交,其次伐兵,其下攻城。攻城之法,为不得已”,可见攻城之计有很多种,而爬墙攻城是最不明智的做法,军队疲惫受损、钱粮损耗、百姓遭殃。故而我们有很多迂回之策,谋略、外交、军事手段等等,每一种都比攻城的代价小,更轻量级,缓存设计亦是如此。
>>>> 为什么要设计缓存呢?
其实高并发应对的解决方案不是互联网独创的,计算机先祖们很早就对类似的场景做了方案。比如《计算机组成原理》这样提到的 cpu 缓存概念,它是一种高速缓存,容量比内存小但是速度却快很多,这种缓存的出现主要是为了解决 cpu 运算速度远大于内存读写速度,甚至达到千万倍。
传统的 cpu 通过 fsb 直连内存的方式显然就会因为内存访问的等待,导致 cpu 吞吐量下降,内存成为性能瓶颈。同时又由于内存访问的热点数据集中性,所以需要在 cpu 与内存之间做一层临时的存储器作为高速缓存。
随着系统复杂性的提升,这种高速缓存和内存之间的速度进一步拉开,由于技术难度和成本等原因,所以有了更大的二级、三级缓存。根据读取顺序,绝大多数的请求首先落在一级缓存上,其次二级...
cpu core1 |
cpu core2 |
||
L1d (一级数据缓存) |
L1i (一级指令缓存) |
L1d (一级数据缓存) |
L1i (一级指令缓存) |
L2 |
L2 |
||
L3 |
L3 |
故而应用于 SOA 甚至微服务的场景,内存相当于存储业务数据的持久化数据库,其吞吐量肯定是远远小于缓存的,而对于 java 程序来讲,本地的 jvm 缓存优于集中式的 redis 缓存。
关系型数据库操作方便、易于维护且访问数据灵活,但是随着数据量的增加,其检索、更新的效率会越来越低。所以在高并发低延迟要求复杂的场景,要给数据库减负,减少其压力。
>>>> 给数据库减负
>>>> 缓存分布式,做多级缓存
1、读请求时写缓存
写缓存时一级一级写,先写本地缓存,再写集中式缓存。具体些缓存的方法可以有很多种,但是需要注意几项原则:
不要复制粘贴,避免重复代码
切忌和业务耦合太紧,不利于后期维护
开发初期刚刚上线阶段,为了排查问题,常常会给缓存设置开关,但是开关设置多了则会同时升高系统的复杂度,需要结合一套统一配置管理系统。
综上所述,高耦合带来的痛,弥补的代价是很大的,所以可以借鉴 Spring cache 来实现,实现也比较简单,使用时一个注解就搞定了。
2、写缓存失败了怎么办?应该先写缓存还是数据库呢?
既然是缓存的设计,那么策略一定是保证最终一致性,那么我们只需要采用异步消息来补偿就好了。
大部分缓存应用的场景是读写比差异很大的,读远大于写,在这种场景下,只需要以数据库为主,先写数据库,再写缓存就好了。
最后补充一点,数据库出现异常时,不要一股脑的 catch RuntimeException,而是把具体关心的异常往外抛,然后进行有针对性的异常处理。
3、关于其他性能方面
缓存设计都是占用越少越好,内存资源昂贵以及太大不好维护都驱使我们这样设计。所以要尽可能减少缓存不必要的数据,有的同学图省事把整个对象序列化存储。另外,序列化与反序列化也是消耗性能的。
>>>> vs各种缓存同步方案
缓存同步方案有很多种,在考虑一致性、数据库访问压力、实时性等方面做权衡。总的来说有以下几种方式:
1、懒加载式
如上段提到的方式,读时顺便加载。为了更新缓存数据,需要过期缓存。
优点:简单直接
缺点:
会造成一次缓存不命中
这样当用户并发很大时,恰好缓存中无数据,数据库承担瞬时流量过大会造成风险。
懒加载式太简单了,没有自动加载,异步刷新等机制,为了弥补其缺陷,请参见接下来的两种方法。
2、补充式
可以在缓存时,把过期时间等信息写到一个异步队列里,后台起个线程池定期扫描这个队列,在快过期时主动 reload 缓存,使得数据会一直保持在缓存中,如果缓存没有也没有必要去数据库查询了。常见的处理方式有使用 binlog 加工成消息供增量处理。
优点:刷新缓存变为异步的任务,对数据库的压力瞬间由于任务队列的介入而降低了,削平并发的波峰。
缺点:消息一旦积压会造成同步延迟,引入复杂度。
3、定时加载式
这就需要有个异步线程池定期把数据库的数据刷到集中式缓存,如 redis里。
优点:保证所有数据最小时间差同步到缓存中,延迟很低。
缺点:如补充式,需要一个任务调度框架,复杂度提升,且要保证任务的顺序。如果递进一步还想加载到本地缓存,就得本地应用自己起线程抓取,方案维护成本高。可以考虑使用 mq 或者其他异步任务调度框架。
ps:为了防止队列过大调度出现问题,处理完的数据要尽快结转,且要对积压数据以及写入情况做监控。
>>>> 防止缓存穿透
缓存穿透 是指查询的 key 压根不存在,从而缓存查询不到而查询了数据库。若是这样的 key 恰好并发请求很大,那么就会对数据库造成不必要的压力。怎么解决呢?
把所有存在的 key 都存到另外一个存储的Set集合里,查询时可以先查询key 是否存在。
干脆简单一些,给查询不到的 key 也加一个标识空值的 Value,这样就不会去查询数据库了,比如场景为查询省市区街道对应的移动营业厅,若是某街道确实没有移动营业厅,key 规则不变,value 可以设置为 "0" 等无意义的字符。当然此种方案要保证缓存集群的高可用。
这些 Key 可能不是永远不存在,所以需要根据业务场景来设置过期时间。
>>>> 热点缓存与缓存淘汰策略
有一些场景,需要只保持一部分的热点缓存,不需要全量缓存,比如热卖的商品信息,购买某类商品的热门商圈信息等等。
综合来讲,缓存过期的策略有以下三种:
1、FIFO(First In,First Out)
先进先出,淘汰最早进来的缓存数据,一个标准的队列。
以队列为基本数据结构,从队首进入新数据,从队尾淘汰。
2、LRU(Least RecentlyUsed)
最近最少使用,淘汰最近不使用的缓存数据。如果数据最近被访问过,则不淘汰。
和FIFO不同的是,需要对链表做基本模型,读写的时间复杂度是O(1),写入新数据进入头部,链表满了数据从尾部淘汰;
最近时间被访问的数据移动到头部,实现算法有很多,如hashmap+双向链表等等;
问题在于若是偶发性某些key被最近频繁访问,而非常态,则数据受到污染。
3、LFU(Least Frequently used)
最近使用次数最少的数据被淘汰,注意和 LRU 的区别在于 LRU 的淘汰规则是基于访问时间。
LFU中的每个数据块都有一个引用计数,数据块按照引用计数排序,若是恰好具有相同引用计数的数据块则按照时间排序;
因为新加入的数据访问次数为1,所以插入到队列尾部;
队列中的数据被新访问后,引用计数增加,队列重新排序;
当需要淘汰数据时,将已经排序的列表最后的数据块删除;
有很明显问题是若短时间内被频繁访问多次,比如访问异常或者循环没有控制住,而后很长时间未使用,则此数据会因为频率高而被错误的保留下来没有被淘汰。尤其对于新来的数据,由于其起始的次数是1,所以即便被正常使用也会因为比不过老的数据而被淘汰。所以维基百科说纯粹的LFU算法不经常单独使用而是组合在其他策略中使用。
>>>> 缓存使用的一些常见问题
Q:那么应该选择用本地缓存(local cache)还是集中式缓存(Cache cluster)呢?
A:首先看数据量,看缓存更新的成本,如果整体缓存数据量不是很大,而且变化的不频繁,那么建议本地缓存。
Q:怎么批量更新一批缓存数据?
A:依次从数据库读取,然后批量写入缓存,批量更新,设置版本过期key或者主动删除。
Q:如果不知道有哪些key怎么定期删除?
A:拿 redis 来说keys * 太损耗性能,不推荐。可以指定一个集合,把所有的key都存到这个集合里,然后对整个集合进行删除,这样便能完全清理了。
Q:一个key包含的集合很大,redis无法做到内存空间上的均匀Shard?
A:1、可以简单的设置key过期,这样就要允许有缓存不命中的情况;2、给key设置版本,比如为两天后的当前时间,然后读取缓存时用时间判断一下是否需要重新加载缓存,作为版本过期的策略。
转载自:京东技术。
投稿:有投稿意向技术人请在公众号对话框留言。
转载:意向文章下方留言。
更多精彩请关注 “数据和云” 公众号。
阅读原文:查看专业的数据库服务。
招聘专栏
Oracle 售前工程师(广州、深圳、上海、武汉、北京、石家庄)
Oracle 高级工程师(上海、深圳、北京、成都、昆明、贵州、西宁)
MySQL 技术经理(上海、南京、成都)
MySQL 工程师(上海、杭州)
超高待遇:丰厚的年终奖,五险一金,高额学习基金,团建旅游,法定节假日,福利假期等。
推荐他人成功入职有好礼(iPhone X)相送 。
投递简历至邮箱:hr@enmotech.com
资源下载
关注公众号:数据和云(OraNews)回复关键字获取
2018DTCC , 数据库大会PPT
2017DTC,2017 DTC 大会 PPT
DBALIFE ,“DBA 的一天”海报
DBA04 ,DBA 手记4 电子书
122ARCH ,Oracle 12.2体系结构图
2017OOW ,Oracle OpenWorld 资料
PRELECTION ,大讲堂讲师课程资料
近期文章
仅仅使用AWR做报告? 性能优化还未入门
实战课堂:一则CPU 100%的故障分析
杨廷琨:如何编写高效SQL(含PPT)
一份高达555页的技术PPT会是什么样子?
大象起舞:用PostgreSQL解海盗分金问题
ProxySQL!像C罗一样的强大
高手过招:用SQL解决环环相扣刑侦推理问题
多级缓存设计详解 | 给数据库减负,刻不容缓!相关推荐
- 京东java多级缓存_京东技术:多级缓存设计详解 | 给数据库减负
来这里找志同道合的小伙伴! 作 者 简 介 王梓晨 自古兵家多谋,<谋攻篇>,"故上兵伐谋,其次伐交,其次伐兵,其下攻城.攻城之法,为不得已",可见攻城之计有很多种,而 ...
- 京东java多级缓存_多级缓存设计详解 | 给数据库减负,刻不容缓!
来这里找志同道合的小伙伴! 作 者 简 介 王梓晨 自古兵家多谋,<谋攻篇>,"故上兵伐谋,其次伐交,其次伐兵,其下攻城.攻城之法,为不得已",可见攻城之计有很多种,而 ...
- hbase 二进制数据写入_分布式数据库HBase的架构设计详解(有彩蛋)
原标题:分布式数据库HBase的架构设计详解(有彩蛋) 本文根据DBAplus社群第99期线上分享整理而成,文末还有好书送哦~ 讲师介绍 陈鸿威 云财经大数据CTO 曾任百度高级工程师,现主持设计开发 ...
- Java开源生鲜电商平台-Java分布式以及负载均衡架构与设计详解(源码可下载)
Java开源生鲜电商平台-Java分布式以及负载均衡架构与设计详解(源码可下载) 说明:主要是针对一些中大型的项目需要进行分布式以及负载均衡的架构提一些思路与建议. 面对大量用户访问.高并发请求,海量 ...
- 架构设计-支付宝、京东、美团、去哪儿的支付系统架构整体设计详解!!!
架构设计-支付宝.京东.美团.去哪儿的支付系统架构整体设计详解!!! 支付产品模块是按照支付场景来为业务方提供支付服务.这个模块一般位于支付网关之后,支付渠道之前. 它根据支付能力将不同的支付渠道封装 ...
- 聊聊微服务架构中的多级缓存设计
大家好,我是不才陈某~ 今天我们来聊聊缓存这个话题,看看在微服务环境下如何设计有效的多级缓存架构.主要涉及三方面内容: Web 应用的客户端缓存: 应用层静态资源缓存: 服务层多级缓存. 首先,咱们先 ...
- HTTP缓存机制详解
HTTP缓存机制详解 一. 前言 二. 缓存的介绍 什么是缓存? 为什么要使用缓存? 1. 减少冗余的数据传输 2. 缓解带宽瓶颈 3. 破坏瞬间拥塞 4. 降低距离时延 三. 缓存有效性 命中和未命 ...
- redis缓存雪崩详解
缓存雪崩详解: 情景一:在没有缓存服务器的情况下,用户发起请求时,服务器直接向数据库请求数据,数据库直接返回数据给服务器. 情景二:当有redis缓存服务器时,用户发起请求时,服务器会先对redis ...
- 【MyBatis】MyBatis 二级缓存全详解
1.概述 转载:MyBatis 二级缓存全详解 上一篇文章中我们介绍到了 MyBatis 一级缓存其实就是 SqlSession 级别的缓存,什么是 SqlSession 级别的缓存呢?一级缓存的本质 ...
最新文章
- 再谈变分自编码器(VAE):估计样本概率密度
- MySQL高级 - 查询缓存 - 开启查询缓存
- 红帽子linux安装ftp,Linux 安装 vsftpd ftp软件包
- 瞒不住了,难怪.NET进大厂这么难!
- 工作243:name报错
- 谷歌将停止对32位Linux系统Chrome浏览器支持
- web安全day28:一文读懂Linux日志,运维工程师必备
- PS批量制作获奖证书并导出PNG
- FatFs- 通用FAT文件系统模块
- 新浪OAuth客户端登陆另辟蹊径
- PPT 不支持打开显示 webp 图片
- EpiQuik病毒RNA提取试剂盒,快速、简单、经济有效
- java基础--内存
- linux系统编程3—文件存储函数
- python自动登录并提交表单_用python模拟登录(解析cookie + 解析html + 表单提交 + 验证码识别 + excel读写 + 发送邮件)...
- 最佳论文!商汤提出手机端实时单目三维重建系统 | ISMAR 2020
- 数学建模:整数规划示例模型 (Python 求解)
- 微博短链接生成 php,新浪微博API生成短链接
- ASUS eeepc-1005HA安装archlinux后耳机无声解决方案
- 买定离手!AI预测英雄联盟S12冠军;微软使用AI提高农业生产效率;编程语言的自动生成;机器学习核方法入门·电子书;前沿论文 | ShowMeAI资讯日报
热门文章
- ffmpeg开源工具的使用_如何使用开源工具和最佳实践提高在线隐私
- Hoodie旨在成为开源最多样化和包容性社区之一
- moodle 用户 权限_用户和社区反馈如何驱动Moodle
- 文末送书 | WAF 那些事
- CSS3 响应式布局之弹性网格
- CSS 浮动 float属性
- 飞利浦css6530b评测,带多种输入模式 无线接收器很方便_飞利浦 CSS6530B/93_音频评测-中关村在线...
- python数据分类聚类案例_Python实现的KMeans聚类算法实例分析
- 【CSS】CSS 的优先级总结
- wordpress如何使用vim和markdown写blog