本文目录导读:

我来分享几个典型的Java流量突增案例,以及对应的排查思路和解决方案。
双11大促流量突增导致服务雪崩
场景描述
- 背景:电商系统,双11零点促销活动
- 现象:流量从平常的1000 QPS突增到10000 QPS,系统响应时间从50ms飙升到5秒,部分节点出现OOM
排查过程
// 1. 首先查看系统整体状态 jstat -gcutil <pid> 1000 // 查看GC情况 jmap -heap <pid> // 查看堆内存使用 top -Hp <pid> // 查看线程CPU占用 // 发现的问题: // - Full GC频繁,达到每分钟50次 // - 老年代使用率99% // - CPU使用率飙升至95%
根因分析
// 问题代码示例
public class OrderService {
// 问题1:无限缓存用户信息
private static Map<Long, UserInfo> userCache = new HashMap<>();
// 问题2:同步调用过多
public Order createOrder(OrderRequest request) {
// 同步调用库存服务(2ms)
StockInfo stock = stockClient.queryStock(request.getSkuId());
// 同步调用用户服务(3ms)
UserInfo user = userClient.queryUser(request.getUserId());
// 同步调用优惠券服务(2ms)
CouponInfo coupon = couponClient.queryCoupon(request.getUserId());
// 同步调用支付服务(1ms)
PayInfo pay = payClient.queryPay(request.getOrderId());
// 总耗时:8ms,但流量突增时每个服务都会变慢
return buildOrder(stock, user, coupon, pay);
}
}
解决方案
// 方案1:缓存本地化
@Component
public class UserCacheManager {
private LoadingCache<Long, UserInfo> cache = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build(new CacheLoader<Long, UserInfo>() {
@Override
public UserInfo load(Long userId) {
return userClient.queryUser(userId);
}
});
public UserInfo getUser(Long userId) {
try {
return cache.get(userId);
} catch (Exception e) {
return userClient.queryUser(userId);
}
}
}
// 方案2:异步化改造
public CompletableFuture<Order> createOrderAsync(OrderRequest request) {
CompletableFuture<StockInfo> stockFuture =
CompletableFuture.supplyAsync(() -> stockClient.queryStock(request.getSkuId()));
CompletableFuture<UserInfo> userFuture =
CompletableFuture.supplyAsync(() -> userClient.queryUser(request.getUserId()));
CompletableFuture<CouponInfo> couponFuture =
CompletableFuture.supplyAsync(() -> couponClient.queryCoupon(request.getUserId()));
CompletableFuture.allOf(stockFuture, userFuture, couponFuture).join();
return CompletableFuture.completedFuture(
buildOrder(stockFuture.get(), userFuture.get(), couponFuture.get(), null)
);
}
// 方案3:限流熔断
@Bean
public RateLimiter rateLimiter() {
return RateLimiter.create(5000); // 每秒钟只允许5个请求
}
public Order createOrderWithLimit(OrderRequest request) {
if (!rateLimiter.tryAcquire(100, TimeUnit.MILLISECONDS)) {
throw new BusyException("系统繁忙,请稍后重试");
}
// 业务逻辑
}
热点商品抢购导致的线程池耗尽
场景描述
- 现象:核心线程池全部被占满,新请求排队等待,甚至出现RejectedExecutionException
- 特征:某一个SKU的请求量特别大
排查过程
// 查看线程池状态 ThreadPoolExecutor executor = (ThreadPoolExecutor) threadPoolTaskExecutor.getThreadPoolExecutor(); executor.getActiveCount(); // 当前活跃线程数 executor.getQueue().size(); // 队列大小 executor.getPoolSize(); // 线程池大小 // 通过Arthas查看线程状态 thread -n 3 -v // 查看最忙的3个线程 // 发现大量线程阻塞在:redis.clients.jedis.Jedis.get()
解决方案
// 方案1:热点Key隔离
public class HotKeyAwareService {
private static final int HOT_THRESHOLD = 100;
private volatile Map<String, AtomicInteger> hotKeyCounter = new ConcurrentHashMap<>();
private ExecutorService hotKeyExecutor = Executors.newFixedThreadPool(50);
private ExecutorService normalExecutor = Executors.newFixedThreadPool(200);
public void processRequest(String skuId, Request request) {
AtomicInteger counter = hotKeyCounter.computeIfAbsent(skuId, k -> new AtomicInteger(0));
if (counter.incrementAndGet() > HOT_THRESHOLD) {
// 热点SKU,使用独立线程池
hotKeyExecutor.submit(() -> handleHotRequest(skuId, request));
} else {
// 正常请求
normalExecutor.submit(() -> handleNormalRequest(skuId, request));
}
}
}
// 方案2:布隆过滤器+多级缓存
public class CacheStrategy {
private BloomFilter<String> hotSkuFilter = BloomFilter.create(Funnels.stringFunnel(), 10000, 0.01);
private LoadingCache<String, Object> localCache = cacheConfig.createLocalCache();
private RedisTemplate<String, Object> redisTemplate;
public Object getSkuInfo(String skuId) {
// 1. 本地缓存
Object localData = localCache.getIfPresent(skuId);
if (localData != null) return localData;
// 2. Redis缓存
Object redisData = redisTemplate.opsForValue().get("sku:" + skuId);
if (redisData != null) {
localCache.put(skuId, redisData);
return redisData;
}
// 3. 数据库查询(加分布式锁防止缓存击穿)
String lockKey = "sku:lock:" + skuId;
boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS);
if (lock) {
try {
Object dbData = queryFromDB(skuId);
redisTemplate.opsForValue().set("sku:" + skuId, dbData, 10, TimeUnit.MINUTES);
return dbData;
} finally {
redisTemplate.delete(lockKey);
}
}
// 等待重试
try { Thread.sleep(50); } catch (InterruptedException e) {}
return redisTemplate.opsForValue().get("sku:" + skuId);
}
}
日志打爆磁盘IO
场景描述
- 现象:磁盘IO使用率100%,应用响应变慢
- 原因:流量突增时,错误日志疯狂打印,特别是DEBUG级别的日志
排查过程
// 查看磁盘和日志情况 df -h // 查看磁盘使用 iostat -x 1 // 查看IO情况 du -sh logs/* // 查看各日志文件大小 // 通过日志分析工具查看 grep -c "ERROR" error.log | tail -n 100
解决方案
// 方案1:日志分级和限流
@Component
public class LoggingInterceptor {
private static final org.slf4j.Logger LOGGER =
LoggerFactory.getLogger(LoggingInterceptor.class);
// 限流日志
private RateLimiter errorLogLimiter = RateLimiter.create(10);
private RateLimiter warnLogLimiter = RateLimiter.create(5);
public void logError(String traceId, String message, Throwable e) {
if (errorLogLimiter.tryAcquire()) {
// 避免打印堆栈过多
LOGGER.error("traceId: {}, error: {}", traceId, message);
} else {
// 记录到内存缓冲区,定期汇总
logBuffer.add(new LogEntry(traceId, message));
}
}
}
// 方案2:异步日志+批量写入
<configuration>
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>8192</queueSize>
<discardingThreshold>0</discardingThreshold>
<neverBlock>true</neverBlock>
<appender-ref ref="FILE"/>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%date{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.example" level="INFO"/>
<logger name="org.springframework" level="WARN"/>
<root level="INFO">
<appender-ref ref="ASYNC"/>
</root>
</configuration>
流量突增排查工具清单
# 1. 系统层面 top # CPU使用情况 free -m # 内存使用 vmstat 1 # 系统活动 iostat -x 1 # IO状态 netstat -ant | wc -l # 连接数 # 2. JVM层面 jps # 查看java进程 jstat -gcutil <pid> 1000 # GC情况 jmap -heap <pid> # 堆内存详情 jstack <pid> > dump.log # 线程栈 # 3. 应用层面 curl -X GET /actuator/metrics # Spring Boot指标 curl -X GET /actuator/health # 健康检查 # 4. 中间件 redis-cli info # Redis状态 kafka-consumer-groups --describe --group <group> # Kafka消费情况
通用优化建议
// 1. 配置好连接池
@Configuration
public class ConnectionPoolConfig {
@Bean
public HikariDataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(50);
config.setMinimumIdle(10);
config.setConnectionTimeout(30000);
config.setMaxLifetime(1800000);
// 关键:设置连接泄漏检测
config.setLeakDetectionThreshold(60000);
return new HikariDataSource(config);
}
}
// 2. 使用内嵌缓存+Caffeine
@Configuration
public class CacheConfig {
@Bean
public Caffeine caffeineConfig() {
return Caffeine.newBuilder()
.maximumSize(10000)
.expireAfterWrite(60, TimeUnit.SECONDS)
.recordStats();
}
}
// 3. 服务降级策略
@Component
public class DegradeStrategy {
private boolean isHealthy = true;
private CircuitBreaker circuitBreaker = CircuitBreaker.ofDefaults("myservice");
public Object callWithDegrade() {
return circuitBreaker.executeSupplier(() -> {
if (!isHealthy) return fallback();
return doBusiness();
});
}
private Object fallback() {
return Collections.emptyMap(); // 返回缓存或默认值
}
}
- 提前预防:流量突增前做好压测,预先把线程池、连接池调大
- 快速定位:使用Arthas、JProfiler等工具快速定位瓶颈
- 弹性设计:使用Hystrix/Resilience4j做好熔断降级
- 缓存优先:尽可能使用本地缓存+Redis多级缓存
- 异步化:非核心链路使用异步处理
- 监控报警:配置好Prometheus+Grafana,当流量达到警戒线时自动告警
面试重点:能针对突增流量设计出合理的解决方案,并解释为什么这么设计,以及考虑系统的高可用性和降级策略。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播