百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

有关 Redis 缓存的一些应用场景及踩过的坑

mhr18 2024-11-05 10:22 27 浏览 0 评论

在上家公司用到 Redis 作为缓存的场景比较多,常用的数据结构除了 Hash 其他均有用到,总结下当时部分业务场景的实现方案以及上线之后遇到的问题。

二、业务场景

如上图所示,这是个游戏评论页,整个页面的数据按照某些维度分开存储在 Redis 中,在返回 APP 端数据时拼装到一起。着重介绍一下「游戏评分」及「游戏评论」这两个典型案例。

2.1 游戏评分

要求:

  • 评分后实时展示最终结果

2.2 游戏评论(含回复)

要求:

  • 用缓存实现评论的 CRUD 功能,最大限度的减少数据库压力

三、实现方案

3.1 游戏评分

最终方案:

将评论中的评分累加得到一个总分及总评论数,放入 Redis 中,总分除以总评论数即得到平均评分,此后用户评论实时操作 Redis 中的值。

3.2 游戏评论(含回复)

注意点:

  • 冷热数据(通常只有前几页的访问频率较高)
  • 排序(点赞、头衔、回复等因素影响排序)
  • 数据写入方式(实时 or 定时)

如上图所示,分别有三种 Redis 缓存的设计方案,从左到右逐步优化。

最终方案:

首次进入页面只加载前 50 条热点数据,同时将评论ID 及具体的评论内容分开存储到 Redis 中。评论ID 用 Zset 存储,评论内容用 String 或者 Hash 存储。这样做的好处是删除或修改某个热点评论时,能最大限度的减少影响的数据,只需要从 Zset 中删除一个 id,或者修改对应的评论内容缓存即可。排序通过 Zset 中的 score 属性实现。

下面用时序图的方式介绍 CRUD 的流程:

① 获取评论列表

sequenceDiagram
title: 获取评论列表流程
participant user as 用户
participant hero as 服务端
user->>hero: 用户进入评论列表页
hero->>hero: 从数据库中查询前 50 条热点数据
hero->>hero: 将 50 个评论ID 放入 Zset 中,评论内容用单独 key 存储
hero->>hero: 根据页码计算偏移量,用 zrevrang 方法获取当前页评论ID 列表
hero->>hero: 如果偏移量大于 50 则继续从数据库中查询并追加到 Zset 中
hero->>hero: 拼装点赞数、回复数等附加数据
hero-->>user: 返回评论列表

② 添加评论(影响评分)

sequenceDiagram
title: 添加评论流程
participant user as 用户
participant hero as 服务端
participant timer as 定时器
user->>hero: 用户发表评论
hero->>hero: 查询数据库中最大的评论ID 并放入 Redis 中
hero->>hero: 缓存的最大评论ID + 1
hero->>hero: 拼装评论内容并放入 Redis 中
hero->>hero: 将评论ID 添加到热点评论ID 缓存列表中
note over hero: 实时变动游戏评分
hero->>hero: 相应评分数 + 1
hero->>hero: 总评论数 + 1 且总评分累加
hero-->>user: 返回评论成功
note over timer: 每隔半小时
note over timer: 数据库回写
timer->>timer: 回写在「数据库最大评论ID 及 Redis 最大评论ID」 区间内的数据

③ 删除评论(不影响评分)

sequenceDiagram
title: 删除评论流程
participant user as 用户
participant hero as 服务端
user->>hero: 用户删除评论
hero->>hero: 根据评论ID 查询数据库是否存在
hero->>hero: 存在则逻辑删除数据库中的数据
hero->>hero: 删除 Zset 中相应的元素
hero->>hero: 删除对应的评论内容缓存
hero->>hero: 删除对应的评论回复
hero->>hero: 总评论数 - 1
hero-->>user: 返回删除成功

四、线上遇到的问题

4.1 我下载的、我试玩的、我喜欢的、我点评的列表数据经常变为 1 条,与个人主页的统计数不符

原因:列表缓存 10 分钟,有序集合类型,通过 zadd 命令追加数据,而缓存失效后如果用户点下载或者试玩,zadd 命令会自动创建一个空的列表,并将刚操作的游戏ID加入,导致列表只有一条数据。

解决方法:在追加数据前先判断缓存是否存在,不存在则从数据库加载并放入 Redis,之后再通过 zadd 命令往里追加。

4.2 腾讯视频人气从几百万突然变为几百,此前几天无异常

原因:人气、点赞等数据缓存时间为一周,失效后通过 incr 命令会自动创建 key 并从 0 开始累加。

解决方法:累加前先判断缓存是否存在,不存在则从数据库加载并放入 Redis,之后再通过 incr 命令累加。

4.3 某个用户下拉游戏推荐列表到第 14 页时无返回数据

原因:该用户下拉到第 13 页后,过了将近 20 分钟后才继续下拉到第 14 页,此时 Redis 中游戏推荐列表的缓存已失效,重新加载是默认加载前50条,而第 14 页是需要 131~140 的数据,故而找不到对应的下标则返回空列表。

解决方法:适当延长缓存时间规避这种情况,当然这并不能百分百解决。

4.4 判断当前用户是否点赞「点赞数为 0」的评论或者回复时每次都要查询数据库

原因:点赞记录会加载进 Redis 缓存中,如果点赞数为 0 则代表没点赞记录也就是没缓存,进而导致每次都发生缓存穿透。

解决方法:缓存中设置一条默认的点赞记录。

五、结语

以上就是在上家公司涉及到 Redis 缓存比较典型的业务场景,方案也是当时设计的,可能并非最优方案,如有问题欢迎探讨。

获取资料:

本次给大家分享一些学习资料,里面包括:(高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)以及Java进阶学习路线图。

领取方式:加微信号:weixin99ting 免费获取!

相关推荐

Java面试宝典之问答系列(java面试回答)

以下内容,由兆隆IT云学院就业部根据多年成功就业服务经验提供:1.写出从数据库表Custom中查询No、Name、Num1、Num2并将Name以姓名显示、计算出的和以总和显示的SQL。SELECT...

ADG (Active Data Guard) 数据容灾架构下,如何配置 Druid 连接池?

如上图的数据容灾架构下,上层应用如果使用Druid连接池,应该如何配置,才能在数据库集群节点切换甚至主备数据中心站点切换的情况下,上层应用不需要变动(无需修改配置也无需重启);即数据库节点宕机/...

SpringBoot多数据源dynamic-datasource快速入门

一、简介dynamic-datasourc是一个基于SpringBoot的快速集成多数据源的启动器,其主要特性如下:支持数据源分组,适用于多种场景纯粹多库读写分离一主多从混合模式。支持...

SpringBoot项目快速开发框架JeecgBoot——项目简介及系统架构!

项目简介及系统架构JeecgBoot是一款基于SpringBoot的开发平台,它采用前后端分离架构,集成的框架有SpringBoot2.x、SpringCloud、AntDesignof...

常见文件系统格式有哪些(文件系统类型有哪几种)

PART.01常见文件系统格式有哪些常见的文件系统格式有很多,通常根据使用场景(Windows、Linux、macOS、移动设备、U盘、硬盘等)有所不同。以下是一些主流和常见的文件系统格式及其特点:一...

Oracle MySQL Operator部署集群(oracle mysql group by)

以下是使用OracleMySQLOperator部署MySQL集群的完整流程及关键注意事项:一、部署前准备安装MySQLOperator通过Helm安装Operator到Ku...

LibreOffice加入"转向Linux"运动

LibreOffice项目正准备削减部分Windows支持,并鼓励用户切换到Linux系统。自Oracle放弃OpenOffice后,支持和指导LibreOffice开发的文档基金会对未来有着明确的观...

Oracle Linux 10发布:UEK 8.1、后量子加密、增强开发工具等

IT之家6月28日消息,科技媒体linuxiac昨日(6月27日)发布博文,报道称OracleLinux10正式发布,完全二进制兼容(binarycompatibility...

【mykit-data】 数据库同步工具(数据库同步工具 开源)

项目介绍支持插件化、可视化的数据异构中间件,支持的数据异构方式如下MySQL<——>MySQL(增量、全量)MySQL<——>Oracle(增量、全量)Oracle...

oracle关于xml的解析(oracle读取xml节点的属性值)

有时需要在存储过程中处理xml,oracle提供了相应的函数来进行处理,xmltype以及相关的函数。废话少说,上代码:selectxmltype(SIConfirmOutput).extract...

如何利用DBSync实现数据库同步(通过dblink同步数据库)

DBSync是一款通用型的数据库同步软件,能侦测数据表之间的差异,能实时同步差异数据,从而使双方始终保持一致。支持各种数据库,支持异构同步、增量同步,且提供永久免费版。本文介绍其功能特点及大致用法,供...

MYSQL存储引擎InnoDB(八十):InnoDB静态数据加密

InnoDB支持独立表空间、通用表空间、mysql系统表空间、重做日志和撤消日志的静态数据加密。从MySQL8.0.16开始,还支持为模式和通用表空间设置加密默认值,这允许DBA控制在这些模...

JDK高版本特性总结与ZGC实践(jdk高版本兼容低版本吗)

美团信息安全技术团队核心服务升级JDK17后,性能与稳定性大幅提升,机器成本降低了10%。高版本JDK与ZGC技术令人惊艳,且JavaAISDK最低支持JDK17。本文总结了JDK17的主要...

4 种 MySQL 同步 ES 方案,yyds!(两个mysql数据库自动同步的方法)

本文会先讲述数据同步的4种方案,并给出常用数据迁移工具,干货满满!不BB,上文章目录:1.前言在实际项目开发中,我们经常将MySQL作为业务数据库,ES作为查询数据库,用来实现读写分离,...

计算机Java培训课程包含哪些内容?其实就这六大块

不知不觉秋天已至,如果你还处于就业迷茫期,不如来学习Java。对于非科班小白来说,Java培训会更适合你。提前了解下计算机Java培训课程内容,会有助于你后续学习。下面,我就从六个部分为大家详细介绍...

取消回复欢迎 发表评论: