前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >缓存和数据库不一致分析及解决方案及多维度化

缓存和数据库不一致分析及解决方案及多维度化

作者头像
丁D
发布2022-08-12 21:48:08
3490
发布2022-08-12 21:48:08
举报
文章被收录于专栏:老铁丁D老铁丁D

删除缓存还是更新缓存

我们存入缓存的数据,往往是经过一系列的计算才放如缓存的,而不是从数据库直接读取出来,放入缓存;所以更新缓存的代价往往会比较大。 例如:一分钟内可能修改一个字段100次,然后要将相关缓存的数据计算出来,还要查询其他的字段进行计算,然而这个缓存在1分钟内只被读一次,所以如果这时候更新缓存代价就会比较大,而删除删除的代价就小很多。 业界上大部分是删除缓存,而不是更新缓存

为什么缓存和数据库会不一致?

场景1:先更新数据库,再删除缓存 假设先更新数据库成功,删除缓存失败,这时候数据库和缓存就不一致了。 所以先删除缓存,再更新数据库 假设删除缓存成功,更新数据库失败,这个时候,数据是一致的。因为缓存空会去数据库读取。

场景2:先删除缓存,再更新数据库,并读取数据 我们知道删除缓存和更新数据库是两个操作,假设有这么一种情况,我删除缓存了。然后正要去更新数据库的时候但是还没更新,这个时候来了一个读取请求,并且抢到了cpu。读请求发现缓存为空,会去数据库读取,并存入缓存,,,这个时候才更新数据库,这样就会导致缓存和数据库不一致。

当然在并发很低的情况下,出现这个问题的概率会比较低,但是在并发很高的情况下,很容易就出现这个问题的。。

解决方案:删除缓存,更新数据库,读取数据异步串行化

https://zhuanlan.zhihu.com/p/77587581

异步串行化

当我们要更新数据库数据的时候将数据的唯一标识(比如修改库存,商品id/sku)放入一个jvm的内存队列中。

当我们读取请求过来的时候,如果缓存有数据,直接返回。如果没有数据,就要去读取数据库+更新缓存,这个时候也将唯一标识放在jvm的内存队列中

注意同一个标识要路由到同一个队列,并且一个队列只能由一个线程进行消费;;这种方案类似rockermq的顺序消费

由于队列是先进先出的,这个的话更新数据库操作(删除缓存+更新数据库)就会先于读取请求(读取数据+更新缓存)执行。

优化点:当队列中有一个读请求的时候(读取数据+更新缓存),这个没必要放入更多的读请求了到jvm内存队列中。之后的读请求可以使用不断的轮询去读取缓存,等待jvm的那个读请求更新缓存就行。。 当轮询等待的时候过长(200ms)可以直接读取数据库的数据并返回。

注意:队列中可能会堆积多个更新数据库的操作(同一数据),导致读取请求轮询超时直接读取数据库(所以要更新数据频繁的情景会怎么样)。

队列中堆积的更新操作可能是针对不同的数据项的,所以,要设当的扩大队列来分摊更新操作。

比如:如果一个内存队列里居然会挤压100个商品的库存修改操作,每隔库存修改操作要耗费10ms区完成,那么最后一个商品的读请求,可能等待10 * 100 = 1000ms = 1s后,才能得到数据

其实根据之前的项目经验,一般来说数据的写频率是很低的,因此实际上正常来说,在队列中积压的更新操作应该是很少的 针对读高并发,读缓存架构的项目,一般写请求相对读来说,是非常非常少的,每秒的QPS能到几百就不错了 一秒,500的写操作,5份,每200ms,就100个写操作

单机器,20个内存队列,每个内存队列,可能就积压5个写操作,每个写操作性能测试后,一般在20ms左右就完成 那么针对每个内存队列中的数据的读请求,也就最多hang一会儿,200ms以内肯定能返回了

写QPS扩大10倍,但是经过刚才的测算,就知道,单机支撑写QPS几百没问题,那么就扩容机器,扩容10倍的机器,10台机器,每个机器20个队列,200个队列

注意:对同一个商品的更新和读取,要路由到同一台机器;; 比如,写操作路由到机器1,读操作路由到机器2,那这样还讲什么串行话,就gg了。所以要路由到同一个机器。(nginx的hash算法)

这样又会导致另一种场景,热点商品的读取频率会比较高,会导致的服务器的压力大,因为某一个热点商品的读请求,会打到同一个服务器上面。造成某台服务器压力大。。。

全量更新

我们都知道redis的性能跟存入的value的大小有很大的关系。。。当我们存入的value很大这样会导致redis的性能急剧下降。

当我们存入的redis的数据是商品详情页数据(商品基本信息,商品分类信息,商品店铺信息 )混在一起会导致redis的value很大。。。这样当我们只想修改商品的颜色这个小小的基本信息。。。就需要将分类及店铺都拿出来在set进去。。这样读取的数据都非常大。。导致性能很低

我们可以分维度存在redis 比如商品基本信息对应一个key。。商品分类信息对应一个key。。商品店铺信息对应一个key。。分成3个维护存储、、只想修改基本信息,就拿基本信息来修改。。。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-06-03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 删除缓存还是更新缓存
  • 为什么缓存和数据库会不一致?
  • 异步串行化
  • 全量更新
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档