MySQL性能优化
索引优化
为高频查询字段(如电影ID、场次时间、座位状态)添加复合索引,避免全表扫描。例如:
ALTER TABLE seats ADD INDEX idx_movie_showtime_status (movie_id, showtime, status);
分库分表
按电影ID或时间范围水平分表,减少单表数据量。采用Sharding-JDBC实现路由:
// Sharding配置示例
spring.shardingsphere.datasource.names=ds0,ds1
spring.shardingsphere.sharding.tables.seats.actual-data-nodes=ds$->{0..1}.seats_$->{0..15}
SQL优化
使用批量插入代替循环单条插入,减少网络IO:
String sql = "INSERT INTO seats (movie_id, row, col, status) VALUES (?,?,?,?)";
jdbcTemplate.batchUpdate(sql, seatList);
Redis缓存设计
热点数据缓存
使用Hash结构存储场次座位状态,Key格式:movie:{movieId}:showtime:{time}
// 写入缓存
redisTemplate.opsForHash().putAll("movie:1:showtime:19:00", seatStatusMap);
// 读取缓存
Map<Object, Object> seats = redisTemplate.opsForHash().entries("movie:1:showtime:19:00");
分布式锁
采用Redisson实现选座互斥锁,防止超卖:
RLock lock = redissonClient.getLock("seat_lock:" + seatId);
try {
lock.lock(5, TimeUnit.SECONDS);
// 处理选座逻辑
} finally {
lock.unlock();
}
事务控制方案
MySQL事务隔离
使用SELECT...FOR UPDATE悲观锁确保数据一致性:
BEGIN;
SELECT status FROM seats WHERE id=1001 FOR UPDATE;
UPDATE seats SET status='locked' WHERE id=1001;
COMMIT;
Redis+Lua原子操作
通过Lua脚本保证缓存操作的原子性:
local key = KEYS[1]
local seat = ARGV[1]
if redis.call('HGET', key, seat) == 'available' then
return redis.call('HSET', key, seat, 'locked')
end
return 0
高并发架构设计
异步处理
引入RabbitMQ削峰填谷,将选座请求异步化:
@RabbitListener(queues = "seat.queue")
public void processSeatRequest(SeatMessage message) {
// 异步处理订单
}
读写分离
通过MyCAT实现主从分离,查询走从库:
# MyCAT配置
schema name="cinema" checkSQLschema="false" sqlMaxLimit="100">
<table name="seats" primaryKey="id" type="global" dataNode="dn1,dn2"/>
</schema>
限流措施
使用Guava RateLimiter控制接口流量:
RateLimiter limiter = RateLimiter.create(1000); // QPS=1000
if (limiter.tryAcquire()) {
// 处理请求
}
监控与降级
Prometheus监控
暴露关键指标如MySQL查询延迟、Redis命中率:
@Bean
MeterRegistryCustomizer<PrometheusMeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags("application", "seat-service");
}
熔断降级
通过Hystrix保护数据库访问:
@HystrixCommand(fallbackMethod = "getSeatInfoFallback")
public Seat getSeatInfo(Long id) {
return seatMapper.selectById(id);
}
283

被折叠的 条评论
为什么被折叠?



