个人评价
很简单的面试题,八股文问得都比较浅,这次项目问得比较多,在mysql的索引失效中,数据分布影响导致的索引失效这一点比较深,能够讲出来的话,还是比较加分的。
1.介绍一下电影项目项目?(介绍一下实习做的项目)
不同于传统的vip制的电影网站,基于springCloud-Alibaba实现方案两落地的微服务线上影院项目,通过购买片源的形式来播放片源,主要流程就是用户登录片源购买到片源的播放的流程,其中还包括历史播放,热门榜,优惠劵,签到积分的辅助模块。
2.刚刚听到你说热门榜模块,说说你是怎么实现的?
刚开始的时候,想的是将实时的热门榜和历史热门榜都存储到数据库中,但是呢,这个方案效率很低,每次修改片源对应的热度都需要做DB操作。
后续我的优化方案就是通过redis的set和zset结构来存储热门榜的数据,通过定时任务在月初的时候会将当月的热门榜数据存储到DB中,完成历史热门榜的持久化。
使用Set存储用户观看情况,key存片源的id,value就是存userId集合。使用Zset存储片源热度的排名,Key存储单月的信息,member存储片源id,scope存储热度。
在每次对应片源的用户观看情况修改的时候,都会调用scard方法获取用户的数量 * 10就是最新的热度,使用该数据修改zset中的数据,zset就是当前的热门榜数据。
使用xxl-job在执行三个任务,分别是创建当月热门榜表,调用zset的popmin方法取出30条数据做插入操作,清除缓存。
xxl-job任务就会操作DB,在DB中我们也是做了相应的设计的,如果将热门榜的数据全部存储到一张表的话,后续没做索引的话查询效率非常低,因此我们使用水平分表,这里没有使用share-jdbc来做分表,将每个月作为一张表。
在mybatis中insert标签可以做新建表的操作,通过Insert标签 + SPEL语句生成对应的表,然后新增数据。
3.xxl-job中是怎么设置的?
在xxl-job我们使用到的策略是分片广播,因为热门榜的数据比较多,我们搭建了xxl-job的集群,我们会将数据以30条作为一页,通过页码取模的方式匹配对应的节点执行定时任务。
4.rabbitMq用来干什么的?
mq主要就是异步的实现流量削峰,在我的项目主要就是对业务进行解耦合。
5.你Java最熟悉什么?
基础知识的话,集合吧。
6.你说到集合,那你说说ArrayList和LinkedList的区别吧?
- 在线程安全方面,两者都不是线程安全的,可以使用SynchronziedList来包装。
- 底层结构方面,ArrayList使用动态数组实现的,LinkedList使用双向链表实现的,并且ArrayList实现了RandomAccess接口,支持快速的随机访问。
- 在使用方面,当数据进行新增时,ArrayList的时间复杂度为O(n),如果是队尾的话,时间复杂度为O(n),但是如果涉及到扩容,那它的时间复杂度还是O(n)。LinkedList的时间复杂度O(n),当在队尾和队头的时候时间复杂度为O(n)。当数据进行查询的时候,ArrayList的时间复杂度为O(1),LinkedList的时间复杂度为O(n)
7.项目中有没有使用到锁?
在解决超卖问题的时候就使用到了锁,我们领取优惠劵的超领问题没有采用传统的版本号锁来解决,而是通过修改SQL语句的条件部分,但是在同用户进行并发领取的时候还是会出现领到的卷数大于限制的卷数(还是超卖)。我们的解决方案就是对userId添加 Synchronzied保证每次只有一个相同的用户领卷。但是呢这是在一个服务节点时使用的,因为Synchronzied针对一个JVM,在微服务项目中出现锁失效的问题。所以我们需要使用分布式锁。我们使用的就是redisson通过的可重入锁。
8.redisson实现的可重入锁的底层了解过吗?
其底层主要就是基于redis的hash结构,大key存储要上锁的业务id,小key存储线程的id,value存储锁重入的次数。
9.为什么使用redis作为分布式锁,mysql不行吗?
- 我认为只要就是redis的数据结构比较适合做分布式锁。
- reddison实现的分布式锁主要的功能就是 支持锁的重入,ttl的重置机制,堵塞重试机制。
- 锁的重入主要就是基于hash结构实现的,大key存储业务id,小key存储线程id,value存储锁重入的次数。
- ttl的重试机制主要就是基于watch dog实现的,watch dog底层就是一个定时任务,每隔30秒就会重置锁的ttl。
- 阻塞重试机制主要就是基于redis的发布与订阅没模式实现的,获取锁失败的线程会去订阅一个频道,但是其他线程解锁的时候就会向该频道发送消息,获取锁失败的线程就会重新获取锁。
10.除了使用rabbitMq作为异步消息,还有什么方法可以做异步?
线程池。
11.线程池创建的核心参数有了解过吗?
- 核心线程数,总线程数,救急线程存活时间,时间单位,阻塞队列,拒绝策略,线程工厂。
- 阻塞队列主要就是两种ArrayBlockQueue,linkedBlockQueue。
- 拒绝策略有四种,抛出异常策略,使用主线程执行任务策略,删除存在时间最久的任务策略,丢弃任务策略。
12.mysql做SQL优化从哪些方面入手?
- 在数据比较庞大且经常访问的时候,可以建立索引。
- 但SQL建立完索引后速度还是很慢的话,就可以通过慢日志查询,调用explain查看索引覆盖的情况。
- 判断索引是否失效,防止回表的操作,避免使用select *。
- 做分页查询的时候可以通过子查询+覆盖索引优化SQL。
- 在必要的时候可以进行垂直分表,实现冷热数据隔离。
13.你刚刚说防止索引失效,那你说说索引失效场景有哪些?
- 未遵循最左前缀法则,在做条件判断的时候跳过联合索引中的字段。
- 范围查询 >,<导致部分索引失效,可以通过 <=,>=避免。
- 调用字段聚合函数会导致部分索引失效。
- 字段进行了主动的类型转化也会到导致索引失效。
- 字段进行模糊匹配的时候如果字符串的开头为%会导致部分索引失效。
- 当条件中使用or,会导致or右侧的字段部分索引失效。
- 查询的数据分布影响导致索引失效,当查询的数据大于30%就不会走索引。