【面试深度解析】滴滴后端二面:12306场景设计、Redis缓存设计、MyBatis两级缓存(下)

news2025/4/20 11:29:17

欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!

在我后台回复 「资料」 可领取编程高频电子书
在我后台回复「面试」可领取硬核面试笔记

文章导读地址:点击查看文章导读!

感谢你的关注!

前言:
🚀 春招季即将来临,你准备好迎接挑战了吗? 🌟

🎯 【30天面试冲刺计划】 —— 专为大厂面试量身定制!

🔥 跟随学习,一起解锁面试新高度! 🔥

在这里插入图片描述

文章目录

  • 滴滴后端二面:12306场景设计、Redis缓存设计、MyBatis两级缓存(下)
    • 题目分析
      • 5、坐过高铁吧,有抢过票吗?你说说抢票会有哪些情况?
      • 6、现在我们来给 12306 抢票系统设计一个缓存,kv 存什么?
      • 7、那对于数据不一致我们一般怎么处理?

滴滴后端二面:12306场景设计、Redis缓存设计、MyBatis两级缓存(下)

题目分析

5、坐过高铁吧,有抢过票吗?你说说抢票会有哪些情况?

抢票会存在线程安全的问题,因为高铁票是作为一个共享的数据存在,多个线程去读写共享的数据,就会存现线程安全的问题

具体的线程不安全问题就是:高铁票的 少卖超卖

先说一下整个抢票中所涉及的流程:生成订单、扣减库存、用户支付

那么为了保证高并发,扣减库存的操作可以放在本地去做,生成订单的操作通过异步,可以大幅提高系统并发度

接下来先说一下如何 优化抢票性能

将库存放在每台机器的本地,比如总共有 1w 个余票库存,共有 100 台机器,那么就在每台机器上方 100 个库存

当用户抢票之后,就会在本地先扣减库存,如果本地库存不足,此时可以给用户返回一个友好提示,让用户稍后再重试抢票,再将用户抢票的请求路由到其他有库存的机器上去

如果本地库存足够的话,就先扣除本地库存,之后再发送一个 MQ 消息异步的生成高铁票的订单,等待用户支付,如果用户十分钟内不支付的话,订单就失效,返还库存

接下来分析一下上边的流程是否会出现少卖和超卖的问题:

对于超卖来说,每次用户请求时,先扣除库存,再去生成订单,这样当库存不足时,就不会再生成订单了,因此肯定不会出现超卖的问题

对于少卖来说,总共有 100 台机器,每台机器有 100 个库存,如果其中的几台机器宕机了,那么宕机的机器上的库存就没办法继续售卖,就会出现少卖的问题

解决少卖问题:

可以在每台机器上放一些冗余的库存,如果其他机器发生了宕机,就将宕机的机器上的库存给放到健康的机器上去,就可以避免机器宕机而导致一部分库存卖不出去的问题了

那么这样的话,就需要使用 Redis 来统一管理每台机器上的库存,也就是在分布式缓存 Redis 中存储一份缓存,在每台机器的本地也存储一份缓存,当扣减完机器本地的库存之后,再去发送一个远程请求扣减 Redis 上的库存

最后完整的抢票流程:

在这里插入图片描述

  1. 用户发出抢票请求,在本地进行扣减库存操作
  2. 如果本地库存不足,返回用户友好提示,可以稍后重试,如果所有机器上的库存都不足的话,可以直接返回用户已售罄的提示
  3. 如果本地库存充足,在本地扣减库存之后,再向 Redis 中发送网络请求,进行库存扣减(这里 Redis 的作用就是统一管理所有机器上的库存数量)
  4. 扣减库存之后,再发送 MQ 消息,异步的生成订单,之后等待用户支付即可

如有不足,欢迎指出

6、现在我们来给 12306 抢票系统设计一个缓存,kv 存什么?

在回答的时候,要先给面试官分析一下业务场景,再说怎么去设计缓存

在 12306 中如果要设计缓存的话,可以考虑给余票设计一个缓存,因为余票信息是读取比较多的数据,并且在首页,放在缓存中可以大大加快用户查询的速度,如下图

在这里插入图片描述

  • 余票信息缓存

余票信息缓存的话,将车站到车站之间的信息以及余票信息给存储到缓存中,比如当用户查询 A 车站到 B 车站的车票信息时,直接从缓存中获取,如果缓存中没有的话,去数据库中查询,并且在 Redis 缓存中构建一份缓存数据

key 设计为站点的信息,比如查询 2023 年 12 月 15 日 A 车站到 B 车站的车票信息:remaining_ticket_info:{year}:{month}:{day}:{起使车站}:{终止车站}

value 为起使车站到终止车站的信息,比如车次号、余票信息、票价信息、经过车站等一些信息

这里我觉得余票数量可以和其他缓存给分开存储,因为像余票信息的话,用户购买后是需要修改的,如果将余票数量和其他缓存数据放在一起的话,每次修改的时候,都要重新构建很多数据,比较麻烦

  • 余票数量缓存

余票数量缓存的 key 设计为:remaining_ticket_num:{year}:{month}:{day}:{起使车站}:{终止车站}

value :存储余票的数量

在这里插入图片描述

扩展:MyBatis 两级缓存

这里既然说了 Redis 缓存了,就再扩展说一下 MyBatis 的两级缓存吧

MyBatis 设计了两级缓存用于提升数据的检索效率,避免每次数据的访问都需要去查询数据库

MyBatis 一级缓存:

MyBatis 中的一级缓存是会话(SqlSession)级别的,也叫本地缓存,每个用户在执行查询的时候都需要使用 SqlSession 来执行查询语句,MyBatis 将查询出来的数据缓存到 SqlSession 的本地缓存中,避免每次查询都去操作数据库

MyBatis 默认开启一级缓存

一级缓存在执行了增、删、改操作之后,缓存中的相关数据会失效并删除

MyBatis 二级缓存:

MyBatis 中的二级缓存是跨 SqlSession 级别的,一级缓存是只在当前的 SqlSession 中生效,当多个用户在查询数据时,只要有一个 SqlSession 拿到了数据就会存入到二级缓存中去,其他的 SqlSession 都可以读取到二级缓存中的数据

一级、二级缓存的缺点:

一级缓存的话是基于 SqlSession 的,如果 SqlSession 关闭,那么会导致一级缓存中的数据被清空

MyBatis 的一、二级缓存都会出现数据不一致的情况,由于 MyBatis 的缓存都是基于本地的,因此分布式环境中,多个机器的 SqlSession 修改了数据库的数据,如果有些 SqlSession 没有及时更新缓存中的数据,会导致数据不一致,产生了脏数据

一级缓存和二级缓存的使用:

一级缓存默认开启,因此不用手动去设置

二级缓存默认关闭,如果系统对数据的一致性要求不严格,那么开启二级缓存可以显著提升性能

MyBatis 查询流程:

在用户进行查询时,如果开启了二级缓存,则会先去二级缓存中进行查询,如果二级缓存中没有,再去查一级缓存,最后查询数据库

MyBatis 一二级缓存实现原理图:

在这里插入图片描述

一级缓存效果演示:

public class MyBatisCacheDemo {
    public static void main(String[] args) {
        try (InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml")) {
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            SqlSession sqlSession = sqlSessionFactory.openSession();

            try {
                // 第一次查询,会执行 SQL 并缓存结果
                YourMapper mapper = sqlSession.getMapper(YourMapper.class);
                User user = mapper.selectUserById(1);

                // 输出第一次查询的结果
                System.out.println("First query result: " + user);

                // 第二次查询,由于一级缓存,不会执行 SQL,直接从缓存中获取结果
                User cachedUser = mapper.selectUserById(1);
                System.out.println("Second query result (cached): " + cachedUser);

                // 确保两次查询返回的是同一个对象
                System.out.println("Are they the same object? " + (user == cachedUser));
            } finally {
                sqlSession.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

7、那对于数据不一致我们一般怎么处理?

这里的不一致指的应该是数据库和缓存的数据不一致,这里就以商品缓存的更新举例:

如果不采用更新数据时双写来保证数据库与缓存的一致性的话,可以通过 canal + RocketMQ 来实现数据库与缓存的最终一致性,对于数据直接更新 DB,通过 canal 监控 MySQL 的 binlog 日志,并且发送到 RocketMQ 中,MQ 的消费者对数据进行消费并解析 binlog,过滤掉非增删改的 binlog,那么解析 binlog 数据之后,就可以知道对 MySQL 中的哪张表进行 增删改 操作了,那么接下来我们只需要拿到这张表在 Redis 中存储的 key,再从 Redis 中删除旧的缓存即可,那么怎么取到这张表在 Redis 中存储的 key 呢?

可以我们自己来进行配置,比如说监控 sku_info 表的 binlog,那么在 MQ 的消费端解析 binlog 之后,就知道是对 sku_info 表进行了增删改的操作,那么假如 Redis 中存储了 sku 的详情信息,key 为 sku_info:{skuId},那么我们就可以在一个地方对这个信息进行配置:

// 配置下边这三个信息
tableName = "sku_info"; // 表示对哪个表进行最终一致性
cacheKey = "sku_info:"; // 表示缓存前缀
cacheField = "skuId"; // 缓存前缀后拼接的唯一标识

// data 是解析 binlog 日志后拿到的 key-value 值,data.get("skuId") 就是获取这一条数据的 skuId 属性值
// 如下就是最后拿到的 Redis 的 key
redisKey = cacheKey + data.get(cacheField)

那么整体的流程图如下:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1416415.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Mac安装nvm,安装多个不同版本node,指定node版本

一.安装nvm brew install nvm二。配置文件 touch ~/.zshrc echo export NVM_DIR~/.nvm >> ~/.zshrc echo source $(brew --prefix nvm)/nvm.sh >> ~/.zshrc三.查看安装版本 nvm -vnvm常用命令如下:nvm ls :列出所有已安装的 node 版本nvm…

一张图文深入了解信息量概念

通信原理第10页最后一段: 概率论告诉我们,事件的不确定程度可以用其出现的概率来描述。因此,消息中包含的信息量与消息发生的概率密切相关。消息出现的概率越小,则消息中包含的信息量就越大。 这句话怎么理解呢? 比如…

小红构造数组-牛客周赛 Round 29(DFS方法)

题目很直白,方法就是暴力即可。 虽然说数据范围显得很大,但是在长整型范围内,一个数字的素因子数量最多不超64,而如果是不相同的素因子,虽然没有计算过,但是如果是12个不同的素因子应该会超过数据范围了。…

消息中间件之八股面试回答篇:三、RabbitMQ如何解决消息堆积问题(100万条消息堆积)+RabbitMQ高可用性和强一致性机制+回答模板

RabbitMQ中的消息堆积问题 当生产者发送消息的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到队列存储消息达到上限。之后发送的消息就会成为死信,可能会被丢弃,这就是消息堆积问题。 解决消息堆积有三种种思路…

c++阶梯之引用与内联函数

1. 引用 1.1 引用概念 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。 语法 类型& 引用变量名(对象名) 引用实体; 示例 很显然,在下面这…

21.Arrays类

Arrays类 1. 概述2. 常见方法3. sort 方法的自定义排序4. 代码示例5. 输出结果6. 注意事项 具体信息请查看 API 帮助文档 1. 概述 Arrays类是Java中的一个工具类,位于java.util包中。 它提供了一组静态方法,用于操作数组。通过Arrays类,我们…

springboot136人口老龄化社区服务与管理平台

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计,课程设计参考与学习用途。仅供学习参考, 不得用于商业或者非法用途,否则,一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

web前端---------盒子模型2

一------内边距 padding 属性用来设置元素的内边距长度,元素在默认情况下没有内边距,其值为none。 (1)当 padding 属性中仅含一个值时,该长度应用在上、下、左、右四个区域。 (2)当 padding …

Java二分查找-图文

一、二分查找概念 二分查找也叫折半查找,是在一组有序(升序/降序)的数据中查找一个元素,它是一种效率较高的查找方。 二、二分查找原理 1.二分查找的数组必须是有序数值型数组。 2.将想要查找的目标元素与查找范围内的中间元素进行比较,如果…

文件包含漏洞长度截断

长度截断 文件漏洞的利用方式什么是长度截断通过实操理解00截断对版本要求更高一点,而长度截断则是利用了windows的系统漏洞,就是windows文件名(就是文件名后缀之后)之后如果有空格,或者是点都会被忽略掉,也…

研发日记,Matlab/Simulink避坑指南(八)——else if分支结构Bug

文章目录 前言 背景介绍 问题描述 分析排查 解决方案 总结归纳 前言 见《研发日记,Matlab/Simulink避坑指南(三)——向上取整Bug》 见《研发日记,Matlab/Simulink避坑指南(四)——transpose()转置函数Bug》 见《研发日记,Matlab/Simuli…

Spring Cloud + Vue前后端分离-第13章 网站开发

源代码在GitHub - 629y/course: Spring Cloud Vue前后端分离-在线课程 Spring Cloud Vue前后端分离-第13章 网站开发 13-1 网站模块的搭建 新建web模板 1.网站开发,增加web模块,使用命令:vue create web vue版本4.2.3 大家拿到一个v…

【Web】小白也能做的RWCTF体验赛baby题部分wp

遇到不会的题,怎么办!有的师傅告诉你完了,废了,寄了!只有Z3告诉你,稳辣!稳辣!都稳辣! 这种CVE复现的题型,不可能要求选手从0到1进行0day挖掘,其实…

如何快速上手一个vue框架

安装nvm 下载nvm-setup.zip: https://github.com/coreybutler/nvm-windows/releases 解压安装nvm: 创建两个文件夹,一个是nvm的安装位置,另一个是node.js的下载位置。不需要配置环境变量和修改setting文件了 检查nvm是否安装成功…

Redis客户端之Redisson(三)Redisson分布式锁

一、背景: 高效的分布式锁设计应该包含以下几个要点: 1、互斥: 在分布式高并发的条件下,我们最需要保证,同一时刻只能有一个线程获得锁,这是最基本的一点 2、防止死锁: 在分布式高并发的条…

【vue3源码】vue源码探索之旅:项目介绍

简言 记录下我眼中的vue源码项目。 gitHubvue3项目仓库 项目要求: vue版本 3.4.15nodeV18.12.0以上使用pnpm包管理器vitest测试框架Vue3 vue3是渐进式JavaScript框架,易学易用,性能出色,适用场景丰富的 Web 前端框架。 Vue 是一个框架,也是一个生态。其功能覆盖了大部分…

VBA技术资料MF111:将表对象转换为正常范围

我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。我的教程一共九套,分为初级、中级、高级三大部分。是对VBA的系统讲解,从简单的入门,到…

【Linux C | 进程】Linux 进程间通信的10种方式(1)

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…

python14-Python的字符串之原始字符串

由于字符串中的反斜线都有特殊的作用。 因此当字符串中包含反斜线时,就需要对其进行转义。 比如写一条Windows的路径:D:\pythonStudy\demo,如果在Python 程序中直接这样写肯定是不行的,需要写成:D:\\pythonStudy\\demo,这很烦人. 此时可借助于原始字符串来解决这个问题。…

LeNet跟LeNet5详解

1 LeNet结构 主要是为了手写数字识别 具体结构讲解:从图中例子可得 1 先传入一个灰度图像尺寸为1x28x28,通道数为1,尺寸为28x28的灰度图像 2 第一层5x5卷积,经过公式 输入图像尺寸-卷积核尺寸2padding/步长1,&#…