场景题
二哥星球 https://www.yuque.com/itwanger/gykdzg/ded8g2
某个接口相应慢,如何排查?
- 查看服务器日志:服务器日志通常会记录接口请求的相关信息,如请求时间、响应时间、是否有异常报错等。通过分析日志,可以初步确定接口响应慢是偶尔出现还是频繁发生,以及是否存在特定的错误信息提示。
- 性能分析工具检测:利用性能分析工具,如 Java 中的 JProfiler、VisualVM 等。这些工具可以帮助分析接口执行过程中各个方法的耗时情况,定位到具体是哪些代码块或方法占用了大量时间,从而找到性能瓶颈。
- 数据库查询优化检查:如果接口涉及数据库操作,检查数据库查询语句是关键。可以通过数据库的性能分析工具,查看查询执行计划,判断是否存在全表扫描、缺少索引等问题。优化查询语句,添加必要的索引,能够显著提高数据库查询性能,进而提升接口响应速度。
- 网络状况检查:使用网络诊断工具,如 ping、traceroute 等,检查网络连接是否稳定,是否存在高延迟、丢包等情况。如果是分布式系统,还要考虑不同节点之间的网络通信情况,确保网络不会成为数据传输的瓶颈。
- 服务器资源监控:监控服务器的 CPU、内存、磁盘 I/O 等资源使用情况。如果服务器资源紧张,如 CPU 使用率过高、内存不足等,可能会导致接口处理速度变慢。此时需要考虑增加服务器资源或优化应用程序对资源的使用。
- 缓存机制检查:检查接口是否使用了缓存,以及缓存的策略和有效性。如果缓存未命中或缓存数据更新不及时,可能会导致每次请求都需要从数据库或其他数据源获取数据,增加响应时间。优化缓存策略,合理设置缓存过期时间,提高缓存命中率,可以有效提升接口性能。
表中有一千万条数据,如何处理
分库分表?
手写实现生产者-消费者
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 生成器
怎么设计秒杀系统
如何防止库存超卖
- MySQL:直接用 InnoDB 的排他锁,利用事务判断库存是否足够,足够再进行扣减。优点是数据强一致,缺点是并发性能一般,适合对一致性要求高的场景。
- Redis:把库存预加载到 Redis,用 setnx 加锁或 Lua 脚本扣减库存,然后异步同步到 MySQL。优点性能很好,适用于高并发,缺点是可能存在短期数据不一致情况。
如何实现 TTL 过期机制
- Redis 设置 TTL 过期时间,配合缓存删除策略;
- MQ 延迟队列
短链接怎么转换成长链接
电商促销高峰期百万 QPS 如何防止刷单
- 建立多维度风控模型
- 设备指纹识别:除 IP 外,还需关注设备硬件信息、浏览器指纹、屏幕分辨率等;
- 行为模式分析:考察用户在页面的滑动、点击等习惯;
- 时间窗口检测:正常用户从点击商品到商品下单有一定时间间隔(如 10 秒),过快很有可能就是刷单行为;
- 分层防护体系
- CDN 边缘防护:在 CDN 层面识别异常流量,基于 IP 地理位置、请求频率进行初步过滤;
- 网关层限流:进行更精细的控制,如设置单 IP 每分钟访问次数
- 业务层智能识别:实时计算用户的风险得分,考虑用户注册时长、历史订单情况、设备登录历史等因素
- 实时监控,动态调整
- 考虑下单转化率、评价会话时长、异常 IP 占比等,动态调整防刷策略,同时保证正常用户的使用