clean-java-project-structure-意在clean&standard
断WAN手撕了一个平平无奇的秒杀系统,crud过载,赶紧多看看源码缓缓
秒杀系统实现 - 前言
在互联网高速发展的时代,电商平台的各种促销活动层出不穷,其中“秒杀”活动以其低价、限时、限量的特点吸引了大量用户,成为电商平台吸引流量、提升销量的有效手段。然而,秒杀系统由于其高并发、瞬间流量巨大的特点,对系统架构和技术选型提出了极高的要求。实现一个稳定、高效、公平的秒杀系统,并非易事。
秒杀系统的挑战:
- 高并发: 秒杀活动开启瞬间,会涌入海量请求,系统需要具备处理高并发请求的能力。
- 资源竞争: 多个用户同时抢购有限的商品,如何保证数据的一致性和避免超卖是关键问题。
- 性能瓶颈: 数据库、缓存、网络带宽等都可能成为系统的性能瓶颈,需要进行合理的优化和设计。
- 安全性: 秒杀系统容易成为攻击目标,需要防范恶意请求和刷单行为。
- 公平性: 如何保证所有用户都有公平的参与机会,防止机器人或恶意脚本抢占资源,也是一个重要挑战。
构建秒杀系统的关键点:
- 架构设计: 选择合适的架构模式,例如微服务架构、分布式架构,以应对高并发和海量数据。
- 缓存策略: 利用缓存技术减轻数据库压力,提高系统响应速度。
- 异步处理: 将一些耗时操作异步处理,例如订单生成、库存扣减等。
- 限流降级: 通过限流和降级策略,保护系统在高并发情况下不崩溃。
- 安全防护: 采用多种安全措施,例如验证码、风控系统等,防止恶意攻击和刷单行为。
- 公平性保障: 设计合理的抢购策略和算法,确保用户公平参与秒杀活动。
本系列文章将深入探讨秒杀系统的实现,涵盖以下内容:
- 需求分析与系统设计: 明确秒杀系统的功能需求、性能指标和技术选型。
- 高并发架构设计: 介绍如何利用负载均衡、分布式缓存、消息队列等技术构建高并发架构。
- 缓存策略与数据一致性: 探讨如何选择合适的缓存方案,并保证数据一致性。
- 异步处理与性能优化: 介绍如何利用异步处理技术提高系统性能和响应速度。
- 限流降级与熔断机制: 讨论如何设计限流、降级和熔断策略,保证系统稳定性。
- 安全防护与反作弊: 介绍如何利用验证码、风控系统等技术防范恶意攻击和刷单行为。
- 性能测试与调优: 通过性能测试发现系统瓶颈,并进行针对性的优化。
目标:
通过本系列文章,希望能够帮助读者理解秒杀系统的设计原理和实现方法,掌握构建高性能、高可用、安全可靠的秒杀系统的关键技术,并能够将其应用到实际项目中。
项目开发过程
1. 使用 Maven Archetype 创建新项目
-
打开终端/命令提示符:
输入mvn -v来验证安装maven是否安装。 -
运行 Maven 命令:
使用 Maven 的 Archetype 插件来生成一个新的项目结构。 Maven 提供了多种 Archetype,可以通过mvn archetype:generate命令查看和选择不同的模板。运行以下命令:mvn archetype:generate -DgroupId=com.example -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false这里的参数解释:
-DgroupId=com.example:指定项目的组 ID,一般是公司域名的倒序。-DartifactId=my-app:指定项目的唯一标识符。-DarchetypeArtifactId=maven-archetype-quickstart:使用的原型模板,maven-archetype-quickstart是一个简单的 Java 项目模板。-DinteractiveMode=false:非交互模式,避免在执行过程中询问输入。
-
项目结构:
运行上述命令后,Maven 会创建一个目录结构如下:my-app ├── pom.xml └── src ├── main │ └── java │ └── com │ └── example │ └── App.java └── test └── java └── com └── example └── AppTest.java -
项目配置文件 (
pom.xml):
pom.xml是 Maven 项目的核心配置文件,包含了项目的基本信息、依赖管理、构建信息等。 -
构建和运行项目:
- 构建项目: 在项目根目录下运行
mvn package,Maven 会编译代码并打包成一个 JAR 文件。 - 运行项目: 打包完成后,可以运行生成的 JAR 文件,或者直接使用
mvn springboot:run来运行(需要在pom.xml中配置springboot-maven-plugin插件)。
- 构建项目: 在项目根目录下运行
2.逐步写出项目结构和依赖配置:
- Maven依赖 (pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>seckill-system</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<properties>
<java.version>11</java.version>
<kafka.version>3.3.1</kafka.version>
<redisson.version>3.17.0</redisson.version>
<guava.version>31.1-jre</guava.version>
</properties>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Kafka -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<!-- Database -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
</dependency>
<!-- Utils -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 项目结构
seckill-system/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/seckill/
│ │ │ ├── SeckillApplication.java
│ │ │ ├── config/
│ │ │ │ ├── KafkaConfig.java
│ │ │ │ ├── RedisConfig.java
│ │ │ │ ├── RateLimitConfig.java
│ │ │ │ └── WebConfig.java
│ │ │ ├── controller/
│ │ │ │ └── SeckillController.java
│ │ │ ├── service/
│ │ │ │ ├── SeckillService.java
│ │ │ │ ├── OrderService.java
│ │ │ │ └── StockService.java
│ │ │ ├── consumer/
│ │ │ │ └── SeckillConsumer.java
│ │ │ ├── domain/
│ │ │ │ ├── Order.java
│ │ │ │ ├── Product.java
│ │ │ │ └── SeckillMessage.java
│ │ │ ├── repository/
│ │ │ │ ├── OrderRepository.java
│ │ │ │ └── ProductRepository.java
│ │ │ ├── exception/
│ │ │ │ ├── SeckillException.java
│ │ │ │ └── GlobalExceptionHandler.java
│ │ │ ├── monitor/
│ │ │ │ ├── SeckillMonitor.java
│ │ │ │ └── AlertService.java
│ │ │ └── util/
│ │ │ ├── JsonUtil.java
│ │ │ └── RedisUtil.java
│ │ └── resources/
│ │ ├── application.yml
│ │ ├── application-dev.yml
│ │ └── application-prod.yml
│ └── test/
│ └── java/
│ └── com/example/seckill/
│ ├── service/
│ │ └── SeckillServiceTest.java
│ └── controller/
│ └── SeckillControllerTest.java
├── pom.xml
└── README.md
- 配置文件 (application.yml)
spring:
application:
name: seckill-system
datasource:
url: jdbc:mysql://localhost:3306/seckill?useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
redis:
host: localhost
port: 6379
kafka:
bootstrap-servers: localhost:9092
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
batch-size: 16384
buffer-memory: 33554432
consumer:
group-id: seckill-group
auto-offset-reset: earliest
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
enable-auto-commit: false
server:
port: 8080
management:
endpoints:
web:
exposure:
include: "*"
metrics:
tags:
application: ${
spring.application.name}
seckill:
rateLimit:
enabled: true
permits-per-second: 1000
order:
timeout-minutes: 30
3.开始开发主要代码
不是全部代码,只是举例说明
这个秒杀系统实现了:
-
高并发支持(Kafka削峰)
-
库存一致性保证
-
防重复提交
-
限流保护
-
系统架构设计
@Configuration
public class SeckillConfig {
// 秒杀相关的Topic配置
public static final String SECKILL_TOPIC = "seckill-orders";
public static final String DEAD_LETTER_TOPIC = "seckill-dead-letter";
public static final String GROUP_ID = "seckill-group";
@Bean
public NewTopic seckillTopic() {
// 创建秒杀订单Topic,设置分区数和副本数
return TopicBuilder.name(SECKILL_TOPIC)
.partitions(3)
.replicas(2)
.build();
}
}
- 库存预热和检查
@Service
@Slf4j
public class StockService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private static final String STOCK_KEY = "seckill:stock:";
private static final String LOCK_KEY = "seckill:lock:";
// 预热库存到Redis
public void preloadStock(Long productId, Integer stock) {
String key = STOCK_KEY + productId;
redisTemplate.opsForValue().set(key, String.valueOf(stock));
}
// 检查并扣减库存
public boolean checkAndDeductStock(Long productId) {
String key = STOCK_KEY + productId;
String lockKey = LOCK_KEY + productId;
// 分布式锁
try {
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
// 检查库存
Long stock = redisTemplate.opsForValue()
.decrement(key);
if (stock != null && stock >= 0) {
return true;
} else {
// 库存不足,恢复库存
redisTemplate.opsForV


4709

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



