实战深入了解redis+消息队列如何实现秒杀
Posted 陈ོ努力
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实战深入了解redis+消息队列如何实现秒杀相关的知识,希望对你有一定的参考价值。
SpringBoot +Redis +RabbitMQ 实现高并发限时秒杀
所谓秒杀,从业务角度看,是短时间内多个用户“争抢”资源,这里的资源在大部分秒杀场景里是商品;将业务抽象,技术角度看,秒杀就是多个线程对资源进行操作,所以实现秒杀,就必须控制线程对资源的争抢,既要保证高效并发,也要保证操作的正确。
文章目录
开发环境
SpringBoot+mysql+maven+JDK8+RabbitMQ+Redis
测试环境
Jmeter测试工具
环境安装
安装RabbitMQ
docker安装:https://blog.csdn.net/qq_33612228/article/details/103732890
windows安装:https://blog.csdn.net/m0_37034294/article/details/82839494
需要安装mq的可视化工具
安装Redis
docker安装:https://blog.csdn.net/qq_33612228/article/details/10360918
windows安装:https://blog.csdn.net/qq_39135287/article/details/82686837
springboot整合redis:https://blog.csdn.net/qq_33612228/article/details/103700543
redis需要安装客户端,方便数据查看。
安装 Jmeter测试工具
windows安装:https://blog.csdn.net/liuyanh2006/article/details/82494548
mac安装: https://blog.csdn.net/zgy_boke/article/details/102689531
mac安装需要的Homebrew:https://blog.csdn.net/o_o814222198/article/details/120185851?spm=1001.2014.3001.5502
maven安装
mac安装:https://www.jianshu.com/p/191685a33786
window安装:https://www.cnblogs.com/eagle6688/p/7838224.html
代码模块
数据库设计
商品库存表:stock
CREATE TABLE `stock` (
`id` varchar(64) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`stock` varchar(255) DEFAULT NULL,
`remarks` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
`update_date` datetime DEFAULT NULL COMMENT '最后更新时间',
`create_date` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) NOT NULL DEFAULT '',
`create_by` varchar(64) NOT NULL DEFAULT '',
`del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '0正常,1删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='商品库存表';
秒杀订单表:t_order
CREATE TABLE `t_order` (
`id` varchar(64) NOT NULL,
`order_name` varchar(255) DEFAULT NULL,
`order_user` varchar(255) DEFAULT NULL,
`remarks` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
`update_date` datetime DEFAULT NULL COMMENT '最后更新时间',
`create_date` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) NOT NULL DEFAULT '',
`create_by` varchar(64) NOT NULL DEFAULT '',
`del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '0正常,1删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='秒杀订单表';
pom.xml
- 集成MybatisPlus
- fastjosn依赖
- Druid
- MyBatis增强工具
- lombok
- websocket
- 前端页面通过thymeleaf渲染
- 工具类包
- swagger-ui
- redis
- RabbitMQ
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>集成MybatisPlus</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<druid.version>1.1.14</druid.version>
<mysql-connector-java.version>8.0.11</mysql-connector-java.version>
<mybatis-plus-boot-starter.version>3.1.1</mybatis-plus-boot-starter.version>
<mybatis-plus-generator.version>3.1.1</mybatis-plus-generator.version>
<lombok.version>1.18.0</lombok.version>
<swagger.version>2.9.2</swagger.version>
<fastjson.version>1.2.47</fastjson.version>
<commons-text.version>1.6</commons-text.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--依赖管理-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.8.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector-java.version}</version>
</dependency>
<!--阿里巴巴fastjosn依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- Druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- MyBatis增强工具-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus-generator.version}</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- 前端页面通过thymeleaf渲染 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--工具类包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>${commons-text.version}</version>
</dependency>
<!--swagger-ui-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--RabbitMQ-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
- 数据源
- 端口号
- redis
- mq
- 扫描mapper文件
- 文件上传
- 页面模板
- log日志配置
spring:
datasource:
url: jdbc:mysql://182.92.210.212:3306/order_db?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
username: root
password: ***
# 使用Druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
data:
redis:
repositories:
enabled: false
redis:
database: 0 # redis数据库索引(默认为0),我们使用索引为其他(0-15)的数据库,避免和其他数据库冲突
host: 182.92.210.212
port: 6379
password: ***
rabbitmq: #mq配置
host: localhost
port: 5672
username: guest
password: guest
resources:
static-locations: classpath:/static #这个配置项告诉springboot去哪找资源 最关键的地方
profiles:
active: dev
servlet:
multipart:
enabled: true
max-file-size: 10MB #允许上传的文件大小
max-request-size: 10MB
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
encoding: UTF-8
mode: HTML5
context-type: text/html
mvc:
view:
prefix: /
suffix: .html
static-path-pattern: /** #这个配置告诉springboot,应该以什么方式去找资源,默认是/*
mybatis-plus:
mapper-locations: classpath*:com.example.demo.mapper/*.xml
global-config:
db-config:
id-type: uuid
field-strategy: not_null
refresh: true
configuration:
map-underscore-to-camel-case: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
server:
port: 8090
logging:
config: classpath:logback-spring.xml
logback-spring.xml
- 各级别日志分开打印,一个等级一个日志文件。
- 每天存档。
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>logback</contextName>
<property name="path" value="./log"/>
<property name="maxHistory" value="30"/>
<property name="maxFileSize" value="50MB"/>
<!--输出sql语句-->
<logger name="com.example.demo.mapper" level="debug"/>
<!--输出到控制台-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>-->
<encoder>
<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!--debug_file-->
<appender name="debug_file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${path}/logback_debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天一归档 -->
<fileNamePattern>${path}/logback_debug.log.%d{yyyy-以上是关于实战深入了解redis+消息队列如何实现秒杀的主要内容,如果未能解决你的问题,请参考以下文章
Redis基于(ListPubSubStream消费者组)实现消息队列,基于Stream结构实现异步秒杀下单
Redis个人笔记:Redis应用场景,Redis常见命令,Reids缓存击穿穿透,Redis分布式锁实现方案,秒杀设计思路,Redis消息队列,Reids持久化,Redis主从哨兵分片集群