feat:增加秒杀系统设计文档
This commit is contained in:
111
docs/Web/Others/Seckill.md
Normal file
111
docs/Web/Others/Seckill.md
Normal file
@@ -0,0 +1,111 @@
|
||||
---
|
||||
title: 秒杀系统设计与实战
|
||||
date: 2026-06-10
|
||||
---
|
||||
|
||||
# 一、简介
|
||||
  一个典型的秒杀系统通常采用 **限流 + 缓存 + 异步** 的架构:
|
||||
```plain
|
||||
客户端
|
||||
↓
|
||||
Nginx / 网关(限流)
|
||||
↓
|
||||
秒杀接口(校验、Redis 预扣库存)
|
||||
↓
|
||||
RocketMQ(下单消息)
|
||||
↓
|
||||
订单服务(创建订单、真正扣库存)
|
||||
↓
|
||||
MySQL
|
||||
```
|
||||
  **限流挡人、缓存决策、异步解耦**。
|
||||
|
||||
# 二、实战设计
|
||||
## 2.1 限流
|
||||
### 2.1.1 Nginx限流
|
||||
```conf
|
||||
# 定义规则
|
||||
limit_req_zone $binary_remote_addr zone=seckill:10m rate=5r/s;
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
location /seckill-api/ {
|
||||
# 启用限流
|
||||
limit_req zone=seckill burst=10 nodelay;
|
||||
|
||||
# 返回 429
|
||||
limit_req_status 429;
|
||||
|
||||
proxy_pass http://127.0.0.1:8080/;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
  `limit_req_zone`用来制定规则,`limit_req`表示启用规则,如果某个`location`没写,则不会启动规则。
|
||||
  `zone=seckill:10m`表示开辟一块`10MB`的内存,取名叫`seckill`,专门存`IP`访问记录,`rate=5r/s`表示每个`IP`每秒最多`5`个请求。
|
||||
  `limit_req zone=seckill`表示启动`seckill`规则,`burst=10`表示突发请求缓冲,`nodelay`表示超出后直接失败。
|
||||
|
||||
|
||||
::: tip
|
||||
`limit_req_zone`一定要写在`http`模块中,如果是`Linux`部署的,直接写在最外面。
|
||||
:::
|
||||
|
||||
::: warning
|
||||
Nginx限流只能防止单ip高刷,无法挡住大量不同IP的分布式攻击。
|
||||
:::
|
||||
|
||||
### 2.1.2 Semaphore限流
|
||||
  `Semaphore`是针对应用层限流,保护`JVM`,防止`Tomcat`线程池被打爆。
|
||||
```java
|
||||
private final Semaphore semaphore = new Semaphore(100);
|
||||
|
||||
if (!semaphore.tryAcquire()) {
|
||||
return ResponseEntity.status(429).body("系统繁忙");
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
} finally {
|
||||
semaphore.release();
|
||||
}
|
||||
```
|
||||
|
||||
  `new Semaphore(100)`表示最多`100`个线程同时进来,超过则直接返回失败,不会进入排队,也不会卡住线程。
|
||||
::: tip
|
||||
Semaphore不是全局限流,不具备分布式能力。
|
||||
:::
|
||||
|
||||
### 2.1.3 Redis限流
|
||||
```java
|
||||
String userKey = "seckill:user:" + userId;
|
||||
Boolean first = redis.opsForValue().setIfAbsent(userKey, "1", 60, TimeUnit.SECONDS);
|
||||
if (Boolean.FALSE.equals(first)) {
|
||||
return ResponseEntity.status(429).body("请勿重复尝试");
|
||||
}
|
||||
```
|
||||
  如果是限制每个用户只能限购一次,则可以将过期时间设置为永久。
|
||||
|
||||
## 2.2 缓存
|
||||
  先在`Redis`里面判断逻辑,然后再执行数据库。
|
||||
```java
|
||||
String stockKey = "seckill:stock:1";
|
||||
Long remain = redis.opsForValue().decrement(stockKey);
|
||||
if (remain == null || remain < 0) {
|
||||
redis.opsForValue().increment(stockKey);
|
||||
return ResponseEntity.status(200).body("已售罄");
|
||||
}
|
||||
```
|
||||
  要先减再判断,如果小于0,则表示已售罄,再回滚数据。
|
||||
|
||||
## 2.3 异步
|
||||
```java
|
||||
rocketMQTemplate.convertAndSend("seckill-order", Map.of("userId", userId, "goodsId", 1));
|
||||
return ResponseEntity.status(200).body("秒杀成功");
|
||||
```
|
||||
  Redis成功后则通过发消息通知消费者操作数据库。
|
||||
  为了防止重复创建订单,还需要进行一次幂等校验,即根据订单号的唯一性判断是否有重复的。
|
||||
|
||||
# 三、压测
|
||||
  采用ApiPost工具进行压测。
|
||||
@@ -7,6 +7,7 @@
|
||||
  Redis是一个高性能的开源内存数据库,用作缓存、数据库和消息中间件。它以极快的读写速度(基于内存存储)支持字符串、列表、哈希等多种数据结构。Redis提供数据持久化、主从复制、哨兵模式等高可用特性,广泛应用于缓存、会话存储、排行榜、消息队列等场景。
|
||||
|
||||
# 二、安装
|
||||
## 2.1 apt安装
|
||||
1. 通过apt包管理器安装:
|
||||
```bash
|
||||
sudo apt update
|
||||
@@ -25,6 +26,33 @@ requirepass password
|
||||
|
||||
  `systemctl restart redis-server`重启服务。
|
||||
|
||||
## 2.2 docker安装
|
||||
```yml
|
||||
services:
|
||||
redis:
|
||||
image: redis:8.6.4
|
||||
container_name: redis
|
||||
restart: always
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- ./redis.conf:/usr/local/etc/redis/redis.conf
|
||||
- ./data:/data
|
||||
command: redis-server /usr/local/etc/redis/redis.conf
|
||||
```
|
||||
|
||||
  redis.conf:
|
||||
```conf
|
||||
bind 0.0.0.0
|
||||
protected-mode yes
|
||||
port 6379
|
||||
|
||||
requirepass password
|
||||
```
|
||||
|
||||
## 2.3 客户端
|
||||
[Tiny RDM](https://redis.tinycraft.cc/zh/)
|
||||
|
||||
# 三、SpringBoot使用
|
||||
## 3.1 引入依赖
|
||||
```xml
|
||||
|
||||
100
docs/Web/SpringBoot/SpringBoot-RocketMQ.md
Normal file
100
docs/Web/SpringBoot/SpringBoot-RocketMQ.md
Normal file
@@ -0,0 +1,100 @@
|
||||
---
|
||||
title: SpringBoot RocketMQ简介和使用
|
||||
date: 2026-06-10
|
||||
---
|
||||
|
||||
# 一、简介
|
||||
  [RocketMQ](https://rocketmq.apache.org/zh/)Apache RocketMQ 是一款面向万亿级消息规模的 AI 原生异步通信引擎。诞生于阿里巴巴高并发电商场景,经过数千家企业的生产验证,RocketMQ 已从高性能消息队列演进为统一消息平台,横跨传统业务消息、事件流处理和新兴的 AI 原生通信三大范式。
|
||||
|
||||
# 二、安装
|
||||
## 2.1 docker安装
|
||||
```yml
|
||||
services:
|
||||
namesrv:
|
||||
image: apache/rocketmq:5.3.2
|
||||
container_name: rmqnamesrv
|
||||
ports:
|
||||
- 9876:9876
|
||||
networks:
|
||||
- rocketmq
|
||||
command: sh mqnamesrv
|
||||
broker:
|
||||
image: apache/rocketmq:5.3.2
|
||||
container_name: rmqbroker
|
||||
ports:
|
||||
- 10909:10909
|
||||
- 10911:10911
|
||||
- 10912:10912
|
||||
volumes:
|
||||
- ./broker.conf:/home/rocketmq/rocketmq-5.3.2/conf/broker.conf
|
||||
environment:
|
||||
- NAMESRV_ADDR=rmqnamesrv:9876
|
||||
depends_on:
|
||||
- namesrv
|
||||
networks:
|
||||
- rocketmq
|
||||
command: sh mqbroker -c /home/rocketmq/rocketmq-5.3.2/conf/broker.conf
|
||||
proxy:
|
||||
image: apache/rocketmq:5.3.2
|
||||
container_name: rmqproxy
|
||||
networks:
|
||||
- rocketmq
|
||||
depends_on:
|
||||
- broker
|
||||
- namesrv
|
||||
ports:
|
||||
- 8380:8080
|
||||
- 8381:8081
|
||||
restart: on-failure
|
||||
environment:
|
||||
- NAMESRV_ADDR=rmqnamesrv:9876
|
||||
command: sh mqproxy
|
||||
rocketmq-dashboard:
|
||||
image: apacherocketmq/rocketmq-dashboard:2.1.0
|
||||
container_name: rocketmq-dashboard
|
||||
environment:
|
||||
- JAVA_OPTS=-Drocketmq.namesrv.addr=rmqnamesrv:9876
|
||||
ports:
|
||||
- 8382:8082
|
||||
networks:
|
||||
- rocketmq
|
||||
depends_on:
|
||||
- namesrv
|
||||
restart: always
|
||||
networks:
|
||||
rocketmq:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
  broker.conf:
|
||||
```conf
|
||||
brokerIP1=192.168.1.100
|
||||
autoCreateTopicEnable=true
|
||||
```
|
||||
|
||||
::: tip
|
||||
这里一定要配置brokerIP1,否则Broker的地址是docker的内网地址,具体可以在控制台中查看Broker的地址。
|
||||
:::
|
||||
|
||||
# 三、SpringBoot使用
|
||||
## 3.1 引入依赖
|
||||
```xml
|
||||
<!-- RocketMQ -->
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-spring-boot-starter</artifactId>
|
||||
<version>2.3.6</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
::: tip
|
||||
需要加上版本号,SpringBoot3使用2.3以上的版本。
|
||||
:::
|
||||
|
||||
## 3.2 配置文件
|
||||
```yml
|
||||
rocketmq:
|
||||
name-server: 192.168.1.100:9876
|
||||
producer:
|
||||
group: seckill-producer-group
|
||||
```
|
||||
Reference in New Issue
Block a user