资讯详情

资讯详情

12306高并发架构解析:Redis分布式锁与消息队列实战

12306抢票系统作为全球最大的实时票务系统每年春运期间需要应对数百万用户同时在线抢票的极端高并发场景。这个由中国铁路总公司开发的系统其技术架构经历了多次迭代升级从最初的频繁崩溃到现在的稳定运行背后是一套完整的高并发解决方案。最值得关注的是12306系统通过分布式架构、缓存策略、消息队列和流量控制等多重技术手段成功解决了秒杀场景下的库存一致性、系统扩展性和用户体验等核心问题。本文将深入分析12306系统的高并发架构设计并给出可落地的技术实现方案。1. 核心能力速览能力项技术实现并发处理能力分布式集群架构支持百万级QPS数据一致性Redis分布式锁 数据库事务库存管理Redis原子操作 异步扣减流量控制令牌桶算法 分级限流系统扩展性微服务架构 弹性伸缩容灾能力多机房部署 故障自动切换2. 系统架构设计原理12306系统的高并发架构核心在于分层削峰的设计理念。整个系统采用典型的互联网分布式架构分为接入层、业务层和数据层。2.1 接入层设计接入层采用LVSNginx的负载均衡方案通过DNS轮询将用户请求分发到不同的机房。在这一层主要实现请求过滤识别恶意请求和爬虫静态资源缓存CSS、JS、图片等静态资源通过CDN加速SSL终端减轻后端服务器的加密解密负担2.2 业务层架构业务层采用微服务架构将系统拆分为用户服务、车次服务、订单服务、支付服务等独立模块。每个服务都可以独立部署和扩展通过服务注册发现机制实现动态负载均衡。// 伪代码示例车次查询服务 Service public class TrainQueryService { Autowired private RedisTemplate redisTemplate; public ListTrainInfo queryTrains(QueryCondition condition) { // 先查缓存 String cacheKey buildCacheKey(condition); ListTrainInfo cachedResult redisTemplate.opsForValue().get(cacheKey); if (cachedResult ! null) { return cachedResult; } // 缓存未命中查询数据库 ListTrainInfo dbResult trainMapper.queryByCondition(condition); // 写入缓存设置过期时间 redisTemplate.opsForValue().set(cacheKey, dbResult, 5, TimeUnit.MINUTES); return dbResult; } }2.3 数据层设计数据层采用分库分表策略按照用户ID、车次ID等进行数据分片。同时使用主从复制实现读写分离提高数据库的并发处理能力。3. Redis在抢票系统中的关键作用Redis作为高性能的内存数据库在12306系统中扮演着至关重要的角色。主要体现在以下几个方面3.1 库存缓存设计车票库存信息全部缓存在Redis中采用hash数据结构存储每个车次不同席别的余票数量。# Redis键值设计示例 train_seat:2024-02-10:G123:商务座 - 20 train_seat:2024-02-10:G123:一等座 - 100 train_seat:2024-02-10:G123:二等座 - 5003.2 分布式锁实现使用Redis实现分布式锁保证同一张车票不会被多个用户同时购买。public class DistributedLock { private static final String LOCK_PREFIX ticket_lock:; private static final int LOCK_EXPIRE 30; // 秒 public boolean tryLock(String ticketId, String requestId) { String lockKey LOCK_PREFIX ticketId; return redisTemplate.opsForValue() .setIfAbsent(lockKey, requestId, LOCK_EXPIRE, TimeUnit.SECONDS); } public void unlock(String ticketId, String requestId) { String lockKey LOCK_PREFIX ticketId; // 验证是否是自己持有的锁 if (requestId.equals(redisTemplate.opsForValue().get(lockKey))) { redisTemplate.delete(lockKey); } } }3.3 计数器限流使用Redis的incr命令实现接口限流防止恶意刷票。Service public class RateLimitService { private static final String RATE_LIMIT_KEY rate_limit:%s:%s; // 格式:接口:用户ID public boolean isAllowed(String apiKey, String userId, int limit, int period) { String key String.format(RATE_LIMIT_KEY, apiKey, userId); Long count redisTemplate.opsForValue().increment(key, 1); if (count 1) { // 第一次设置过期时间 redisTemplate.expire(key, period, TimeUnit.SECONDS); } return count limit; } }4. 消息队列的应用消息队列在12306系统中主要用于异步处理和削峰填谷。常见的应用场景包括4.1 订单异步处理用户提交订单后立即返回排队中状态实际的车票锁定和订单创建通过消息队列异步处理。Component public class OrderMessageProducer { Autowired private RabbitTemplate rabbitTemplate; public void sendOrderMessage(OrderRequest order) { rabbitTemplate.convertAndSend(order.queue, order); } } Component public class OrderMessageConsumer { RabbitListener(queues order.queue) public void processOrder(OrderRequest order) { try { // 实际处理订单逻辑 orderService.processOrder(order); } catch (Exception e) { // 处理失败进入死信队列 log.error(订单处理失败: {}, order.getOrderId(), e); } } }4.2 数据同步使用消息队列实现不同系统之间的数据同步比如订单数据同步到财务系统、统计分析系统等。5. 数据库优化策略5.1 分库分表设计按照用户ID进行分库每个库再按照时间维度分表。例如用户库_01、用户库_02...用户库_16订单表_202401、订单表_202402...5.2 读写分离主数据库负责写操作多个从数据库负责读操作。通过中间件实现自动的读写分离。# 数据库配置示例 spring: datasource: write: url: jdbc:mysql://master:3306/train username: root password: 123456 read: - url: jdbc:mysql://slave1:3306/train username: root password: 123456 - url: jdbc:mysql://slave2:3306/train username: root password: 1234565.3 索引优化针对高频查询条件建立合适的索引比如车次查询日期出发站到达站订单查询用户ID创建时间6. 流量控制与防护机制6.1 多层限流策略网关层限流针对IP地址和用户ID进行限流业务层限流针对具体接口进行限流数据层限流防止数据库被压垮6.2 排队机制在高峰期启用排队系统用户进入排队队列系统按照队列顺序处理请求。Component public class QueueService { private static final String QUEUE_KEY ticket_queue:; private static final int MAX_QUEUE_SIZE 100000; public long joinQueue(String trainDate, String trainNo, String userId) { String queueKey QUEUE_KEY trainDate : trainNo; Long rank redisTemplate.opsForZSet().rank(queueKey, userId); if (rank null) { // 新用户加入队列 redisTemplate.opsForZSet().add(queueKey, userId, System.currentTimeMillis()); rank redisTemplate.opsForZSet().rank(queueKey, userId); } return rank ! null ? rank 1 : -1; } }6.3 验证码机制在关键操作前加入验证码验证防止机器恶意刷票。7. 容灾与高可用设计7.1 多机房部署系统在多个机房部署通过全局负载均衡实现流量调度单个机房故障时自动切换到其他机房。7.2 数据备份与恢复实时备份数据库binlog实时同步到备份集群定时备份每天全量备份重要数据故障演练定期进行故障切换演练7.3 服务降级策略在系统压力过大时自动关闭非核心功能保证核心购票流程的可用性。8. 性能监控与优化8.1 全链路监控使用APM工具监控每个服务的性能指标包括响应时间、QPS、错误率等。8.2 日志收集分析通过ELK栈收集和分析系统日志及时发现和解决问题。8.3 容量规划根据历史数据和业务增长预测提前进行容量规划和技术升级。9. 实战部署方案9.1 环境准备部署12306类似系统需要准备以下环境负载均衡LVS/Nginx应用服务器Tomcat/Spring Boot缓存集群Redis哨兵或集群模式消息队列RabbitMQ/RocketMQ数据库MySQL集群监控系统PrometheusGrafana9.2 部署架构用户请求 - CDN - LVS - Nginx集群 - 应用集群 - Redis集群 - MySQL集群 - 消息队列 - 异步处理服务9.3 配置示例# Nginx配置示例 upstream app_servers { server 10.0.1.10:8080 weight3; server 10.0.1.11:8080 weight3; server 10.0.1.12:8080 weight2; } server { listen 80; server_name ticket.example.com; location / { proxy_pass http://app_servers; proxy_set_header X-Real-IP $remote_addr; # 限流配置 limit_req zoneapi burst10 nodelay; } # 静态资源缓存 location ~* \.(js|css|png|jpg)$ { expires 30d; add_header Cache-Control public; } }10. 常见问题与解决方案10.1 超卖问题问题现象同一张车票被多个用户购买成功解决方案使用Redis原子操作保证库存扣减的原子性数据库唯一索引防止重复订单分布式锁保证并发安全10.2 系统雪崩问题现象某个服务故障导致整个系统不可用解决方案服务熔断机制超时设置和重试策略资源隔离和限流10.3 数据不一致问题现象缓存和数据库数据不一致解决方案延迟双删策略基于binlog的缓存更新最终一致性设计11. 性能测试方案11.1 压力测试工具使用JMeter、wrk等工具模拟高并发场景测试系统极限性能。# wrk压力测试示例 wrk -t12 -c400 -d30s --latency http://ticket.example.com/api/query11.2 测试场景设计正常流量测试模拟日常访问模式峰值流量测试模拟春运抢票场景异常流量测试模拟恶意攻击和爬虫11.3 性能指标监控响应时间P50、P95、P99吞吐量QPS、TPS错误率HTTP错误、业务错误资源使用率CPU、内存、网络IO12. 安全防护措施12.1 网络安全DDoS防护使用云服务商的DDoS防护服务WAF防护Web应用防火墙过滤恶意请求网络隔离生产环境与测试环境网络隔离12.2 数据安全数据加密敏感数据加密存储访问控制基于角色的权限管理审计日志记录重要操作日志12.3 业务安全反爬虫机制识别和阻断爬虫请求人机验证关键操作前进行验证码验证风险控制识别异常操作行为12306抢票系统的高并发解决方案为其他秒杀类系统提供了宝贵的技术参考。在实际项目中需要根据具体业务场景选择合适的技
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →