SpringBoot+MyBatis+Redis+MQ+Nginx
数据库的表
seckill:秒杀库存表,
CREATE TABLE `seckill` (
`seckill_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '商品库存ID',
`name` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '商品名称',
`number` int(11) NOT NULL COMMENT '库存数量',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`start_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '秒杀开始时间',
`end_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '秒杀结束时间',
PRIMARY KEY (`seckill_id`) USING BTREE,
INDEX `idx_start_time`(`start_time`) USING BTREE,
INDEX `idx_end_time`(`end_time`) USING BTREE,
INDEX `idx_create_time`(`create_time`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1000 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '秒杀库存表';
success_killed:秒杀成功明细表
CREATE TABLE `success_killed` (
`seckill_id` bigint(20) NOT NULL COMMENT '秒杀商品ID',
`user_phone` bigint(20) NOT NULL COMMENT '用户手机号',
`state` tinyint(4) NOT NULL DEFAULT -1 COMMENT '状态标识:-1:无效 0:成功 1:已付款 2:已发货',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`seckill_id`, `user_phone`) USING BTREE,
INDEX `idx_create_time`(`create_time`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '秒杀成功明细表';
搭建基础架构
yml配置
设置端口号 ,连接数据库
camel:开启驼峰命名转换,把数据库字段里下划线后的首个单词自动大写。
实现商品展示单页
Dao+XML
namespace指向Dao类
id是Dao中方法名
long对应要从外界传递进来的参数
resultType 返回的Goods对象
XML
DAO层
Service层
为什么不能直接从DAO到Controller?
为了解耦,虽然service层看起来好像啥也没干,但是它实现了controller层与DAO直接的松散耦合。
Controller层
压力测试
JMeter就是专门用来做压力测试的。
模拟100个用户,每个用户100次请求
Min最快响应时间,Max最长响应时间。
最重要的指标是吞吐量Throughput,这里的意思是每秒处理205个请求。
静态数据优化
这里redis是作为缓存去缓存那些不常修改的数据。
Redis
Redis常见面试问题
redis优点
速度快,因为数据存在内存中
支持事务,操作都是原子性
丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
1.redis有哪些数据类型
String(value可以是String也可以是数字)、hash()、list(可以有队列的功能)、set(无序的字符串集合,不存在重复的元素)、sorted set(相比于set能够按照score排序)
2.为什么说redis快(3点)
因为它是在内存中操作数据的,并且他不像多线程那样需要上下文切换,最后他采用了非阻塞I/O多路复用机制。
3.多路io复用
4.秒杀过程中怎么保证redis缓存和数据库的一致性
5.Redis 持久化机制
通过持久化机制把内存中的数据同步到硬盘文件来保证数据持久化。当Redis重启后通过把硬盘文件重新加载到内存,就能达到恢复数据的目的。
6.解决超卖问题的核心原因
Redis是单进程单线程的,Redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。
Redis有哪几种数据淘汰策略
POM中添加缓存依赖
Service层
Redis解决超卖问题
因为Redis是单线程的,所以可以拿来解决超卖问题:
主要逻辑就是List存秒杀商品的id,Set存秒杀成功的用户的id。一个商品被秒杀了,就弹出List,随后Set就进来一个用户id,这里会判断该用户id是否已经存在,若存在则抛异常,并且要给List补偿回一个商品id,这样就可以防止同一个用户秒杀到两次商品的情况。
Service层代码
这边要加入商品补偿机制。
MQ解决流量冲击
可能一次订单支付就要等5秒。
MQ就是一个数据的仓库,允许消费者一次只从MQ提取200,防止支付订单系统的宕机和塞车。
可以通过负载均衡把多个支付订单系统连接上MQ加大效率。
Order表
MQ是异步的,就是说消息从MQ发到消费者后,controller会立刻返回一个orderId给html页面,但是返回订单号不代表订单已经创建好了,秒杀页面还要定时检查订单创建好了没,好了就返回到order.ftl这个页面,如果没有就返回到wait.ftl继续等待。前端界面要每隔一段时间就要去查询后端处理的状态
Service层中加入发送消息的代码
消息封装成Map对象
yml中对MQ发送端的配置
消费者从MQ抽取消息
prefetch的数值是关键。一次拿10个消息,其他消息在MQ队列中等着。
Service层中消费者消费MQ消息的代码
Nignx负载均衡
Nignx是作第七层http的负载均衡。
Nginx配置文件的配置 config文件
把#去了,开启日志
负载均衡策略
Ngnix主要目的就是实现负载均衡
1轮询,就是让每台服务器按顺序轮流工作,实现负载均衡
2最少连接策略,就是筛选出当前连接数最少,负载最小的服务器去工作
3IP Hash 服务器和用户IP绑定,比如第一个用户是查询数据,第二个用户干的是数据的导入导出,这样就会导致第一个服务器压力很小,第二个服务器压力很大,所以一般不建议,并不能实现负载均衡。更多时候用到后端处理系统,同时使用人数不多,但是业务复杂的场景。
4权重策略,适用于多台服务器配置不一样的场景,尽量给配置高的服务器多分配一些工作量(能力强的多干活),即权重大的服务器处理的请求就多。
Nginx心跳检查机制
找到坏掉的那个服务器,如果请求发到某台服务器上,如上图中的配置,时间(fail_timeout)超过30秒没有响应,并且这样的情况出现次数(max_fails)达到了三次,那么我下次请求就不发到这个服务器了,这个服务器肯定是出现问题了,它就会被剔除。
设置好我们把8001服务器关了,来看看会发生什么。
日志文件
这里我们可以看到每次请求到8001服务器的时候,他都会报错504,并且把请求转发(回忆一下转发和重定向的区别)给其他服务器处理。
设置Ngnix集群实现Session共享
session存用户信息,在服务器中。
第一次我用户登录信息存在服务器1里面,我刷新一下可能就是服务器2工作了,但是我session信息还在服务器1里面,这不就出事了吗,又要重新登录可烦了。怎么解决呢?redis又来了
多台服务器共享redis中的数据,
技术实现
yml中对redis端口号设置
Controller层对Session的配置
Session的过期时间设置,实际是设置redis过期时间
Nginx静态资源的缓存
.css和.js这些静态资源,可以通过Nginx放到缓存(其实就是从本地文件读取出来)里,提高访问速度,不过动态资源还是需要交到Controller层去处理的。
具体实现方法:
先对config文件进行配置
Nginx资源压缩
带宽100mbps每个月就要交几百块给阿里云
由于带宽有限,Nginx的Gzip功能可以把数据返回给浏览器的时候,可以先对数据进行压缩,浏览器再去解压就行,
具体实现,也是去config里写
一般我们取压缩级别为1就行,压缩效果已经不错了。
利用CDN解决带宽问题
Nginx对图片的压缩效果不好,我们用阿里云的CDN。详细的以后再说吧,这里都是知识盲区了。