同样操作 云端部署的方式: https://www.cnblogs.com/yugehard/p/14171007.html
现在我们的部署方案将我们tomcat一个秒杀的java web的服务器及对应的数据库部署在了同一台机器上,单机有对应的容量问题,需要系统有一个水平扩展的能力,这个能力依托于nginx的反向代理做一个收口的操作。
如何对于同一个域名可以代理到多台不同的application server的应用服务器上——nginx的反向代理 它可以代理我们后端的一个tomcat的服务器集群,以一个同一域名的方式暴露出去供用户调用
一.修改前端用于部署nginx
因为之前在JMter测压之前进行了云端部署,但是我这里没有做云端部署,但是还是记录一下操作的过程
建立gethost.js
var g_host = "localhost:8090";
在前端文件中引入js
<script src="./gethost.js" type="text/javascript"></script>
在每个url处进行使用
url:"http://"+g_host+"/
二.部署Nginx OpenResty
只需要将一个对应的OpenResty打包下载下来,进行编译之后就可以使用nginx的互联网相关的一些基本内容
OpenResty是基于nginx上面另外开发包装对应的一个可以支持lua的一个应用
视频中是在linux上进行操作
这里百度了一个Openresty在windows安装和使用 不知道影不影响后续使用 现在先这样处理
Openresty在windows安装和使用_openresty windows_蓝色雨88的博客-CSDN博客
下载完成后 点击nginx.exe运行
将秒杀系统中html文件复制进入D:\openresty-1.21.4.1-win64\openresty-1.21.4.1-win64\html下
进入网站
成功
然后全部运行一遍 运行成功
三.前端资源路由
第一步:修改C:\Windows\System32\drivers\etc 中hosts文件
⚠出现了问题 修改后不能使用miaoshaserver直接访问
解决①(1条消息) windows修改hosts文件不生效(非DNS缓存问题)_TianXinCoord的博客-CSDN博客
②
(1条消息) 修改hosts 不生效? 三种方法解决-CSDN博客
最后是修改后重新启动电脑成功解决
第二步:修改修改nginx.conf
⚠输入之后 在进行nginx重新配置时出错
在任务管理器把进程结束了 想着重新启动
结果启动搞不起来 错误如下
解决(1条消息) nginx.conf配置文件修改的注意事项/规则_nginx conf文件被修改_哆啦Ci梦的博客-CSDN博客
末尾少了一个 /
----------------------------------
此处我感觉用windows做这一步意义不大
就是在html文件下创建了一个 resources文件 把html中的文件全部放入resources中
四.配置nginx反向代理
第一步:进入nginx.conf进行修改
#gzip on;
#
#后端服务器集群
upstream backend_server{
server 本地网Ip weight=1;
}
这里的网址 我添加的是电脑本地的网址 不知道后续有没有影响 先这样放在这
location /resources/ {
alias /usr/local/openresty/nginx/html/resources/;
index index.html index.htm;
}
location / {
proxy_pass http://backend_server;
proxy_set_header Host $http_host:$proxy_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
①proxy_pass http://backend_server; 当路径访问除开resouces节点之外,就反向代理到http://backend_server backend_server 对应的ip地址是后端服务器集群中的地址
②proxy_set_header Host $http_host:$proxy_port; 后面$后是端口号
③proxy_set_header X-Real-IP $remote_addr;真正的客户地址其实是一个远端的客户地址
④ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;Nginx作为一个代理服务器转发了这个请求
⚠经试验后,未成功
参考这个博主duiwindows下配置nginx访问本地静态资源,完整配置,使用root和alias的区别,小心掉坑里_windows nginx alias_一点光辉的博客-CSDN博客
nginx配置访问本地静态资源 - long77 - 博客园 (cnblogs.com)
对nginx.conf重新进行修改
完整代码如下:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream backend_server{
server localhost:8090;
}
server {
listen 80;
server_name localhost;
location /resources/ {
alias D:/openresty-1.21.4.1-win64/openresty-1.21.4.1-win64/html/;
index index.html index.htm;
}
location / {
proxy_pass http://backend_server;
proxy_set_header Host $http_host:$proxy_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
运行成功!!
第二步:开启tomcat access log验证
这里又涉及到是在windows上而不是在linux上
首先 设置application.properties
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.directory=D:/miaosha/tomcat
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D
解释:
%h - 远程主机名称(如果resolveHosts为false则展示IP)
%l - 远程用户名,始终为'-'(Remote logical username from identd)
%r - 请求的第一行(包括请求方法和请求的URI)
%s - response的HTTP状态码(200,404等)
%t - 日期和时间,Common Log Format格式
%u - 被认证的远程用户, 不存在则展示'-'
%D - 处理请求的时间,单位为毫秒
%T - 处理请求的时间,单位为秒
%I - 当前请求的线程名(can compare later with stacktraces)
server.tomcat.accesslog.directory 表示日志存放的位置
然后对nginx.conf进行修改 设置日志输入位置 这里出了很多错误 其中还把logs中的nginx.pid复制进了miaosha\tomcat中
error_log D:/miaosha/tomcat;
error_log D:/miaosha/tomcat notice;
error_log D:/miaosha/tomcat info;
pid D:/miaosha/tomcat/nginx.pid;
access_log D:/miaosha/tomcat main;
运行
运行后查看日志输出
返回码 200,发送了331个字节,处理时间791ms
对gethost.js进行修改
var g_host = "miaoshaserver";
五.分布式扩展后的性能压测
还在是localhost上测压
换为miaoshaserver
换为127.0.0.1
修改Nginx.conf
upstream backend_server{
server localhost:8090;
keepalive 30;
}
location / {
proxy_pass http://backend_server;
proxy_set_header Host $http_host:$proxy_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
运行 127.0.0.1
不知道为什么 每次重新点运行 数据就会一直发生变化
六.Nginx高性能原因
七.分布式会话管理
1.基于cookie传输sessionid:java tomcat容器session实现
目前我们项目使用的是 SpringBoot内嵌tomcat容器里的 HTTPsession
机制,是基于cookie传输sessionid的一个机制,用来标识一个用户会话项目中用到的地方是登陆/注册功能
第一步:在pom.xml添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
第二步:创建RedisConfig
@Component
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
public class RedisConfig {
}
第三步:在windows上安装redis
Window下Redis的安装和部署详细图文教程(Redis的安装和可视化工具的使用)_windows 安装redis_明金同学的博客-CSDN博客
测试
第四步:将redis操作配置上去
修改application.properties
#配置springboot对redis的依赖
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=10
#spring.redis.password=
#设置jedis连接池
spring.redis.jedis.pool.max-active=50
spring.redis.jedis.pool.min-idle=20
启动app
⚠
Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to serialize object using DefaultSerializer; nested exception is java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type [com.miaoshaproject.service.model.UserModel]
报错没有UserModel的一个序列化接口 要存入redis的数据,都得实现 Serializable
序列化
修改UserModel.java
public class UserModel implements Serializable {
}
重新启动后 查看keys *
第五步:验证这套方案是否适应于分布式
在redis.conf中 如果默认不加任何ip地址的话 默认绑在0.0.0.0 也就是说所有的只要能够连接到这台服务器的 不管是内网ip还是外网ip都可以 现在修改成对应的内网ip
不知道这样可行不可行 先放在这
然后重新运行程序 进行操作 具体操作就是登录之后在下单页面点击几次下单
2.基于token传输sessionid:java代码session的实现
token类似于服务端下发sessionid植入到cookie,下发令牌,交给前端,等登陆请求时,把token加入到http header或url中。将java代码将token传到redis中
第一步:修改UserController.java
@Autowired
private RedisTemplate redisTemplate;
//用户登录接口
@RequestMapping(value = "/login", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
public CommonReturnType login(@RequestParam(name="telphone")String telphone,
@RequestParam(name="password")String password) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
//入参校验
if(org.apache.commons.lang3.StringUtils.isEmpty(telphone)||
StringUtils.isEmpty(password)){
throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR);
}
//用户登录服务,用来校验用户登录是否合法
//用户加密后的密码
UserModel userModel = userService.validateLogin(telphone, this.EncodeByMd5(password));
//将登陆凭证加入到用户登陆成功的session内
//修改成若用户登录验证成功后将对应的登录信息和登录凭证一起存入redis中
//生成登录凭证token,UUID
String uuidToken = UUID.randomUUID().toString();
// 例如:5dcac225-b98b-4618-b09d-533440b936e7 将token的"-"给去掉
uuidToken = uuidToken.replace("-","");
//建议token和用户登陆态之间的联系
redisTemplate.opsForValue().set(uuidToken,userModel);
// 设置uuidToken过期时间为1小时
redisTemplate.expire(uuidToken,1, TimeUnit.HOURS);
/*//将登陆凭证加入到用户登录成功的session内
this.httpServletRequest.getSession().setAttribute("IS_LOGIN", true);
this.httpServletRequest.getSession().setAttribute("LOGIN_USER", userModel);*/
//下发了token
return CommonReturnType.create(uuidToken);
}
第二步:修改login.html
$.ajax({
type:"POST",
contentType:"application/x-www-form-urlencoded",
url:"http://"+g_host+"/user/login",
data:{
"telphone":telphone,
"password":password
},
//允许跨域请求
xhrFields:{withCredentials:true},
success:function (data) {
if (data.status=="success") {
alert("登录成功");
//将token返回给前端 并储存起来
var token=data.data;
window.localStorage["token"] = token;
window.location.href = "listitem.html";
}else {
alert("登录失败,原因为" + data.data.errMsg);
}
},
error:function (data) {
alert("登录失败,原因为"+data.responseText);
}
});
return false;
});
});
第三步:修改getitem.html
$("#createorder").on("click",function () {
//将储存在客户端的token取出
var token = window.localStorage["token"];
if(token == null){
alert("没有登录,不能下单");
window.location.href="login.html";
return false;
}
$.ajax({
type:"POST",
contentType:"application/x-www-form-urlencoded",
//如果获取到token就将token返回到后端
url:"http://"+g_host+"/order/createorder?token="+token,
第四步:修改OrderController.java
@Autowired
private RedisTemplate redisTemplate;
//封装下单请求
@RequestMapping(value = "/createorder", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
public CommonReturnType createOrder(@RequestParam(name = "itemId") Integer itemId,
@RequestParam(name = "amount") Integer amount,
@RequestParam(name="promoId",required=false)Integer promoId) throws BusinessException {
//获取用户登录信息
// Boolean isLogin = (Boolean) httpServletRequest.getSession().getAttribute("IS_LOGIN");
/* if (isLogin == null || !isLogin.booleanValue()) {
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN, "用户还未登录,不能下单");
}
UserModel userModel = (UserModel) httpServletRequest.getSession().getAttribute("LOGIN_USER");*/
//获取token请求
String token = httpServletRequest.getParameterMap().get("token")[0];
if (StringUtils.isEmpty(token)) {
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN, "用户还未登录,不能下单");
}
// 获取用户的登录信息
UserModel userModel = (UserModel) redisTemplate.opsForValue().get(token);
if (userModel == null) {
throw new BusinessException(EmBusinessError.USER_NOT_LOGIN, "用户还未登录,不能下单");
}
OrderModel orderModel = orderService.createOrder(userModel.getId(), promoId,itemId, amount);
return CommonReturnType.create(null);
}
}
第六步:运行进入 下单
查看控制台
这里不知道为什么用火狐就不行 用了微软