面试题汇总06-场景题&线上问题排查&难点亮点

时间:2025-04-08 07:27:05

面试题汇总06-场景题&线上问题排查&难点亮点

  • 【一】场景题
    • 【1】订单到期关闭如何实现
    • 【2】每天100w次登录请求,4C8G机器如何做JVM调优?
      • (1)问题描述和分析
      • (2)堆内存设置
      • (3)垃圾收集器选择
      • (4)各区大小设置
      • (5)添加必要的日志
    • 【3】如果你的业务量突然提升100倍QPS你会怎么做?
  • 【二】线上问题排查
    • 【1】RocketMQ消费堆积问题排查
    • 【2】RT飙高问题排查过程
    • 【3】数据库死锁问题排查过程
      • (1)现象
      • (2)背景介绍
      • (3)死锁日志
      • (4)问题排查
      • (5)索引分析
      • (6)加锁原理
      • (7)解决方法
    • 【4】数据库死锁问题排查问题2
    • 【5】慢sql问题排查(联合索引失效)
      • (1)问题排查
      • (2)问题解决
    • 【6】线上sql优化的整体思路
    • 【7】POI导致内存溢出排查(结果查询数据导出)
      • (1)问题描述
      • (2)问题排查
      • (3)问题解决
    • 【8】频繁FullGC问题排查
      • (1)问题定位
  • 【三】项目难点&亮点
    • 【1】引入分布式锁解决并发问题
    • 【2】redis的多种使用案例
    • 【3】easyExcel的多线程导出导入
    • 【4】

【一】场景题

【1】订单到期关闭如何实现

在电商、支付等系统中,一般都是先创建订单(支付单),再给用户一定的时间进行支付,如果没有按时支付的话,就需要把之前的订单(支付单)取消掉。这种类似的场景有很多,还有比如到期自动收货、超时自动退款、下单后自动发送短信等等都是类似的业务问题。

订单的到期关闭的实现有很多种方式,分别有:

1、被动关闭(不推荐)
2、定时任务(推荐,适合时间精确度要求不高的场景)
3、DelayQueue(不推荐,基于内存,无法持久化)
4、时间轮(不推荐,基于内存,无法持久化)
5、kafka(MQ 方案不推荐,大量无效调度)
6、RocketMQ延迟消息(MQ 方案不推荐,大量无效调度)
7、RabbitMQ死信队列(MQ 方案不推荐,大量无效调度)
8、RabbitMQ插件(MQ 方案不推荐,大量无效调度)
9、Redis过期监听(不推荐,容易丢消息)
10、Redis的ZSet(不推荐,可能会重复消费)
11、Redisson(推荐,可以用)

Redisson中定义了分布式延迟队列RDelayedQueue,这是一种基于我们前面介绍过的zset结构实现的延时队列,它允许以指定的延迟时长将元素放到目标队列中。

其实就是在zset的基础上增加了一个基于内存的延迟队列。当我们要添加一个数据到延迟队列的时候,redisson会把数据+超时时间放到zset中,并且起一个延时任务,当任务到期的时候,再去zset中把数据取出来,返回给客户端使用。


定义一个Redisson客户端:

@Configurationpublic class RedissonConfig {
           @Bean(destroyMethod="shutdown")    
public RedissonClient redisson() throws IOException {
   
        Config config = new Config();	
      config.useSingleServer().setAddress("redis://127.0.0.1:6379");		        RedissonClient redisson = Redisson.create(config);
        return redisson;
}}

接下来,在想要使用延迟队列的地方做如下方式:

org.redisson.api.RBlockingDeque;import org.redisson.api.RDelayedQueue;import org.redisson.api.RedissonClient;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.concurrent.TimeUnit;
@Componentpublic class RedissonOrderDelayQueue {
   


    @Autowired    RedissonClient redisson;
    public void addTaskToDelayQueue(String orderId) {
                 RBlockingDeque<String> blockingDeque = redisson.getBlockingDeque("orderQueue");
            RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(blockingDeque);
        System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + "添加任务到延时队列里面");        delayedQueue.offer(orderId, 3, TimeUnit.SECONDS);        delayedQueue.offer(orderId, 6, TimeUnit.SECONDS);        delayedQueue.offer(orderId, 9, TimeUnit.SECONDS);    }

   public String getOrderFromDelayQueue() {
           RBlockingDeque<String> blockingDeque = redisson.getBlockingDeque("orderQueue");        RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(blockingDeque);        String orderId = blockingDeque.take();        return orderId;    }
}

使用offer方法将两条延迟消息添加到RDelayedQueue中,使用take方法从RQueue中获取消息,如果没有消息可用,该方法会阻塞等待,直到消息到达。

我们使用 RDelayedQueue 的 offer 方法将元素添加到延迟队列,并指定延迟的时间。当元素的延迟时间到达时,Redisson 会将元素从 RDelayedQueue 转移到关联的 RBlockingDeque 中。

使用 RBlockingDeque 的 take 方法从关联的 RBlockingDeque 中获取元素。这是一个阻塞操作,如果没有元素可用,它会等待直到有元素可用。

所以,为了从延迟队列中取出元素,使用 RBlockingDeque 的 take 方法,因为 Redisson 的 RDelayedQueue 实际上是通过转移元素到关联的 RBlockingDeque 来实现延迟队列的。

【2】每天100w次登录请求,4C8G机器如何做JVM调优?

(1)问题描述和分析

首先,我们需要问清楚,一天100W次的登录,在一天内有没有某个时段是高峰的?高峰期的QPS大概可以达到多少。

如果没有高峰期,虽然100万听上去