news 2026/2/12 10:41:45

淘宝秒杀系统架构实战 - 百万级并发技术方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
淘宝秒杀系统架构实战 - 百万级并发技术方案

一、业务场景分析

1.1 秒杀特点

  • 瞬时流量: 开场10秒内100万+请求
  • 读写比例: 1000:1 (99.9%用户抢不到)
  • 库存稀缺: 1000件商品,100万人抢
  • 强一致性: 不能超卖,不能少卖
  • 用户体验: P99延迟 < 200ms

1.2 核心技术挑战

100万并发 ↓

网关层(5万) 应用层(2万) 数据层(1万)

如何削峰? 如何防超卖? 如何不挂?


二、架构设计 - 五层防护体系

┌─────────────────────────────────────────┐

│ CDN + 前端限流 (第一层: 拦截90%无效请求) │ ├─────────────────────────────────────────┤

│ Nginx + OpenResty (第二层: 动态黑名单 + 令牌桶) │ ├─────────────────────────────────────────┤

│ 网关 Gateway (第三层: Sentinel限流熔断) │ ├─────────────────────────────────────────┤

│ 应用层 (第四层: Redis库存预扣 + Lua原子操作) │ ├─────────────────────────────────────────┤

│ 数据层 (第五层: 分库分表 + 异步落库 + 最终一致性) │ └─────────────────────────────────────────┘


三、核心技术方案

3.1 第一层: 前端拦截 - JS+页面静态化

3.1.1 秒杀页面静态化
  1. 倒计时控制 (开始前禁用按钮)
  2. 前端防刷 - Token Bucket
  3. 防重复提交 + 请求合并
  4. WebSocket + HTTP
  5. 防刷签名 (前端加签)
3.1.2 CDN预热脚本

3.2 第二层: Nginx + OpenResty 动态限流

3.2.1 Nginx配置
  1. IP黑名单拦截
  2. 令牌桶限流 (Lua实现)
  3. 静态资源缓存

nginx.conf

http { # 限流配置 lua_shared_dict ip_blacklist 10m; lua_shared_dict rate_limit_store 100m; # 连接池优化 upstream seckill_backend { least_conn; keepalive 1000; keepalive_requests 10000; server 10.0.1.10:8080 weight=5 max_fails=3 fail_timeout=30s; server 10.0.1.11:8080 weight=5 max_fails=3 fail_timeout=30s; server 10.0.1.12:8080 weight=5 max_fails=3 fail_timeout=30s; } server { listen 80; server_name seckill.taobao.com; # 1. IP黑名单拦截 access_by_lua_block { local ip = ngx.var.remote_addr local blacklist = ngx.shared.ip_blacklist if blacklist:get(ip) then ngx.exit(ngx.HTTP_FORBIDDEN) end } # 2. 令牌桶限流 (Lua实现) location /api/seckill { access_by_lua_file /etc/nginx/lua/rate_limit.lua; proxy_pass http://seckill_backend; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 超时配置 proxy_connect_timeout 1s; proxy_send_timeout 3s; proxy_read_timeout 3s; } # 3. 静态资源缓存 location ~* \.(jpg|jpeg|png|gif|css|js)$ { expires 1h; add_header Cache-Control "public, immutable"; } # 4. 健康检查 location /health { access_log off; return 200 "OK"; } } }

lua

-- /etc/nginx/lua/rate_limit.lua local resty_lock = require "resty.lock" local cjson = require "cjson" -- 配置参数 local rate_limit_store = ngx.shared.rate_limit_store local ip = ngx.var.remote_addr local uri = ngx.var.uri -- 多维度限流 local limits = { -- IP维度: 100 req/s {key = "ip:" .. ip, rate = 100, burst = 200}, -- URI维度: 5000 req/s (全局) {key = "uri:" .. uri, rate = 5000, burst = 10000}, -- 用户维度: 10 req/s {key = "user:" .. (ngx.var.cookie_userId or "anonymous"), rate = 10, burst = 20} } -- 令牌桶算法实现 local function check_rate_limit(key, rate, burst) local current_time = ngx.now() local data_key = "limiter:" .. key -- 获取或初始化桶状态 local bucket_data = rate_limit_store:get(data_key) local tokens, last_time if bucket_data then local decoded = cjson.decode(bucket_data) tokens = decoded.tokens last_time = decoded.last_time else tokens = burst last_time = current_time end -- 计算新增令牌 local elapsed = current_time - last_time tokens = math.min(burst, tokens + elapsed * rate) -- 尝试消费1个令牌 if tokens >= 1 then tokens = tokens - 1 rate_limit_store:set(data_key, cjson.encode({ tokens = tokens, last_time = current_time }), 10) return true else return false end end -- 检查所有限流规则 for _, limit in ipairs(limits) do if not check_rate_limit(limit.key, limit.rate, limit.burst) then ngx.log(ngx.WARN, "Rate limit exceeded: ", limit.key) ngx.header["X-RateLimit-Remaining"] = "0" ngx.status = 429 ngx.say(cjson.encode({ code = 429, message = "Too many requests", retryAfter = 1 })) ngx.exit(429) end end -- 动态黑名单 (连续失败5次) local fail_count_key = "fail:" .. ip local fail_count = rate_limit_store:get(fail_count_key) or 0 if fail_count >= 5 then local blacklist = ngx.shared.ip_blacklist blacklist:set(ip, true, 300) -- 封禁5分钟 ngx.exit(ngx.HTTP_FORBIDDEN) end

3.3 第三层: Spring Cloud Gateway 限流熔断

3.3.1 网关配置
package com.taobao.seckill.gateway.config; import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import reactor.core.publisher.Mono; @Configuration public class GatewayConfig { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("seckill_route", r -> r .path("/api/seckill/**") .filters(f -> f // 限流过滤器 .requestRateLimiter(c -> c .setRateLimiter(redisRateLimiter()) .setKeyResolver(userKeyResolver()) .setDenyEmptyKey(false)) // 熔断过滤器 .circuitBreaker(c -> c .setName("seckillCircuitBreaker") .setFallbackUri("forward:/fallback/seckill")) // 重试过滤器 .retry(c -> c .setRetries(2) .setStatuses(org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR)) // 请求日志 .filter(new RequestLogFilter()) ) .uri("lb://seckill-service") ) .build(); } @Bean public RedisRateLimiter redisRateLimiter() { return new RedisRateLimiter( 100, // replenishRate: 每秒填充速率 200, // burstCapacity: 桶容量 1 // requestedTokens: 每次消耗令牌数 ); } @Bean public KeyResolver userKeyResolver() { return exchange -> { String userId = exchange.getRequest() .getHeaders() .getFirst("X-User-Id"); return Mono.just(userId != null ? userId : exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()); }; } }
3.3.2 Sentinel熔断配置
package com.taobao.seckill.gateway.sentinel; import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants; import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition; import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem; import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule; import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager; import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.ServerResponse; import javax.annotation.PostConstruct; import java.util.*; @Configuration public class SentinelGatewayConfig { @PostConstruct public void init() { initApiDefinitions(); initGatewayRules(); initDegradeRules(); initBlockHandler(); } private void initApiDefinitions() { Set<ApiDefinition> definitions = new HashSet<>(); // 定义秒杀API组 ApiDefinition seckillApi = new ApiDefinition("seckill_api") .setPredicateItems(new HashSet<>() {{ add(new ApiPathPredicateItem() .setPattern("/api/seckill/buy/**") .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX)); }}); definitions.add(seckillApi); GatewayApiDefinitionManager.loadApiDefinitions(definitions); } private void initGatewayRules() { Set<GatewayFlowRule> rules = new HashSet<>(); // QPS限流: 5万/秒 GatewayFlowRule qpsRule = new GatewayFlowRule("seckill_api") .setCount(50000) .setIntervalSec(1) .setControlBehavior(0); // 快速失败 // 线程数限流: 500 GatewayFlowRule threadRule = new GatewayFlowRule("seckill_api") .setGrade(0) .setCount(500); rules.add(qpsRule); rules.add(threadRule); GatewayRuleManager.loadRules(rules); } private void initDegradeRules() { List<DegradeRule> rules = new ArrayList<>(); // 慢调用比例熔断 DegradeRule slowRule = new DegradeRule("seckill_api") .setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType()) .setCount(500) // RT阈值 500ms .setSlowRatioThreshold(0.6) // 慢调用比例 60% .setMinRequestAmount(20) .setStatIntervalMs(10000) // 统计窗口 10s .setTimeWindow(30); // 熔断时长 30s // 异常比例熔断 DegradeRule errorRule = new DegradeRule("seckill_api") .setGrade(CircuitBreakerStrategy.ERROR_RATIO.getType()) .setCount(0.5) // 异常比例 50% .setMinRequestAmount(10) .setStatIntervalMs(10000) .setTimeWindow(60); rules.add(slowRule); rules.add(errorRule); DegradeRuleManager.loadRules(rules); } private void initBlockHandler() { GatewayCallbackManager.setBlockHandler((exchange, t) -> ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS) .contentType(MediaType.APPLICATION_JSON) .body(BodyInserters.fromValue(Map.of( "code", 429, "message", "系统繁忙,已为您排队", "timestamp", System.currentTimeMillis(), "queuePosition", getQueuePosition() ))) ); } private int getQueuePosition() { // 模拟队列位置 return (int) (Math.random() * 10000); } }

3.4 第四层: 应用层 - Redis库存预扣减

3.4.1 秒杀核心Service
package com.taobao.seckill.service; import lombok.extern.slf4j.Slf4j; import org.redisson.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.stereotype.Service; import java.util.Collections; import java.util.concurrent.TimeUnit; @Slf4j @Service public class SeckillService { @Autowired private RedissonClient redisson; @Autowired private StringRedisTemplate redisTemplate; @Autowired private KafkaTemplate<String, String> kafkaTemplate; private static final String STOCK_KEY = "seckill:stock:"; private static final String USER_BUY_KEY = "seckill:user:"; private static final String ORDER_QUEUE = "seckill.order.queue"; /** * 方案1: Lua脚本原子操作 (推荐) */ public boolean seckillWithLua(Long productId, Long userId) { String stockKey = STOCK_KEY + productId; String userKey = USER_BUY_KEY + productId; // Lua脚本: 库存扣减 + 用户去重 + 限购 String luaScript = "local stock = redis.call('get', KEYS[1]) " + "if not stock or tonumber(stock) <= 0 then " + " return {0, 'SOLD_OUT'} " + "end " + "local userBuyCount = redis.call('hget', KEYS[2], ARGV[1]) " + "if userBuyCount and tonumber(userBuyCount) >= tonumber(ARGV[3]) then " + " return {-1, 'LIMIT_EXCEEDED'} " + "end " + "redis.call('decr', KEYS[1]) " + "redis.call('hincrby', KEYS[2], ARGV[1], 1) " + "redis.call('expire', KEYS[2], ARGV[2]) " + "return {1, 'SUCCESS'}"; DefaultRedisScript<List> script = new DefaultRedisScript<>(); script.setScriptText(luaScript); script.setResultType(List.class); List<Object> result = redisTemplate.execute( script, Arrays.asList(stockKey, userKey), userId.toString(), "86400", // 24小时过期 "1" // 限购1件 ); if (result == null || (Long) result.get(0) <= 0) { log.warn("秒杀失败: userId={}, productId={}, reason={}", userId, productId, result != null ? result.get(1) : "UNKNOWN"); return false; } // 异步创建订单 (发送Kafka消息) sendOrderMessage(productId, userId); return true; } /** * 方案2: Redisson分布式信号量 */ public boolean seckillWithSemaphore(Long productId, Long userId) { String semaphoreKey = "seckill:semaphore:" + productId; RSemaphore semaphore = redisson.getSemaphore(semaphoreKey); // 初始化信号量 (库存数量) if (!semaphore.isExists()) { semaphore.trySetPermits(10000); } // 尝试获取许可 boolean acquired = semaphore.tryAcquire(100, TimeUnit.MILLISECONDS); if (!acquired) { log.info("库存不足: productId={}", productId); return false; } try { // 用户去重检查 if (hasBought(productId, userId)) { semaphore.release(); return false; } // 异步创建订单 sendOrderMessage(productId, userId); return true; } catch (Exception e) { // 异常回滚信号量 semaphore.release(); throw e; } } /** * 方案3: RedissonRateLimiter + 布隆过滤器 */ public boolean seckillWithBloomFilter(Long productId, Long userId) { // 1. 布隆过滤器拦截无效用户 RBloomFilter<String> bloomFilter = redisson.getBloomFilter("seckill:valid:users"); if (!bloomFilter.contains(userId.toString())) { log.warn("非法用户: userId={}", userId); return false; } // 2. 用户级别限流 RRateLimiter userLimiter = redisson.getRateLimiter("user:limit:" + userId); if (!userLimiter.tryAcquire(1, 0, TimeUnit.SECONDS)) { log.warn("用户请求过快: userId={}", userId); return false; } // 3. Lua脚本扣减库存 return seckillWithLua(productId, userId); } /** * 库存预热 (秒杀开始前) */ public void warmUpStock(Long productId, Integer stock) { String stockKey = STOCK_KEY + productId; redisTemplate.opsForValue().set(stockKey, stock.toString(), 1, TimeUnit.HOURS); // 初始化布隆过滤器 RBloomFilter<String> bloomFilter = redisson.getBloomFilter("seckill:valid:users"); bloomFilter.tryInit(10000000, 0.01); // 1000万用户,1%误判率 log.info("库存预热完成: productId={}, stock={}", productId, stock); } /** * 库存回补 (订单取消/超时) */ public void replenishStock(Long productId, Integer quantity) { String stockKey = STOCK_KEY + productId; redisTemplate.opsForValue().increment(stockKey, quantity); log.info("库存回补: productId={}, quantity={}", productId, quantity); } private boolean hasBought(Long productId, Long userId) { String userKey = USER_BUY_KEY + productId; return redisTemplate.opsForHash().hasKey(userKey, userId.toString()); } private void sendOrderMessage(Long productId, Long userId) { String message = String.format("{\"productId\":%d,\"userId\":%d,\"timestamp\":%d}", productId, userId, System.currentTimeMillis()); kafkaTemplate.send(ORDER_QUEUE, message); log.info("订单消息已发送: {}", message); } }
3.4.2 秒杀Controller
package com.taobao.seckill.controller; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import com.taobao.seckill.annotation.AccessLimit; import com.taobao.seckill.service.SeckillService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.Map; @Slf4j @RestController @RequestMapping("/api/seckill") public class SeckillController { @Autowired private SeckillService seckillService; /** * 秒杀抢购接口 */ @PostMapping("/buy/{productId}") @AccessLimit(seconds = 1, maxCount = 5) // 自定义限流注解 @SentinelResource( value = "seckill-buy", blockHandler = "buyBlockHandler", fallback = "buyFallback" ) public Map<String, Object> buy( @PathVariable Long productId, @RequestHeader("X-User-Id") Long userId, HttpServletRequest request ) { // 防刷校验 if (!validateRequest(request, userId)) { return error(403, "非法请求"); } // 秒杀逻辑 boolean success = seckillService.seckillWithLua(productId, userId); if (success) { return success("抢购成功,订单生成中"); } else { return error(400, "商品已抢完或您已购买"); } } /** * Sentinel限流降级处理 */ public Map<String, Object> buyBlockHandler( Long productId, Long userId, HttpServletRequest request, BlockException ex ) { log.warn("触发限流: userId={}, productId={}", userId, productId); return error(429, "系统繁忙,已为您排队,请稍后查看订单"); } /** * 异常兜底 */ public Map<String, Object> buyFallback( Long productId, Long userId, HttpServletRequest request, Throwable ex ) { log.error("秒杀异常: userId={}, productId={}", userId, productId, ex); return error(500, "系统异常,请稍后重试"); } /** * 查询库存 (SSE推送) */ @GetMapping(value = "/stock/{productId}", produces = "text/event-stream") public SseEmitter getStock(@PathVariable Long productId) { SseEmitter emitter = new SseEmitter(60000L); // 定时推送库存 ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); executor.scheduleAtFixedRate(() -> { try { String stock = redisTemplate.opsForValue().get("seckill:stock:" + productId); emitter.send(SseEmitter.event() .name("stock") .data(Map.of("stock", stock != null ? stock : "0"))); } catch (Exception e) { emitter.completeWithError(e); executor.shutdown(); } }, 0, 500, TimeUnit.MILLISECONDS); emitter.onCompletion(executor::shutdown); emitter.onTimeout(executor::shutdown); return emitter; } private boolean validateRequest(HttpServletRequest request, Long userId) { // 1. 验证签名 String timestamp = request.getHeader("X-Timestamp"); String nonce = request.getHeader("X-Nonce"); String sign = request.getHeader("X-Sign"); if (timestamp == null || nonce == null || sign == null) { return false; } // 2. 时间戳校验 (5秒内有效) long requestTime = Long.parseLong(timestamp); if (Math.abs(System.currentTimeMillis() - requestTime) > 5000) { return false; } // 3. 签名校验 String expectedSign = DigestUtils.md5Hex(userId + timestamp + nonce + "SECRET_KEY"); return sign.equals(expectedSign); } private Map<String, Object> success(String message) { return Map.of("code", 200, "message", message, "timestamp", System.currentTimeMillis()); } private Map<String, Object> error(int code, String message) { return Map.of("code", code, "message", message, "timestamp", System.currentTimeMillis()); } }
3.4.3 自定义限流注解
package com.taobao.seckill.annotation; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AccessLimit { int seconds() default 1; int maxCount() default 5; boolean needLogin() default true; }
package com.taobao.seckill.aspect; import com.taobao.seckill.annotation.AccessLimit; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.util.concurrent.TimeUnit; @Slf4j @Aspect @Component public class AccessLimitAspect { @Autowired private StringRedisTemplate redisTemplate; @Before("@annotation(accessLimit)") public void before(JoinPoint joinPoint, AccessLimit accessLimit) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String userId = request.getHeader("X-User-Id"); if (accessLimit.needLogin() && userId == null) { throw new RuntimeException("请先登录"); } String key = "access:limit:" + request.getRequestURI() + ":" + userId; Integer count = (Integer) redisTemplate.opsForValue().get(key); if (count == null) { redisTemplate.opsForValue().set(key, "1", accessLimit.seconds(), TimeUnit.SECONDS); } else if (count < accessLimit.maxCount()) { redisTemplate.opsForValue().increment(key); } else { log.warn("访问限流: userId={}, uri={}", userId, request.getRequestURI()); throw new RuntimeException("访问过于频繁"); } } }

3.5 第五层: 数据层 - 异步落库 + 分库分表

3.5.1 Kafka消费者 (订单创建)
java package com.taobao.seckill.consumer; import com.alibaba.fastjson.JSON; import com.taobao.seckill.entity.SeckillOrder; import com.taobao.seckill.mapper.SeckillOrderMapper; import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.kafka.support.Acknowledgment; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @Slf4j @Component public class SeckillOrderConsumer { @Autowired private SeckillOrderMapper orderMapper; @Autowired private RedissonClient redisson; private final List<SeckillOrder> batchBuffer = new ArrayList<>(1000); /** * 消费秒杀订单消息 (批量插入优化) */ @KafkaListener( topics = "seckill.order.queue", groupId = "seckill-order-group", concurrency = "10", properties = { "max.poll.records=100", "fetch.min.bytes=1048576" // 1MB } ) public void consumeOrder(List<ConsumerRecord<String, String>> records, Acknowledgment ack) { log.info("接收到{}条订单消息", records.size()); try { for (ConsumerRecord<String, String> record : records) { SeckillOrder order = parseOrder(record.value()); // 幂等性检查 (防止重复消费) if (isOrderExists(order.getOrderId())) { continue; } batchBuffer.add(order); // 批量插入 (每1000条刷一次) if (batchBuffer.size() >= 1000) { batchInsertOrders(); } } // 剩余订单刷库 if (!batchBuffer.isEmpty()) { batchInsertOrders(); } // 手动提交offset ack.acknowledge(); } catch (Exception e) { log.error("订单消费失败", e); // 不ACK,触发重试 } } @Transactional(rollbackFor = Exception.class) public void batchInsertOrders() { if (batchBuffer.isEmpty()) { return; } try { // MyBatis批量插入 orderMapper.batchInsert(batchBuffer); log.info("批量插入订单成功: count={}", batchBuffer.size()); // 写入幂等表 for (SeckillOrder order : batchBuffer) { cacheOrderId(order.getOrderId()); } } finally { batchBuffer.clear(); } } private SeckillOrder parseOrder(String message) { Map<String, Object> map = JSON.parseObject(message, Map.class); SeckillOrder order = new SeckillOrder(); order.setOrderId(generateOrderId()); order.setProductId(Long.valueOf(map.get("productId").toString())); order.setUserId(Long.valueOf(map.get("userId").toString())); order.setStatus(0); // 待支付 order.setCreateTime(new Date()); return order; } private String generateOrderId() { // 雪花算法生成订单号 return String.valueOf(System.currentTimeMillis()) + String.format("%06d", (int) (Math.random() * 1000000)); } private boolean isOrderExists(String orderId) { RBucket<String> bucket = redisson.getBucket("order:exists:" + orderId); return bucket.isExists(); } private void cacheOrderId(String orderId) { RBucket<String> bucket = redisson.getBucket("order:exists:" + orderId); bucket.set("1", 1, TimeUnit.HOURS); } }
3.5.2 ShardingSphere分库分表配置

application-sharding.yml

spring: shardingsphere: datasource: names: ds0,ds1,ds2,ds3 ds0: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver jdbc-url: jdbc:mysql://db0.taobao.com:3306/seckill_0?useSSL=false username: root password: xxx hikari: maximum-pool-size: 50 minimum-idle: 10 connection-timeout: 3000 ds1: type: com.zaxxer.hikari.HikariDataSource jdbc-url: jdbc:mysql://db1.taobao.com:3306/seckill_1?useSSL=false hikari: maximum-pool-size: 50 ds2: jdbc-url: jdbc:mysql://db2.taobao.com:3306/seckill_2?useSSL=false ds3: jdbc-url: jdbc:mysql://db3.taobao.com:3306/seckill_3?useSSL=false sharding: default-database-strategy: inline: sharding-column: user_id algorithm-expression: ds$->{user_id % 4} tables: seckill_order: actual-data-nodes: ds$->{0..3}.seckill_order_$->{0..15} table-strategy: inline: sharding-column: user_id algorithm-expression: seckill_order_$->{user_id % 16} key-generator: column: id type: SNOWFLAKE props: worker.id: ${server.port} binding-tables: seckill_order,seckill_order_item broadcast-tables: seckill_product props: sql.show: false executor.size: 50

3.6 数据核对


四、压测监控策略

4.1 压测方案

4.1.1 JMeter压测脚本
4.1.2 压测场景设计

场景1: 预热测试 (1000并发,持续30秒)

jmeter -n -t warmup.jmx -Jthreads=1000 -Jrampup=10 -Jduration=30 -l warmup_result.jtl

场景2: 常规压测 (5000并发,持续60秒)

jmeter -n -t normal.jmx -Jthreads=5000 -Jrampup=20 -Jduration=60 -l normal_result.jtl

场景3: 极限压测 (20000并发,持续120秒)

jmeter -n -t extreme.jmx -Jthreads=20000 -Jrampup=30 -Jduration=120 -l extreme_result.jtl

4.2 监控体系

4.2.1 Prometheus监控配置
4.2.2 Grafana Dashboard配置
4.2.3 自定义业务指标
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/11 9:02:46

vLLM 0.11.0 发布:全面移除 V0 引擎,性能与多模态支持再升级

vLLM 0.11.0 发布&#xff1a;全面移除 V0 引擎&#xff0c;性能与多模态支持再升级 在大模型推理系统持续演进的今天&#xff0c;架构统一和效率提升已成为决定技术落地成败的关键。vLLM 0.11.0 的发布正是这一趋势下的里程碑式突破——V0 推理引擎正式退出历史舞台&#xff…

作者头像 李华
网站建设 2026/2/9 19:40:49

从零开始:使用Git安装TensorRT及其依赖组件

从零开始&#xff1a;使用Git安装TensorRT及其依赖组件 在智能摄像头实时识别行人、车载系统毫秒级响应路况的今天&#xff0c;AI模型的“推理速度”早已不再是锦上添花的优化项&#xff0c;而是决定产品能否落地的关键瓶颈。许多团队在PyTorch或TensorFlow中训练出高精度模型后…

作者头像 李华
网站建设 2026/2/7 18:12:13

模块十八.集合

1.集合框架&#xff08;单列集合&#xff09;2.Collection接口3.迭代器1.迭代器基本使用NoSuchElementException:没有可操作的元素异常2.迭代器底层原理1.获取Iterator的时候怎么获取的&#xff1a;Iterator iterator list.iterator( )我们知道Iterator是一个接口&#xff0c;…

作者头像 李华
网站建设 2026/2/11 13:19:13

FLUX.1-dev服装生成LoRA模型体验

FLUX.1-dev服装生成LoRA模型体验 最近在折腾一个基于 FLUX.1-dev 的服装设计 LoRA&#xff0c;结果有点上头。 这玩意儿真能靠一句话就把衣服从概念变出来——不是那种“看着像”的模糊轮廓&#xff0c;而是连丝绸反光的方向、刺绣纹样的走势、拉链位置的合理性都能交代清楚。你…

作者头像 李华
网站建设 2026/2/12 0:29:00

使用nexus3搭建自己的制品服务器

使用nexus3搭建自己的制品服务器 需求 云原生开发&#xff0c;有个新的需求&#xff0c;就是docker制品服务器&#xff0c;对于私域的开发&#xff0c;公有云的服务器不合适&#xff0c;只能自己搭建了。 所以记录一下搭建一个docker镜像服务器的过程&#xff0c;完成的功能…

作者头像 李华
网站建设 2026/2/8 19:52:25

38、Linux 邮件与网页浏览实用指南

Linux 邮件与网页浏览实用指南 在 Linux 系统中,邮件管理和网页浏览是日常使用中非常重要的功能。下面将详细介绍相关的工具和操作方法。 邮件管理 查看邮件文件夹 可以使用 less 查看邮件文件夹,也能在文本编辑器中编辑。不过,文件夹会显示为一个包含所有邮件的长滚动…

作者头像 李华