clean-java-project-structure-实现秒杀系统

clean-java-project-structure-意在clean&standard
断WAN手撕了一个平平无奇的秒杀系统,crud过载,赶紧多看看源码缓缓

秒杀系统实现 - 前言

在互联网高速发展的时代,电商平台的各种促销活动层出不穷,其中“秒杀”活动以其低价、限时、限量的特点吸引了大量用户,成为电商平台吸引流量、提升销量的有效手段。然而,秒杀系统由于其高并发、瞬间流量巨大的特点,对系统架构和技术选型提出了极高的要求。实现一个稳定、高效、公平的秒杀系统,并非易事。

秒杀系统的挑战:

  • 高并发: 秒杀活动开启瞬间,会涌入海量请求,系统需要具备处理高并发请求的能力。
  • 资源竞争: 多个用户同时抢购有限的商品,如何保证数据的一致性和避免超卖是关键问题。
  • 性能瓶颈: 数据库、缓存、网络带宽等都可能成为系统的性能瓶颈,需要进行合理的优化和设计。
  • 安全性: 秒杀系统容易成为攻击目标,需要防范恶意请求和刷单行为。
  • 公平性: 如何保证所有用户都有公平的参与机会,防止机器人或恶意脚本抢占资源,也是一个重要挑战。

构建秒杀系统的关键点:

  • 架构设计: 选择合适的架构模式,例如微服务架构、分布式架构,以应对高并发和海量数据。
  • 缓存策略: 利用缓存技术减轻数据库压力,提高系统响应速度。
  • 异步处理: 将一些耗时操作异步处理,例如订单生成、库存扣减等。
  • 限流降级: 通过限流和降级策略,保护系统在高并发情况下不崩溃。
  • 安全防护: 采用多种安全措施,例如验证码、风控系统等,防止恶意攻击和刷单行为。
  • 公平性保障: 设计合理的抢购策略和算法,确保用户公平参与秒杀活动。

本系列文章将深入探讨秒杀系统的实现,涵盖以下内容:

  • 需求分析与系统设计: 明确秒杀系统的功能需求、性能指标和技术选型。
  • 高并发架构设计: 介绍如何利用负载均衡、分布式缓存、消息队列等技术构建高并发架构。
  • 缓存策略与数据一致性: 探讨如何选择合适的缓存方案,并保证数据一致性。
  • 异步处理与性能优化: 介绍如何利用异步处理技术提高系统性能和响应速度。
  • 限流降级与熔断机制: 讨论如何设计限流、降级和熔断策略,保证系统稳定性。
  • 安全防护与反作弊: 介绍如何利用验证码、风控系统等技术防范恶意攻击和刷单行为。
  • 性能测试与调优: 通过性能测试发现系统瓶颈,并进行针对性的优化。

目标:

通过本系列文章,希望能够帮助读者理解秒杀系统的设计原理和实现方法,掌握构建高性能、高可用、安全可靠的秒杀系统的关键技术,并能够将其应用到实际项目中。

项目开发过程

1. 使用 Maven Archetype 创建新项目

  1. 打开终端/命令提示符:
    输入 mvn -v 来验证安装maven是否安装。

  2. 运行 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:非交互模式,避免在执行过程中询问输入。
  3. 项目结构:
    运行上述命令后,Maven 会创建一个目录结构如下:

    my-app
    ├── pom.xml
    └── src
        ├── main
        │   └── java
        │       └── com
        │           └── example
        │               └── App.java
        └── test
            └── java
                └── com
                    └── example
                        └── AppTest.java
    
  4. 项目配置文件 (pom.xml):
    pom.xml 是 Maven 项目的核心配置文件,包含了项目的基本信息、依赖管理、构建信息等。

  5. 构建和运行项目:

    • 构建项目: 在项目根目录下运行 mvn package,Maven 会编译代码并打包成一个 JAR 文件。
    • 运行项目: 打包完成后,可以运行生成的 JAR 文件,或者直接使用 mvn springboot:run 来运行(需要在 pom.xml 中配置 springboot-maven-plugin 插件)。

2.逐步写出项目结构和依赖配置:

  1. 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>
  1. 项目结构
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
  1. 配置文件 (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.开始开发主要代码

不是全部代码,只是举例说明

这个秒杀系统实现了:

  1. 高并发支持(Kafka削峰)

  2. 库存一致性保证

  3. 防重复提交

  4. 限流保护

  5. 系统架构设计

@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();
    }
}
  1. 库存预热和检查
@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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值