本地课程中,项目是部署在本地电脑上,实战课程中部署在阿里云主机上
数据层
1.用户注册功能 register
点击注册按钮,填入用户信息(含手机验证码),往用户表中插入一条数据
2.用户登录功能 login
传入手机号和密码,如果传入的密码和从数据库中查出来的手机号对应的密码不相等就登陆失败
商品表item:商品id,商品名称title,商品价格price,商品库存 stock,商品描述description,商品销量sales,商品图片img_varchar,秒杀状态promoStatus:0表示该商品没有秒杀活动,1表示秒杀活动待开始,2表示秒杀活动正在进行中,3表示秒杀活动已结束
3.往商品表中插入一条商品insertitem,展示商品列表listitem,商品详情展示getitem
订单表order:订单编号id,userid哪个用户下单的,购买的数量amount,订单金额orderAmount,购买商品的单价itemprice(秒杀价格和平时的价格不一样)
4.创建订单createOrder
传入商品的itemid,数量amount两个参数
先减库存,然后往订单表中插入一条数据
秒杀表promo
秒杀id,活动名称promoName,秒杀开始时间startDate,秒杀结束时间endDate,参与秒杀活动的商品id:item_id,参与秒杀活动商品的价格promoItemPrice
当前时间和startDate,endDate作比较,status=1,表示秒杀活动未开始,status=2,表示活动进行中,status=3表示活动结束
比如下面这样一条记录:
秒杀id:1
活动名称promoName:iphone4抢购活动
秒杀开始时间startDate:2018-11-18 23:45:00
参与秒杀活动的商品id,item_id:6
参与秒杀活动商品的价格promoItemPrice:100
秒杀功能:
1.涉及的表结构
1.用户信息表user_info 注册方式以及第三方登录账号
2.用户密码表user_password 加密后的密码
3.商品表item 商品名,商品价格
4.商品库存表item_stock
5.秒杀活动表promo
6.订单信息表order_info
2.前端页面和整体流程
最先进去的是getotp页面,注册regist,然后登录login,查询商品列表页listitem,商品详情页getitem
验证码是一个6位的随机数,然后将手机号和验证码绑定,添加到httpsession里面:
httpServletRequest.getSession().setAttribute(telephone,optCode);
然后就跳转到用户注册页面,填写表单
提交后,后台将用户输入的验证码和session里面存的验证码进行比较,如果一致,就注册成功
public XXX regist(String telephone,String optCode,Integer gender,Integer age,String password)
{
//取出session里面存的验证码
String SessionOptCode=httpServletRequest.getSession().getAttribute(telephone);
if(SessionOptCode==optCode)
{
//进行用户注册,往用户表中插入一行数据
UserModel userModel=new UserModel();
userModel.setName(name);
userModel.setGender(gender);
userModel.setAge(age);
userModel.setPassword(EncodeByMd5(password));//存的是加密后的密码
userModel.setRegisterMode("byphone");
userService.register(userModel);
}
}
注册成功后跳转到登录页面:
用户登录成功会在session中添加以下两个属性:
httpServletRequest.getSession().setAttribute("IS_LOGIN",true);
httpServletRequest.getSession().setAttribute("LOGIN_USER",userModel);
登录成功后进入商品列表页:
点击一个商品,进入商品详情页:
下单的时候,下单之前先减库存(库存数量-购买数量,结果大于等于0就减库存成功),然后订单入库(往订单表中插入一行数据)
3.在阿里云服务器上进行部署
购买2cpu 8GB
在本地远程登录虚拟机ssh root@47.105.229.245
(1)先安装java运行环境:通过linux的rpm命令安装rpm安装包
chmod 777 jdk-8u65-linux-x64.rpm//给这个rpm安装包赋予可执行的权限
rpm-ivh jdk-8u65-linux-x64.rpm //安装rpm安装包X
vim ~/.bash_profile 添加环境变量
(2)安装数据库环境:mysql5,启动后在3306端口
yum install mysql* //yum命令强制启动
往服务器的mysql数据库中导入数据:
先是在本地的电脑中将数据备份下来
mysqldump -uroot -proot --databases miaosha //要备份的数据库叫miaosha,会形成一个miaosha.sql文件
然后在本地将这个sql文件上传到云服务器中
scp ~Downloads/miaosha.sql root@47.105.229.245://tmp/
然后让云服务器中的mysql执行这个sql文件,在服务器上执行:
mysql -uroot -proot < //tmp/miaosha.sql(3)
(3)将应用程序打包成一个可运行的java程序
使用maven进行打包,然后将打成的jar包上传到云服务器上,在云服务器上启动这个jar包
java -jar miaosha.jar
(4)设置一台服务器作为nginx服务器
(5)将一台应用服务器也同时作为redis服务器,在上面安装redis
4.用jmeter进行压测
程序在一些业务压力冲击下会变得非常慢,或者宕机
模拟高并发
200个线程20次循环,TPS 200
访问id=6的商品的商品详情页
5.优化:
(1)nginx反向代理负载均衡
现在的部署方案将web服务器和数据库部署在同一台机器上
这样单机的cpu使用率很高,内存占用也很大,网络带宽的使用也增加(cpu,内存,网速都太高了)
从一台阿里云服务器扩展到四台阿里云服务器(一台用于nginx反向代理服务器,一台用于数据库服务器,两台用于应用服务器,如果想省点钱,可以按量收费而不是包月,1个小时才1块钱)
把jar包复制到两台应用服务器上
nginx:在这里充当了两个角色,静态资源服务器(存放html,css,js等静态资源文件),反向代理服务器
进入conf/nginx.conf,修改nginx配置,采用轮询的负载均衡策略,所以两台应用服务器的权重都是1
(2)使用redis实现分布式会话存储
用户在一台应用服务器上登录了,结果下一次的路由请求被发到了另一台应用服务器上,显然在另一台应用服务器上session是不存在的,所以需要一个分布式会话的管理机制,将session维护在一个集中式管理的地方(而不是单台应用服务器上)
明明我登录了,但是点击下单的时候还是会先是未登录,这说明session没有存到接收到下单请求的那台应用服务器上
将其中一台应用服务器也作为redis服务器
如果用户登陆成功,将登录信息和登陆凭证存入redis
String uuidToken=UUID.randomUUID().toString();
redisTemplate.opsForValue().set(uuidToken,userModel)
redisTemplate.expire(uuidToken,1,TimesUnit.HOURS)//设置过期时间
在创建订单createOrder的方法中:
String token= httpServletRequest.getParameterMap().get("token");
if(token!=null)
{
UserModel userModel=redisTemplate.opsForValue().get(token);
}
if(userModel!=null)//去创建订单
{
OrderModel orderModel=orderService.createOrder(userModel.getId()..........);
}
(3)使用多级缓存进行查询优化
商品详情页的动态内容进行缓存
传入一个商品id,展示这个商品的详情页
在redis中key-value键值对
(4)使用redis缓存热点数据 缓存热点商品详情页的动态内容
热点数据:每秒钟会被访问上千上万次
(5)页面静态化
(6)秒杀令牌,秒杀大闸,队列泄洪
(7)防刷限流(验证码,限流,防刷)
6.项目中使用到redis的地方