文章目录
-
- [1. 高并发系统性能调优基础认知](#1. 高并发系统性能调优基础认知)
- [2. JVM参数调优实战](#2. JVM参数调优实战)
-
- [2.1 JVM核心调优参数(堆/非堆/GC)](#2.1 JVM核心调优参数(堆/非堆/GC))
- [2.2 主流GC收集器调优配置](#2.2 主流GC收集器调优配置)
- [2.3 实战案例:生产环境JVM配置模板](#2.3 实战案例:生产环境JVM配置模板)
- [2.4 JVM调优避坑指南](#2.4 JVM调优避坑指南)
- [3. 线程池配置优化与并发控制](#3. 线程池配置优化与并发控制)
-
- [3.1 线程池核心参数设计原理](#3.1 线程池核心参数设计原理)
- [3.2 不同场景线程池配置方案](#3.2 不同场景线程池配置方案)
- [3.3 动态线程池实现(结合Nacos)](#3.3 动态线程池实现(结合Nacos))
- [3.4 线程池常见问题与解决方案](#3.4 线程池常见问题与解决方案)
- [4. Redis缓存防护:穿透/击穿/雪崩](#4. Redis缓存防护:穿透/击穿/雪崩)
-
- [4.1 三大缓存问题场景剖析](#4.1 三大缓存问题场景剖析)
- [4.2 缓存穿透防护方案(布隆过滤器)](#4.2 缓存穿透防护方案(布隆过滤器))
- [4.3 缓存击穿/雪崩防护实战](#4.3 缓存击穿/雪崩防护实战)
- [4.4 Redis缓存优化配置](#4.4 Redis缓存优化配置)
- [5. 数据库分库分表实战](#5. 数据库分库分表实战)
-
- [5.1 分库分表核心原理与场景](#5.1 分库分表核心原理与场景)
- [5.2 分片策略选型(垂直/水平)](#5.2 分片策略选型(垂直/水平))
- [5.3 Sharding-JDBC实战配置](#5.3 Sharding-JDBC实战配置)
- [5.4 分库分表后问题解决方案](#5.4 分库分表后问题解决方案)
- [6. 高并发系统性能监控方案](#6. 高并发系统性能监控方案)
- [7. 总结与进阶方向](#7. 总结与进阶方向)
1. 高并发系统性能调优基础认知
1.1 高并发核心瓶颈与调优目标
高并发场景下,系统性能瓶颈主要集中在四个层面,调优需针对性突破:
-
内存瓶颈:JVM堆溢出、GC频繁、缓存命中率低;
-
线程瓶颈:线程池参数不合理、线程阻塞、上下文切换频繁;
-
存储瓶颈:Redis缓存失效、数据库连接池耗尽、单表数据量过大;
-
网络瓶颈:接口响应慢、连接超时、数据传输量大。
核心调优目标:高可用(99.99%+)、低延迟(接口响应<500ms)、高吞吐(QPS支持万级+)、高容错(故障自动降级)。
1.2 性能评估指标与监控工具
(1)核心性能指标
-
吞吐量(QPS/TPS):每秒处理请求/事务数;
-
响应时间(RT):从请求发起至响应完成的耗时;
-
并发数:系统同时处理的请求数;
-
错误率:请求失败占比(允许值<0.1%);
-
GC指标:GC停顿时间(允许值<100ms)、GC频率(允许值<1次/分钟)。
(2)常用监控工具
-
JVM监控:jstat、jmap、jstack、VisualVM、Arthas;
-
并发监控:JConsole、ThreadDump分析工具;
-
缓存监控:Redis Desktop Manager、Redis Info命令;
-
数据库监控:MySQL Slow Query、Percona Monitoring;
-
全链路监控:SkyWalking、Pinpoint、Prometheus+Grafana。
2. JVM参数调优实战
JVM是Java程序运行的基石,高并发场景下,不合理的JVM配置会导致OOM、GC频繁、响应延迟等问题,需结合业务场景精准调优。
2.1 JVM核心调优参数(堆/非堆/GC)
JVM内存模型分为堆、非堆(方法区、元空间)、程序计数器、虚拟机栈、本地方法栈,核心调优聚焦堆和非堆:
(1)堆内存参数(最核心)
-Xms:初始堆大小(如2g),建议与-Xmx一致,避免频繁扩容;
-Xmx:最大堆大小(如2g),根据物理内存配置(建议为物理内存的1/2~2/3);
-Xmn:新生代大小(如512m),新生代=Eden+From Survivor+To Survivor,建议为堆的1/3~1/2;
-XX:SurvivorRatio:Eden与Survivor区比例(如8),即Eden:From:To=8:1:1;
-XX:MaxTenuringThreshold:对象晋升老年代阈值(如15),超过阈值的新生代对象进入老年代。
(2)非堆内存参数
-XX:MetaspaceSize:元空间初始大小(如256m),替代JDK8前的PermGen;
-XX:MaxMetaspaceSize:元空间最大大小(如512m),避免元空间溢出;
-XX:DirectMemorySize:直接内存大小(如1g),NIO操作会使用直接内存,需避免溢出。
(3)GC日志参数(必须开启)
-XX:+PrintGCDetails:打印GC详细日志;
-XX:+PrintGCTimeStamps:打印GC时间戳;
-XX:+PrintHeapAtGC:打印GC前后堆内存变化;
-Xloggc:./gc.log:GC日志输出路径。
2.2 主流GC收集器调优配置
JDK8默认GC收集器为Parallel Scavenge(新生代)+Parallel Old(老年代),高并发场景推荐使用G1或ZGC(JDK11+),以下为生产级配置:
(1)G1收集器(JDK8+推荐,适合大堆)
bash
# 启用G1收集器
-XX:+UseG1GC
# G1混合回收周期中并行回收线程数
-XX:ParallelGCThreads=8
# 并发标记线程数
-XX:ConcGCThreads=2
# 堆内存占用达到该比例触发混合回收(默认45%)
-XX:InitiatingHeapOccupancyPercent=70
# 每次混合回收的最大时间(默认200ms)
-XX:MaxGCPauseMillis=100
# 禁止新生代提前晋升
-XX:G1PreventiveGCPolicy=region
(2)ZGC收集器(JDK11+,超低延迟,适合超大堆)
bash
# 启用ZGC收集器
-XX:+UseZGC
# 最大堆大小
-Xmx8g
# ZGC并发线程数
-XX:ZGCThreads=4
# 启用ZGC内存压缩
-XX:+ZGCCompressedOops
2.3 实战案例:生产环境JVM配置模板
以"4核8G服务器+高并发接口服务"为例,JVM配置如下(适配JDK8+G1):
bash
java -jar -Xms2g -Xmx2g -Xmn512m -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 \
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:DirectMemorySize=1g \
-XX:+UseG1GC -XX:ParallelGCThreads=4 -XX:ConcGCThreads=2 -XX:InitiatingHeapOccupancyPercent=70 \
-XX:MaxGCPauseMillis=100 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:./gc.log \
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heapdump.hprof your-app.jar
说明:
-
开启OOM自动dump堆内存,便于问题排查;
-
线程数配置与CPU核心数匹配,避免上下文切换频繁;
-
堆大小设置为2g,适配8G服务器(预留系统和其他组件内存)。
2.4 JVM调优避坑指南
-
避免设置-Xms≠-Xmx:会导致堆频繁扩容/缩容,增加GC压力;
-
避免新生代过大/过小:过大导致老年代变小,频繁Full GC;过小导致Minor GC频繁;
-
避免MaxTenuringThreshold设置过大:导致新生代对象长期存活,占用 Survivor 区;
-
禁止开启-XX:+UseConcMarkSweepGC(CMS):JDK9已废弃,高并发下容易出现卡顿;
-
必须开启GC日志:无日志无法定位内存问题,生产环境禁用-XX:+DisableExplicitGC。
3. 线程池配置优化与并发控制
线程池是Java并发编程的核心组件,合理配置线程池能避免线程频繁创建/销毁、资源耗尽等问题,高并发场景下需结合业务类型精准设计。
3.1 线程池核心参数设计原理
ThreadPoolExecutor核心参数(7个),决定线程池的工作机制:
-
corePoolSize:核心线程数(常驻线程),即使空闲也不销毁;
-
maximumPoolSize:最大线程数,核心线程满后可创建的最大临时线程;
-
keepAliveTime:临时线程空闲存活时间,超过时间则销毁;
-
unit:keepAliveTime时间单位(如TimeUnit.SECONDS);
-
workQueue:任务队列,核心线程满后存放任务的队列(如LinkedBlockingQueue);
-
threadFactory:线程工厂,用于创建线程(自定义线程名,便于排查);
-
handler:拒绝策略,任务队列满且线程数达最大值时的处理策略。
3.2 不同场景线程池配置方案
线程池配置需区分"CPU密集型"和"IO密集型"任务,核心公式:
-
CPU密集型(如计算、排序):线程数=CPU核心数+1(减少上下文切换);
-
IO密集型(如接口调用、数据库操作):线程数=CPU核心数×2(IO等待时线程可释放CPU)。
(1)CPU密集型线程池配置
java
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CpuIntensiveThreadPool {
// 获取CPU核心数
private static final int CPU_CORES = Runtime.getRuntime().availableProcessors();
public static ThreadPoolExecutor getInstance() {
return new ThreadPoolExecutor(
CPU_CORES + 1, // 核心线程数
CPU_CORES + 1, // 最大线程数(无临时线程)
0L, // 临时线程存活时间(无临时线程,设为0)
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(1024), // 任务队列(容量1024)
r -> new Thread(r, "cpu-pool-" + r.hashCode()), // 自定义线程名
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略(默认,抛异常)
);
}
}
(2)IO密集型线程池配置
java
public class IoIntensiveThreadPool {
private static final int CPU_CORES = Runtime.getRuntime().availableProcessors();
public static ThreadPoolExecutor getInstance() {
return new ThreadPoolExecutor(
CPU_CORES * 2, // 核心线程数
CPU_CORES * 4, // 最大线程数
60L, // 临时线程空闲60秒销毁
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(2048), // 任务队列(容量2048)
r -> new Thread(r, "io-pool-" + r.hashCode()),
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略(当前线程执行)
);
}
}
3.3 动态线程池实现(结合Nacos)
固定线程池参数无法适配高并发场景的流量波动,动态线程池可通过配置中心(Nacos)实时调整参数,无需重启服务。
(1)引入依赖(pom.xml)
xml
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
(2)动态线程池配置类
java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@RefreshScope // 开启配置动态刷新
public class DynamicThreadPoolConfig {
@Value("${thread-pool.core-size:8}")
private int coreSize;
@Value("${thread-pool.max-size:16}")
private int maxSize;
@Value("${thread-pool.keep-alive-seconds:60}")
private int keepAliveSeconds;
@Value("${thread-pool.queue-capacity:2048}")
private int queueCapacity;
@Bean
public ThreadPoolExecutor dynamicThreadPool() {
return new ThreadPoolExecutor(
coreSize,
maxSize,
keepAliveSeconds,
java.util.concurrent.TimeUnit.SECONDS,
new java.util.concurrent.LinkedBlockingQueue<Runnable>(queueCapacity),
r -> new Thread(r, "dynamic-pool-" + r.hashCode()),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
// 提供参数更新方法
public void updateThreadPoolParams(int coreSize, int maxSize, int keepAliveSeconds) {
ThreadPoolExecutor pool = dynamicThreadPool();
pool.setCorePoolSize(coreSize);
pool.setMaximumPoolSize(maxSize);
pool.setKeepAliveTime(keepAliveSeconds, java.util.concurrent.TimeUnit.SECONDS);
}
}
(3)Nacos配置(thread-pool-dev.yaml)
yaml
thread-pool:
core-size: 8
max-size: 16
keep-alive-seconds: 60
queue-capacity: 2048
3.4 线程池常见问题与解决方案
(1)任务队列溢出(OOM)
原因:队列容量设置过大,任务堆积过多导致内存溢出;
解决方案:使用有界队列(如LinkedBlockingQueue指定容量),搭配合理的拒绝策略。
(2)线程池耗尽(所有线程阻塞)
原因:IO密集型任务线程数不足,导致线程长期阻塞;
解决方案:增加最大线程数,设置合理的keepAliveTime,避免临时线程过早销毁。
(3)拒绝策略不合理
推荐拒绝策略选型:
-
核心业务:AbortPolicy(抛异常,快速失败);
-
非核心业务:CallerRunsPolicy(当前线程执行)或DiscardOldestPolicy(丢弃最旧任务);
-
禁止使用DiscardPolicy(静默丢弃任务,排查困难)。
(4)线程泄漏
原因:线程内任务长期阻塞(如死锁、无限循环),导致线程无法释放;
解决方案:使用线程监控工具(如Arthas)排查阻塞线程,设置任务超时时间(如Future.get(timeout))。
4. Redis缓存防护:穿透/击穿/雪崩
Redis作为高并发系统的核心缓存组件,能有效减轻数据库压力,但缓存失效场景(穿透、击穿、雪崩)会导致缓存雪崩,甚至数据库宕机,需针对性防护。
4.1 三大缓存问题场景剖析
| 问题类型 | 核心场景 | 危害 |
|----------|----------|------|
| 缓存穿透 | 查询不存在的key(如恶意攻击),缓存未命中,直接穿透到数据库 | 数据库压力暴增,可能宕机 |
| 缓存击穿 | 热点key(高并发查询)过期,大量请求同时穿透到数据库 | 数据库瞬间压力过大,热点接口延迟飙升 |
| 缓存雪崩 | 大量key同时过期,或Redis集群宕机,所有请求穿透到数据库 | 数据库雪崩,系统整体不可用 |
4.2 缓存穿透防护方案(布隆过滤器)
核心思路:提前过滤不存在的key,避免请求穿透到数据库,常用布隆过滤器(Bloom Filter)实现。
(1)布隆过滤器原理
布隆过滤器是一种概率型数据结构,通过多个哈希函数将key映射到bit数组,判断key是否存在(存在误判率,无漏判),适合存储海量key的存在性判断。
(2)Redis布隆过滤器实战
Redis 4.0+支持布隆过滤器插件(RedisBloom),以下为Java代码示例:
java
import org.redisson.Redisson;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class BloomFilterManager {
private RedissonClient redissonClient;
private RBloomFilter<String> bloomFilter;
// 初始化Redisson客户端
@PostConstruct
public void init() {
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");
redissonClient = Redisson.create(config);
// 初始化布隆过滤器(存储用户ID,预计100万数据,误判率0.01%)
bloomFilter = redissonClient.getBloomFilter("user:id:bloom");
bloomFilter.tryInit(1000000, 0.0001);
// 预加载已存在的用户ID到布隆过滤器(实际场景从数据库批量加载)
// bloomFilter.add("user1001");
// bloomFilter.add("user1002");
}
// 判断key是否存在(存在则返回true,不存在返回false)
public boolean contains(String key) {
return bloomFilter.contains(key);
}
// 新增key到布隆过滤器
public void add(String key) {
bloomFilter.add(key);
}
}
(3)缓存穿透防护流程
java
@Service
public class UserService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private BloomFilterManager bloomFilterManager;
@Autowired
private UserMapper userMapper;
public User getUserById(String userId) {
// 1. 布隆过滤器判断key是否存在,不存在直接返回null(避免穿透)
if (!bloomFilterManager.contains(userId)) {
return null;
}
// 2. 查询缓存
String key = "user:info:" + userId;
User user = (User) redisTemplate.opsForValue().get(key);
if (user != null) {
return user;
}
// 3. 缓存未命中,查询数据库(加互斥锁,避免击穿)
synchronized (userId.intern()) {
user = (User) redisTemplate.opsForValue().get(key);
if (user != null) {
return user;
}
// 数据库查询
user = userMapper.selectById(userId);
if (user != null) {
// 写入缓存(设置过期时间,避免雪崩)
redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES);
} else {
// 不存在的key写入空缓存(过期时间5分钟,避免重复穿透)
redisTemplate.opsForValue().set(key, null, 5, TimeUnit.MINUTES);
}
}
return user;
}
}
4.3 缓存击穿/雪崩防护实战
(1)缓存击穿防护(热点key)
方案1:互斥锁(synchronized/Redlock),确保只有一个线程查询数据库,其他线程等待;
方案2:热点key永不过期,通过后台线程定期更新缓存(适合不变或低频更新的热点数据);
方案3:缓存预热,系统启动时将热点key提前加载到缓存。
(2)缓存雪崩防护
方案1:过期时间随机化,避免大量key同时过期(如设置30±5分钟);
java
// 随机过期时间(30分钟±5分钟)
int expireTime = 30 * 60 + new Random().nextInt(10 * 60);
redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);
方案2:Redis集群部署(主从+哨兵/Cluster),避免单点故障;
方案3:缓存降级,Redis宕机时,通过熔断机制(如Sentinel)禁止查询缓存,返回默认值或服务降级提示;
方案4:多级缓存,增加本地缓存(如Caffeine),减少Redis依赖。
4.4 Redis缓存优化配置
生产环境Redis配置(避免缓存性能瓶颈):
yaml
spring:
redis:
host: localhost
port: 6379
password: 123456
lettuce:
pool:
max-active: 100 # 最大连接数
max-idle: 20 # 最大空闲连接
min-idle: 5 # 最小空闲连接
max-wait: 3000ms # 连接等待时间
shutdown-timeout: 1000ms
timeout: 3000ms # 连接超时时间
database: 0
# 开启Redis缓存统计(便于监控)
lettuce:
cluster:
refresh:
adaptive: true
period: 30000
cache:
type: redis
redis:
time-to-live: 3600000ms # 默认过期时间
cache-null-values: true # 缓存空值(防穿透)
use-key-prefix: true # 使用key前缀
5. 数据库分库分表实战
高并发场景下,单表数据量达到千万级后,查询性能会急剧下降,分库分表是解决数据量大、并发高的核心方案,通过拆分数据提升数据库吞吐量。
5.1 分库分表核心原理与场景
(1)核心原理
分库:按业务或哈希规则将数据库拆分到多个实例(如用户库拆分为user_db1、user_db2),减轻单库压力;
分表:将单张大数据表拆分为多个小表(如order表拆分为order_1、order_2),提升单表查询速度。
(2)适用场景
-
单表数据量>1000万;
-
数据库CPU/IO使用率持续>80%;
-
业务查询以单表为主,跨表查询较少。
5.2 分片策略选型(垂直/水平)
(1)垂直分片(按业务拆分)
规则:按业务模块拆分(如电商系统拆分为用户库、订单库、商品库);
优点:拆分简单,符合业务逻辑,便于维护;
缺点:存在跨库查询(如查询订单时关联用户),需通过分布式事务保证一致性。
(2)水平分片(按数据拆分)
规则:按字段哈希/范围拆分(如按用户ID哈希、按订单时间范围);
优点:单表数据量大幅减少,查询性能提升明显;
缺点:拆分规则复杂,需处理跨表分页、分布式事务等问题。
(3)分片键选择原则
-
选择查询频繁的字段(如用户ID、订单ID);
-
选择分布均匀的字段(避免数据倾斜);
-
避免使用频繁更新的字段(如订单状态)。
5.3 Sharding-JDBC实战配置
Sharding-JDBC是轻量级分库分表中间件,无需修改业务代码,通过配置即可实现分库分表,以下为"订单表水平分表"实战案例。
(1)引入依赖(pom.xml)
xml
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.16</version>
</dependency>
(2)分表配置(application.yml)
yaml
spring:
shardingsphere:
datasource:
names: ds0,ds1 # 数据源名称(分库时配置,本分表案例用单库)
ds0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/order_db?useUnicode=true&characterEncoding=utf8
username: root
password: root
rules:
sharding:
tables:
t_order: # 逻辑表名
actual-data-nodes: ds0.t_order_${0..1} # 实际表名(t_order_0、t_order_1)
table-strategy: # 分表策略
standard:
sharding-column: order_id # 分片键(订单ID)
sharding-algorithm-name: order_table_sharding # 分表算法
sharding-algorithms:
order_table_sharding: # 哈希分表算法
type: HASH_MOD
props:
sharding-count: 2 # 分表数量(2张表)
props:
sql-show: true # 显示分片SQL(便于调试)
(3)业务代码(无需修改,直接操作逻辑表)
java
@Mapper
public interface OrderMapper extends BaseMapper<Order> {
// 直接操作逻辑表t_order,Sharding-JDBC自动路由到实际表
}
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
public void createOrder(Order order) {
// 插入数据,自动路由到t_order_0或t_order_1
orderMapper.insert(order);
}
public Order getOrderById(Long orderId) {
// 查询数据,自动路由到对应分表
return orderMapper.selectById(orderId);
}
}
说明:通过HASH_MOD算法,订单ID%2=0路由到t_order_0,订单ID%2=1路由到t_order_1,实现水平分表。
5.4 分库分表后问题解决方案
(1)跨表查询问题
解决方案:使用Sharding-JDBC的关联查询功能,或引入Elasticsearch存储分表数据,通过ES实现跨表分页查询。
(2)分布式事务问题
解决方案:集成Seata分布式事务框架,保证分库分表后的数据一致性(参考Seata AT模式)。
(3)数据倾斜问题
原因:分片键选择不当,导致部分分表数据量过大;
解决方案:优化分片键(如按用户ID+时间哈希),或对热点分表进行二次拆分。
(4)主键唯一问题
解决方案:使用分布式ID生成器(如雪花算法、Redis自增),避免分表主键重复。
6. 高并发系统性能监控方案
高并发系统调优后,需建立完善的监控体系,实时感知性能瓶颈和故障,核心监控维度:
-
JVM监控:堆内存、非堆内存、GC频率、GC停顿时间(Prometheus+Grafana);
-
线程池监控:活跃线程数、任务队列长度、拒绝任务数(自定义监控指标+Actuator);
-
缓存监控:Redis命中率、连接数、内存使用率、缓存失效数;
-
数据库监控:慢查询、连接池状态、分库分表路由耗时;
-
全链路监控:SkyWalking追踪接口调用链路,定位慢接口和故障节点。
7. 总结与进阶方向
本文汇总Java高并发系统核心性能调优方案,从JVM参数调优、线程池配置、Redis缓存防护到数据库分库分表,覆盖高并发场景的核心瓶颈与解决方案,核心要点:
-
JVM调优:聚焦堆内存和GC收集器,避免OOM和频繁GC;
-
线程池调优:区分CPU/IO密集型任务,动态调整参数,避免线程泄漏;
-
Redis防护:布隆过滤器防穿透,互斥锁防击穿,随机过期防雪崩;
-
分库分表:优先垂直分片,合理选择分片键,用Sharding-JDBC快速落地。
进阶学习方向
-
分布式锁:Redis/ZooKeeper分布式锁实现,解决分布式环境下的并发安全问题;
-
异步编程:CompletableFuture、Netty异步模型,提升系统吞吐量;
-
服务治理:Sentinel流量控制、熔断降级,避免级联故障;
-
容器化部署:Docker+K8s部署高并发服务,实现弹性扩容。