3.25 模拟面试 50 min
3.25 模拟面试总结
主要今天是一个培训机构的模拟面试,问的问题基本都能回答上来,但是听了一下我自己面试的录音,还是存在一些问题,小结一下
算法题:
旅游规划:滑动窗口
八股文:
- MySQL 和 Redis 之间的区别?
- MySQL 事务机制?
- Redis 缓存,然后缓存击穿、缓存穿透、缓存雪崩是什么以及解决方案?
- Redis 缓存与 Guava、Caffeiene 等本地缓存之间的区别,然后为什么使用 Redis 作为缓存,这两个哪个更加快一些?
- Redis 分布式锁如何实现?
- 缓存那块说完因为说到网络 IO 的内容,简单问了一下网络 IO 模型
- MySQL 和 Redis 的缓存一致性如何保证?
反问:这里我就没有反问了,哈哈哈,因为聊的时候基本差不多了
算法题
算法题这个我感觉不是很难吧,我不到 10 分钟就写完了,hhh,不过讲解的时候思路确实是我第一个问题,下面是这个算法题的图片,主要思路就是你先用一个数组存储,然后将数组按照消费 x 的值进行排序,这样后面就可以使用滑动窗口了。

然后,代码是 ACM 模式,如下:
然后思路这个主要他要问的核心点在于任意两个城市之间的 k 计算,但是我说的时候忘记说我先进行排序了,所以说的时候整得有点久了,后面我直接和他说那个代码实现,就理解了,然后还有说了一下时间复杂度,算法题差不多就过了。
八股文
1.MySQL 和 Redis 之间有什么区别?
MySQL 和 Redis 之间的区别主要就是关系型数据库和非关系数据库之间的区别,然后这里我顺带提了一下关系型数据库和非关系型数据库之间的区别,关系型数据库就是以二维表结构为关系存储的数据库,主要存储的是结构化的数据,非关系型数据库存储的有很多种,可以存储图,也可以存储文档,甚至键值对都是可以的,MySQL 就是典型的关系型数据库,存储以二维线性表为主。然后 Redis 是键值对型数据库,存储的大多是以键值对为主,然后 单机 MySQL 一般处理的 QPS 只有 2k~3k,且由于其存储在磁盘中,而 Redis 处理的 QPS 一般可以达到 80K- 100K QPS,基于内存,所以其读写的效率上来说,Redis 是远高于 MySQL 的,所以在项目中,一般使用 MySQL 作为存储,然后 Redis 作为缓存,很多东西能在缓存中处理掉,就不会使用到 MySQL。
2. 你上面既然说到了 Redis 是键值型数据库,那么我本地使用 Map 存储两个有什么区别?
一开始我说的点离题了,我以为的和回答 Redis 为什么那么快差不多,直接把 Redis 那么快给整上去了,o(╥﹏╥)o
复盘的时候想了一下,真的回答是没过脑子啊,哎,我一开始回答的就是Redis 怎么怎么快,后面面试官提示了一下,其实你本地的话可以比 Redis 更快的,你可以换一下角度,这个时候才想起来了黑马点评当时一个很重要的点,就是Redis 可以分布式缓存,还有会话这些的,后面我就重新回答了一下,主要就是从分布式的角度去回答
(1)稳定性
本地缓存主要就是存储在单个节点,其稳定性较低。而 Redis 很多时候都是采用分布式的方式比如一主二从三哨兵、集群等方式去部署的(这里其实我是有想法把他引导到我熟悉的东西去回答的,可惜差一点),所以其容错性和可靠性越高一点。
(2)读写速度
这个在一开始的时候我说的其实是Redis读写速度快的,后面想了一下不对,重新回答的时候才改回来的,就是在高并发的场景下,由于本地缓存的读写速度很快,所以数据可能不一致,然后 Redis 缓存由于读写这块是单线程的,网络 IO 这块才是多线程的,所以其对于并发读写的控制能力可以更强一些,其线程的安全性相对与本地缓存可以更高一些。
(3)适用场景
这个主要是我想到了亮哥直播中的异构系统那块的内容,然后联想到网关这块,本地缓存是基于内存的,所以主要应对的是数据量比较小、读写比较频繁的情况,如一些会话信息等,然后 Redis 主要应对的是大数据量、高并发、需要跨节点的情况, Redis 的适用范围更加广一些。
以上这些就是我面试的时候说的,我后面复盘的时候感觉可以补充一下:
(1)数据结构支持:本地缓存的数据结构没有像 Redis 那么丰富,Redis 还有 GEO、Bitmap、SortedSet 等数据结构,其可以满足更加复杂地数据需求
(2)内存管理:本地缓存是基于堆内存的,比如 caffeiene 、guava 等,堆内存的大小是有限的,而 Redis 可以采用扩容的方式来提供容量。
然后晚上和实验室的伙伴交流的时候,还有一道题目,就是为什么使用 MySQL 作为数据存储,而不使用文件进行存储,这个晚点打卡的时候我试着自己回答一下,主要思路在于数据的组织形式、还有 MySQL 的集群部署、数据的完整性以及可靠性四个方面
3. 然后就是缓存最常见的问题,缓存击穿、缓存穿透、缓存雪崩?
这个就是各种八股文巴拉巴拉,然后解决方法的话,我缓存穿透多一个点就是用布隆过滤器作为一级,然后缓存空缓存,最后就是分布式锁访问数据库,缓存穿透的话我分布式锁那里说到了双重判断锁,这个和 单例模式饿汉单例那个有点像,所以单例模式那里他后面就问了一些东西,主要就是怎么实现,说一下哪几种实现方式,我说了懒汉、饿汉、枚举三种,然后还说了双重校验和 CAS ,然后继续说缓存雪崩,缓存雪崩这里我按照小林coding那个分成两种原因回答,应对方案就是下面这些了。

4.Redis 分布式锁怎么实现,实现分布式锁的几种方式?
Redis 分布式锁我这里之前总结了一下,首先我说的就是单机版本的,主要就是 setnx ,然后过期时间,finally 解锁操作,然后这里问到了一个 Redis 原子性操作的,然后我因为建立上说到了 lua 脚本,我就解锁操作用 lua 脚本进行解锁,然后过期时间这里 还说到了看门狗机制以及冗余两个方式。
分布式的主要就是 RedLock,客户端先获取时间戳,然后客户端向 Redis 集群发起加锁请求,发起的请求设置超时时间,然后如果一个实例失败了,就直接跳过,继续向下一个实例发起请求,这里我们假设的客户端是 5 个,所以大于等于 3 个就成功了,然后获取此时的时间戳减去一开始获取的时间戳,小于过期时间的话,就算成功,如果大于就算失败,最后操作业务代码,失败之后就解锁。
另外一个实现分布式锁的方案我说到了 Zookeeper,主要就是基于临时节点实现,这个他问到了过期时间这个,我这里回答的是你 zookeeper 是基于临时节点实现了,如果你连接不断,就可以一直拿到锁,所以你只需要执行结速之后断开连接就差不多了,而且进程挂了,临时节点就会自动删除,所以锁一定会释放。
然后说到这里就是以上两种方式去对比
Zookeeper 优点:zookeeper 不用考虑过期时间,watch 机制,加锁失败会等待锁的释放
Zookeeper 缺点:性能不高,没有 Redis 快,然后你部署和运维成本增加了
5.这个也是最后一个问题,就是MySQL 和 Redis 缓存一致性的问题,这个怎么保证?
我是直接说的方案就是实时一致性的方案,我说的就是缓存双删的解决方案,即先删除一遍缓存,然后写数据库,最后在删除一遍的操作,然后先问了一下先删除缓存和先删除数据库两种方案为什么不行,然后面试官又问了一个能不能保证强一致性的?我以为问的是最终一致性的方案,我就回答了先写 MySQL,然后binlog,最后异步更新 Redis,即通过binlog 加上消息队列异步更新 Redis ,然后面试官又强调了一个强一致性,这里感觉是因为我这个时候状态没有一开始那么好了,所以问题没有听清,我最后回答的是用主动更新那个去保持强一致性,后面想了一下好像不行,然后面试官说,如果要保证强一致性的话,可以通过加锁的方式去实现,后面大概懂了,然后就是反问环节吧,我主要问的还是最后这个问题,就是强一致性的,这个问题之前看八股的时候没有遇到过吧,就是我说这种方式如果加锁的话对于性能应该会有所损耗吧,面试官那边说这个最终一致性确实可以保证,但是不推荐使用,我就大概知道了
总结:
- 今天问的问题虽然绝大多数都能答上,但是我感觉回答得不是很好吧,特别是算法那一题,我更多讲的思路是根据代码的思路去讲的,后面那个面试官也说了,这种表达方式并不是很好,比如他问的是 A ,而我的回答确实先说什么是 B,然后去推 A,这种方式虽然也可以,但是却没有说 A 直接,主要就是表达方式的问题吧,感觉在后面我可以重点练习一下。
- 最后一个就是状态问题,一开始还好,但是到后面说的问题多了,可能脑子有点乱,感觉主要还是练太少了 o(╥﹏╥)o,多练几次应该就差不多了
今天这个问的题虽然不难,但是很多问题回答可以再好一点,回去得好好复盘了o(╥﹏╥)o,然后还得着重练习表达这一块,ε=(´ο`*)))唉
