跳转至

场景题

二哥星球 https://www.yuque.com/itwanger/gykdzg/ded8g2

某个接口相应慢,如何排查?

  1. 查看服务器日志:服务器日志通常会记录接口请求的相关信息,如请求时间、响应时间、是否有异常报错等。通过分析日志,可以初步确定接口响应慢是偶尔出现还是频繁发生,以及是否存在特定的错误信息提示。
  2. 性能分析工具检测:利用性能分析工具,如 Java 中的 JProfiler、VisualVM 等。这些工具可以帮助分析接口执行过程中各个方法的耗时情况,定位到具体是哪些代码块或方法占用了大量时间,从而找到性能瓶颈。
  3. 数据库查询优化检查:如果接口涉及数据库操作,检查数据库查询语句是关键。可以通过数据库的性能分析工具,查看查询执行计划,判断是否存在全表扫描、缺少索引等问题。优化查询语句,添加必要的索引,能够显著提高数据库查询性能,进而提升接口响应速度。
  4. 网络状况检查:使用网络诊断工具,如 ping、traceroute 等,检查网络连接是否稳定,是否存在高延迟、丢包等情况。如果是分布式系统,还要考虑不同节点之间的网络通信情况,确保网络不会成为数据传输的瓶颈。
  5. 服务器资源监控:监控服务器的 CPU、内存、磁盘 I/O 等资源使用情况。如果服务器资源紧张,如 CPU 使用率过高、内存不足等,可能会导致接口处理速度变慢。此时需要考虑增加服务器资源或优化应用程序对资源的使用。
  6. 缓存机制检查:检查接口是否使用了缓存,以及缓存的策略和有效性。如果缓存未命中或缓存数据更新不及时,可能会导致每次请求都需要从数据库或其他数据源获取数据,增加响应时间。优化缓存策略,合理设置缓存过期时间,提高缓存命中率,可以有效提升接口性能。

表中有一千万条数据,如何处理

分库分表?

手写实现生产者-消费者

Java
class ProducerConsumer {
    private final int capacity;
    private final Queue<Integer> queue = new LinkedList<>();

    public ProducerConsumer(int capacity) {
        this.capacity = capacity;
    }

    // 生产者方法
    public synchronized void produce(int item) throws InterruptedException {
        while (queue.size() == capacity) {
            wait();
        }
        queue.add(item);
        System.out.println("Produced: " + item);
        notifyAll();
    }

    // 消费者方法
    public synchronized int consume() throws InterruptedException {
        while (queue.isEmpty()) {
            wait();
        }
        int item = queue.poll();
        System.out.println("Consumed: " + item);
        notifyAll();
        return item;
    }
}

class Producer implements Runnable {
    private final ProducerConsumer pc;
    private int count;

    public Producer(ProducerConsumer pc) {
        this.pc = pc;
    }

    @Override
    public void run() {
        try {
            while (count < 10) {
                pc.produce(count++);
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Consumer implements Runnable {
    private final ProducerConsumer pc;

    public Consumer(ProducerConsumer pc) {
        this.pc = pc;
    }

    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                pc.consume();
                Thread.sleep(100);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer(5);
        Thread producerThread = new Thread(new Producer(pc));
        Thread consumerThread = new Thread(new Consumer(pc));

        producerThread.start();
        consumerThread.start();
    }
}

设计一个基于 byte[],遵循 FIFO 读取的缓冲区,要求不能有 byte[] 之外的变量

Java
public class ByteFIFOBuffer {
    private byte[] buffer;
    private int readIndex;
    private int writeIndex;

    public ByteFIFOBuffer(int size) {
        buffer = new byte[size];
        readIndex = 0;
        writeIndex = 0;
    }

    public synchronized void put(byte b) {
        buffer[writeIndex] = b;
        writeIndex = (writeIndex + 1) % buffer.length;
    }

    public synchronized byte get() {
        byte b = buffer[readIndex];
        readIndex = (readIndex + 1) % buffer.length;
        return b;
    }

    public synchronized boolean isEmpty() {
        return readIndex == writeIndex;
    }

    public synchronized boolean isFull() {
        return (writeIndex + 1) % buffer.length == readIndex;
    }
}

对三个不同数据源进行采集,最后组合返回,怎么做

可以使用多线程或异步编程的方式来同时采集三个数据源的数据,然后再将它们组合起来返回。以 Java 中的 CompletableFuture 为例:

Java
import java.util.concurrent.CompletableFuture;

public class DataCollection {

    public static String source1() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Data from source 1";
    }

    public static String source2() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Data from source 2";
    }

    public static String source3() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Data from source 3";
    }

    public static String collectData() {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(DataCollection::source1);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(DataCollection::source2);
        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(DataCollection::source3);

        CompletableFuture.allOf(future1, future2, future3).join();

        return future1.join() + "\n" + future2.join() + "\n" + future3.join();
    }

    public static void main(String[] args) {
        System.out.println(collectData());
    }
}

如果有 1000 个任务,每个任务耗时 0.1 秒,需要在 10 秒内完成,该怎么做

可以使用线程池来并发执行这些任务。由于每个任务耗时 0.1 秒,要在 10 秒内完成 1000 个任务,至少需要 10 个线程并发执行。

Java
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Task implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class TaskExecution {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 1000; i++) {
            executor.submit(new Task());
        }
        executor.shutdown();
    }
}

如何实现股票价格的实时变化

怎么设计一个分布式 id 生成器

怎么设计秒杀系统

如何防止库存超卖

  1. MySQL:直接用 InnoDB 的排他锁,利用事务判断库存是否足够,足够再进行扣减。优点是数据强一致,缺点是并发性能一般,适合对一致性要求高的场景。
  2. Redis:把库存预加载到 Redis,用 setnx 加锁或 Lua 脚本扣减库存,然后异步同步到 MySQL。优点性能很好,适用于高并发,缺点是可能存在短期数据不一致情况。

如何实现 TTL 过期机制

  1. Redis 设置 TTL 过期时间,配合缓存删除策略;
  2. MQ 延迟队列

短链接怎么转换成长链接

电商促销高峰期百万 QPS 如何防止刷单

  1. 建立多维度风控模型
    1. 设备指纹识别:除 IP 外,还需关注设备硬件信息、浏览器指纹、屏幕分辨率等;
    2. 行为模式分析:考察用户在页面的滑动、点击等习惯;
    3. 时间窗口检测:正常用户从点击商品到商品下单有一定时间间隔(如 10 秒),过快很有可能就是刷单行为;
  2. 分层防护体系
    1. CDN 边缘防护:在 CDN 层面识别异常流量,基于 IP 地理位置、请求频率进行初步过滤;
    2. 网关层限流:进行更精细的控制,如设置单 IP 每分钟访问次数
    3. 业务层智能识别:实时计算用户的风险得分,考虑用户注册时长、历史订单情况、设备登录历史等因素
  3. 实时监控,动态调整
    1. 考虑下单转化率、评价会话时长、异常 IP 占比等,动态调整防刷策略,同时保证正常用户的使用