4种常见的缓存问题及解决方案详解

前言
使用缓存可以缓解大流量压力,显著提高程序的性能。我们在使用缓存系统时,尤其是大并发情况下,经常会遇到一些“疑难杂症”。本文总结了一些使用缓存时常见的问题及解决方案,以后在遇到这类问题时可以作为参考,在设计缓存系统的时候也应该考虑这些常见的情况。
为了表述方便,本文以数据库查询缓存为例,使用缓存可以减小对数据库的压力。
分享图片
缓存穿透
我们在使用缓存时,往往先尝试去缓存中取值,如果没有,再去数据库取值,如果数据库也没有值,则根据业务需求,返回空或者抛异常。
如果用户一直访问一个数据库不存在的数据,比如id为-1的数据,就会导致每次请求都会先去缓存查一次,然后再去数据库查一次,造成严重的性能问题。这种情况就叫缓存穿透。
解决方案
以下几种解决方案:
  • 对请求参数做校验,比如用户鉴权校验,id做基础校验,id <= 0的直接拦截。
  • 如果查询到数据库没有值,也将对应的key存进缓存中,value为null。这样下次查询就直接从缓存返回了。但这里的key的缓存时间应该比较短,比如30s。防止后面在数据库插入了这条数据,而用户获取不到。
  • 使用布隆过滤器,判断一个key是否已经查过了,如果已经查过了,就不去数据库查询。
分享图片
缓存击穿
缓存击穿指的是,一个key的访问量非常大,比如某秒杀活动,有1w/s的并发量。这个key在某一时刻过期,那这些大量的请求就会一瞬间到数据库,数据库可能会直接崩溃。
解决方案
缓存击穿的解决方案也有几种,可以配合使用:
  • 对于热点数据,慎重考虑过期时间,确保热点期间key不会过期,甚至有些可以设置永不过期。
  • 使用互斥锁(比如Java的多线程锁机制),第一个线程访问key的时候就锁住,等查询数据库返回后,把值插入到缓存后再释放锁,这样后面的请求就可以直接取缓存里面的数据了。
缓存雪崩
缓存雪崩指的是,在某一时刻,多个key失效。这样就会有大量的请求从缓存中获取不到值,全部到数据库。还有另一种情况,就是缓存服务器宕机,也算做缓存雪崩。
解决方案
针对上述两种情况,缓存雪崩有两种解决方案:
  • 对每个key的过期时间设置一个随机值,而不是所有key都相同。
  • 使用高可用的分布式缓存集群,确保缓存的高可用性,比如redis-cluster。
分享图片
双写不一致
在使用数据库缓存的时候,读和写的流程往往是这样的:
  • 读取的时候,先读取缓存,如果缓存中没有,就直接从数据库中读取,然后取出数据后放入缓存
  • 更新的时候,先删除缓存,再更新数据库
所谓双写不一致,就是在发生写操作(更新)的时候或写操作之后,可能会存在数据库里面的值和缓存中的值不同的情况。
为什么更新的时候要先删除缓存,再更新数据库?因为如果先更新数据库,然后在删除缓存的时候失败了,就会造成缓存里面的值和数据库的值不一致。
然而这样并不能完全避免双写不一致问题。假设在大并发情景下,一个线程先删除缓存,然后取更新数据库,这个时候另一个线程去取缓存,发现没有值,于是去读数据库,然后把数据库旧的值设置进缓存。等第一个线程更新完数据库后,数据库里面就是新的值,而缓存里面是旧的值,所以就存在了数据不一致的问题。
一个比较简单的解决办法是把过期时间设置得比较低,这样就只有在缓存没过期之前存在数据不一致问题,在一些业务场景下也还能接受。
另一种解决方案是使用队列辅助。先更新数据库,再删除缓存。如果删除失败,就放进队列。然后另一个任务从队列中取出消息,不断去重试删除相应的key。
还有一种解决方案是使用对一个数据使用一个队列,使读写操作串行化。比如对id为n的数据建立一个队列。对这条数据的写操作,删除缓存后,放进一个队列;然后另一个线程过来了,发现没有缓存,则把这个读操作也放进这个队列里面。
不过这样会增加程序的复杂性,串行化也会降低程序的吞吐量,可能得不偿失。一般主流的解决方案还是先删除缓存,再更新数据库。可以满足绝大部分需求。
最后
欢迎大家关注我的公众号【程序员追风】,文章都会在里面更新,整理的资料也会放在里面。
相关文章
相关标签/搜索
香港最准一肖中特公开选料1 宜都市| 浦北县| 龙江县| 虎林市| 大连市| 淮安市| 洛南县| 尤溪县| 溆浦县| 武胜县| 汶上县| 宣化县| 通山县| 高碑店市| 阜城县| 德昌县| 宁陕县| 土默特右旗| 潞西市| 贡觉县| 宜宾市| 团风县| 拜泉县| 新源县| 社旗县| 福州市| 怀来县| 平果县| 滦平县| 孝义市| 金华市| 长汀县| 康平县| 孟津县| 海伦市| 永嘉县| 和顺县| 郴州市| 库车县| 济南市| 文水县| 曲阜市| 西乌珠穆沁旗| 海林市| 淅川县| 南木林县| 瑞昌市| 东明县| 克什克腾旗| 启东市| 华阴市| 乳山市| 肃北| 桐乡市| 聂荣县| 长垣县| 体育| 太康县| 重庆市| 子长县| 合阳县| 宜君县| 六枝特区| 大石桥市| 张家界市| 桑日县| 马鞍山市| 鹤壁市| 体育| 渝北区| 卢龙县| 龙里县| 芷江| 留坝县| 库车县| 昌都县| 黑龙江省| 广宁县| 合江县| 广饶县| 灯塔市| 祥云县| 义马市| 怀安县| 汉川市| 山阳县| 察哈| 西安市| 临洮县| 河曲县| 清水河县| 罗定市| 蚌埠市| 遂昌县| 商南县| 尉氏县| 云林县| 龙川县| 富川| 安顺市| 富源县| 水城县| 娱乐| 琼海市| 英德市| 绩溪县| 二连浩特市| 舒兰市| 小金县| 固阳县| 定日县| 上饶市| 兴业县| 东乌| 迁安市| 大连市| 龙井市| 随州市| 全州县| 兴山县| 沂水县| 南昌市| 河东区| 白水县| 无锡市| 武陟县| 高邑县| 宣武区| 井陉县| 寿阳县| 桓台县| 繁昌县| 孙吴县| 化德县| 广河县| 龙胜| 公主岭市| 江永县| 黔南| 浑源县| 温州市| 保康县| 德江县| 阿克陶县| 西乌| 河南省| 六枝特区| 利津县| 新昌县| 五寨县| 布拖县| 漯河市| 闻喜县| 越西县| 静海县| 夏津县| 道孚县| 休宁县| 石屏县| 河北区| 黔东| 奉新县| 赣州市| 兖州市| 云和县| 宁晋县| 阳西县| 营口市| 板桥市| 高安市| 黄大仙区| 辽宁省| 芦山县| 正蓝旗| 柳林县| 濉溪县| 仙桃市| 恩平市| 阳江市| 东山县| 伊春市| 平乡县| 文昌市| 大田县| 六盘水市| 岳普湖县| 阿坝| 林芝县| 安西县| 集安市| 阜宁县| 东山县| 金溪县| 平顶山市| 湘西| 宁阳县| 洪洞县| 乡城县| 门头沟区| 无极县| 安陆市| 正宁县| 伊金霍洛旗| 东兰县| 股票| 西林县| 祁阳县| 铅山县| 集安市| 墨玉县| 弥勒县| 昭平县| 南召县| 通州区| 嘉定区| 乌兰县| 大连市| 漠河县| 临邑县| 安多县| 琼中| 桃江县| 闸北区| 镇赉县| 界首市| 汾西县| 水城县| 白城市| 思茅市| 洮南市| 白山市| 蓬莱市| 革吉县| 同德县| 怀安县| 威宁| 麟游县| 尚义县| 资讯| 闻喜县| 新丰县| 兴宁市| 九江市| 香港| 梁山县| 无极县| 瑞丽市| 本溪市| 滁州市| 金阳县| 合山市| 华池县| 台东市| 交城县| 兖州市| 屏东县| 阿巴嘎旗| 新龙县| 峡江县| 唐山市| 昌邑市| 稷山县| 余干县| 犍为县| 萨迦县| 津南区| 白山市| 大余县| 宁远县| 南漳县| 泗阳县| 曲阳县| 西乡县| 宜春市| 健康| 通州区| 江永县| 卢龙县| 新泰市| 岑巩县| 六盘水市| 弥渡县| 天峻县| 巧家县| 西充县| 噶尔县| 阿坝| 肇东市| 屯留县| 祥云县| 肇州县| 隆子县| 新巴尔虎左旗| 江安县| 贵南县| 巍山| 德阳市| 油尖旺区| 安塞县| 清水河县| 富宁县| 崇左市| 南城县| SHOW| 漠河县| 射阳县| 铜山县| 乡城县| 南京市| 紫阳县| 孙吴县| 岳阳县| 西宁市| 民丰县| 博湖县| 林芝县| 米易县| 綦江县| 潢川县| 商水县| 乌兰浩特市| 桃园县| 清丰县| 资讯| 昌吉市| 曲沃县| 大关县| 马山县| 罗甸县| 贞丰县| 博罗县| 上饶县| 乌兰察布市| 诏安县| 容城县| 花莲县| 安阳县| 盘锦市| 文登市| 贺兰县| 克山县| 寿宁县| 团风县| 武陟县| 武宣县| 岑巩县| 全州县| 诸城市| 冷水江市| 泊头市| 新宁县| 上虞市| 麻栗坡县| 盘锦市| 巧家县| 辽中县| 萍乡市| 遂溪县| 锦屏县| 平罗县| 尉犁县| 喀什市| 城口县| 岑溪市| 嵊州市| 泽普县| 施秉县| 铁力市| 鸡泽县| 南丰县| 涿州市| 藁城市| 龙门县| 富源县| 仁怀市| 温宿县| 固原市| 双桥区| 鲁山县| 昌邑市| 常宁市| 陈巴尔虎旗| 司法| 淮北市| 邯郸市| 萝北县| 龙门县| 巴马| 宜宾市| 米易县| 德令哈市| 石嘴山市| 新竹县| 通江县| 桂林市| 蓝田县| 泗水县| 新绛县| 团风县| 吐鲁番市| 洪江市| 岫岩| 读书| 永登县| 西华县| 石阡县| 什邡市| 枣阳市| 江陵县| 万年县| 大洼县| 维西| 扶沟县| 抚松县| 德格县| 西乌珠穆沁旗| 屯门区| 连平县| 永宁县| 定南县| 阳江市| 乐亭县| 金湖县| 崇阳县| 广南县| 乌什县| 谢通门县| 通海县| 亚东县| 湘潭市| 桓仁| 光泽县| 柏乡县| 鄱阳县| 和田县| 丹东市| 博爱县| 临桂县| 岗巴县| 临洮县| 张家界市| 焦作市| 鹤峰县| 抚州市| 上虞市| 泸定县| 邳州市| 全州县| 新乐市| 新邵县| 无极县| 桦南县| 博爱县| 荔浦县| 攀枝花市| 晋宁县| 乐都县| 西贡区| 广河县| 九龙坡区| 惠州市| 芜湖市| 白河县| 晋江市| 麻栗坡县| 金山区| 安阳市| 柞水县| 朝阳市| 咸丰县| 炉霍县| 荔波县| 连州市| 苍南县| 尉犁县| 伊通| 龙门县| 瑞昌市| 潞西市| 武城县| 察雅县| 文昌市| 杂多县| 喀喇| 志丹县| 大田县| 金湖县| 宁阳县| 砀山县| 隆尧县| 福贡县| 临沭县| 济源市| 怀来县| 太仓市| 洛隆县| 绩溪县| 汉中市| 中西区| 阳东县| 通道| 台中市| 玉田县| 策勒县| 兰州市| 天镇县| 竹北市| 商洛市| 安阳市| SHOW| http://www.yqo3j6rl3v.fun http://wap.gz1980targetc.fun http://m.yqo7j8rl3v.fun http://wap.gz1980creditc.fun http://wap.bo2020cocks.fun http://wap.yqo2j2rl2v.fun http://www.gz1980wearc.fun http://www.bo2020earths.fun http://wap.bo2020notifys.fun http://m.yqo9j8rl0v.fun http://www.gz1980fuckc.fun http://wap.gz1980zissc.fun http://m.bo2020indexs.fun http://www.yqo4j1rl4v.fun http://wap.yqo8j1rl7v.fun