近期尝试使用tomcat和Nginx进行配合作负载均衡和静态与动态资源分配的Demo,期间遇到不少有意思的地方和知识短板,特此记录
一:什么是Nginx?
Nginx也是一款服务器,咱们经常使用它作如:反向代理、负载均衡、动态与静态资源的分离的工做
反向代理:相对应的是正向代理,若是你使用过代理服务器的话就明白,咱们访问某一个网站并不是直接访问目标网站,而是告诉代理服务器我须要访问什么目标网站,由代理服务器发出请求给目标网站,将目标网站访问结果再转发给你,此时,你是请求代理方。而反向代理是此时代理服务器作服务器的代理,咱们的访问请求并不是直接访问到目标服务器上,而是访问代理服务器,由代理服务器决定什么样的请求以什么样的方式访问正式服务器
负载均衡:目前大多数的网站都会采用负载均衡手段来针对目前用户的指数级增加来减小对单点服务器的负载压力,好比目前咱们拥有3台真实服务器,咱们须要根据相应策略决定什么样的用户请求分配到哪一个真实服务器,好比按照轮询的方式,用户请求挨个到达代理服务器,此时代理服务器按照第一个请求转发至第一台真实服务器,第二个请求转发到第二个服务器上,依次类推,这样能够防止大量的用户请求所有访问到同一台物理机上,单点物理机的性能始终有限的,固然这可能对服务器数据访问时候形成事务性的失效,在Web方面可能形成Session访问的问题,这不在本文讨论方面内
动态静态资源分离:最方便列举就是Java的JSP和静态资源如:.js/.css/.html/.png方面的资源分离,以前开发web方面的程序时候咱们习惯将html、css等资源文件也放置于Tomcat之中,用户访问后tomcat须要将请求的这些静态资源文件一并返回给用户,再者若是有多台同业务逻辑的tomcat服务器的话,一样的资源还须要在每一个服务器上放一份,同时也增长了tomcat服务器的网络IO,十分不合算的,若是咱们只讲JSP之类的请求交给tomcat,而代理服务器上存放静态资源,当用户的请求非动态资源的时候,咱们彻底能够将代理服务器的静态资源直接返回给用户,而不去增大Tomcat的压力,tomcat只须要负责逻辑处理和动态资源的加载就能够了
基于上述的Nginx优点,决定搭建一下Nginx+Tomcat的组合来进行测试,包括参数传递,post、get传递参数是否有影响,还有Nginx的工做模式master和worker的工做方式进行一些浅薄的总结
1、Nginx的安装
安装部分这里就不在细说了,网上的教程不少,咱们直接从配置文件开始吧
2、配置文件
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
#user nobody;
#这里是核心worker数,通常设置为与cpu核心数相同的数目,避免进程切换形成的上下文切换耗费资源,cpu信息能够从/proc/cpuinfo中查看
worker_processes
1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
#use epoll model使用epoll模型,采用异步非阻塞模型加快处理速度
use epoll;
worker_connections
1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
#设定经过nginx上传文件的大小
client_max_body_size
300m;
#使用sendfile函数在两个文件描述符之间直接传递数据(彻底在内核中操做,传送),从而避免了内核缓冲区数据和用户缓冲区数据之间的拷贝,操做效率很高,被称之为零拷贝。
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
#链接活跃时间
keepalive_timeout
65;
#使用压缩数据减小IO量,可是在不支持数据解压浏览器可能产生乱码
#gzip on;
#静态服务器组
#设定静态资源服务器访问接口
upstream
static.zh-jieli.com {
server localhost:
808 weight=
1;
}
#动态服务器组
upstream zh-jieli.com {
#设置Hash轮询规则
#ip_hash;
#weight: server ip:port weight=10
#默认 轮询
#fair:按照后端服务器的响应时间来分配
#url_hash:按照url规则进行分配,使得固定的请求分配到固定的服务器上
server localhost:
8080;
server localhost:
8081;
}
server{
listen
808;
server_name
static;
location / {
}
location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff) {
#全部静态文件直接读取硬盘内容:读取的静态资源存放位置
root /apache-tomcat-
8.5.24/webapps/ROOT ;
#资源是否进行缓存与缓存时间
expires
30d;
#缓存30天
}
}
server {
listen
80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index1.html
index.htm;
}
location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff) {
#proxy_cache cache_one;
proxy_cache_valid
200 304 302 5d;
proxy_cache_valid any
5d;
proxy_cache_key
'$host:$server_port$request_uri';
add_header X-Cache
'$upstream_cache_status from $host';
proxy_pass http:
# 全部静态文件直接读取硬盘
root /apache-tomcat-
8.5.24/webapps/ROOT;
expires
30d;
#缓存30天
}
#其余页面反向代理到tomcat容器
location ^~ /tomcat {
index index;
# proxy_pass http://localhost:8080/;
#设定代理服务器组
proxy_pass http:
}
error_page
500 502 503 504 /
50x.html;
location = /
50x.html {
root html;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
整个nginx工做时当http请求到来时,由nginx针对nginx.conf配置好的规则,对location进行正则匹配,匹配到相应的正则,进行location内部的处理
关于Nginx的location配置附上一篇博客,很nice
http://seanlook.com/2015/05/17/nginx-location-rewrite/
里面很详细列出了各类要求的location匹配规则,值得注意的一点是:
location匹配遵循最长原则,即知足了以前的匹配规则后,除了碰见^会终止向下继续匹配,其余状况会依次向下搜索,知道找到合适的location匹配规则而后进行处理
Nginx在模块功能上分三个模块:
Handlers(处理器模块)。此类模块直接处理请求,并进行输出内容和修改headers信息等操做。Handlers处理器模块通常只能有一个。
Filters (过滤器模块)。此类模块主要对其余处理器模块输出的内容进行修改操做,最后由Nginx输出。
Proxies (代理类模块)。此类模块是Nginx的HTTP Upstream之类的模块,这些模块主要与后端一些服务好比FastCGI等进行交互,实现服务代理和负载均衡等功能。
由于是测试,因此个人两个tomcat都安装到了同一台本地机器上
生产环境中根据须要进行配置相应的IP就行了
本地写好相应的测试代码+log4j将信息日志打到相应的位置用来观察参数是否传递过来
TestOne.javacss
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
package
com.nginx.controllers
import
com.nginx.utils.Log4jUtils
import org
.springframework.stereotype.Controller
import org
.springframework.web.bind.annotation.RequestMapping
import org
.springframework.web.bind.annotation.RequestParam
@Controller
@RequestMapping(
"/test")
public class TestOne {
@RequestMapping(
"/getname")
public void test(@RequestParam(value =
"name") String name) {
//用来记录获取的参数name,能够经过查看日志进行确认
Log4jUtils
.getLogger()
.info(
"my name is" + name)
}
}
Log4jUtils.javahtml
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
package com.nginx.utils;
import org.apache.log4j.Logger;
public class Log4jUtils {
private static final Logger logger = Logger.getLogger(Logger.class);
public static Logger
getLogger() {
return logger;
}
}
这里简单作了两个的demo程序,作相应的测试,将项目打成war包后上传至Linux服务器,移动到tomcat/webapps中,tomcat进行热部署
先测试当前的tomcat是否能正常运行,因为没有作区别页面,就直接看日志来判断了

如图:以轮询方式进行访问8080和8081监听的tomcat
上述方式是get请求进行的测试,咱们来试试post
<!DOCTYPE html>
<html>
<body>
<form action="http://123.207.85.242/tomcat/nginx/test/getname" method="post">
<input type="text" name="name">
<input type="submit" value="提交">
</form>
</body>
</html>
测试结果依旧能够正常接收参数,这里就不贴图了
2、静态动态资源分离
如今试试直接访问
http:
咱们会直接跳转到tomcat的主页面,若是检索tomcat.png的话
http://ip/tomcat/tomcat
.png
能够直接检索到tomcat.png,它是来自tomcat服务器的资源,若是须要检索nginx的静态资源,可使用
http://ip/tomcat
.png
这样咱们的资源就来自于nginx.conf文件中配置的关于静态资源的访问路径了,为了证实此事资源来自于nginx,我尝试将8080端口的tomcat/webapps/ROOT/tomcat.png改名为tomcat1.png,而后尝试访问http://ip/tomcat1.png访问成功,这时候若是刷新http://ip/tomcat/访问tomcat主页的时候会发现图标会在出现和不出现之间轮转,缘由就是这里请求了tomcat服务器自己去拿资源,tomcat:8080的图片名被更改,若是代理访问的服务器正好是tomcat:8080的话,它是找不到tomcat.png的,固然轮转到tomcat:8081时候,图片仍是会出现滴
3、Nginx工做模式

如图nginx启动后会有两个进程
若是你将nginx.conf的
worker_processes 1;更改成worker_processes 2;
那么出现的就是

那咱们来讲说master和worker进程分别的是干什么的,从pid来看,matser的父进程是init进程,而worker的父进程都是master,这里就颇有意思了,那nginx这两个进程都究竟是干吗的嘞???
感谢baidu与google的强大,对于疑问的解释很清楚
原地址:http://blog.csdn.net/hguisu/article/details/8930668
感兴趣的同窗能够看一看,这里只简单总结一下
master进程
主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常状况下),会自动从新启动新的worker进程。
master的平滑重启颇有意思,master只负责接收外界信号,那么当咱们更改了nginx.conf文件须要从新启动nginx时候怎么办????只须要经过kill向master进程发送信号就好了。好比kill -HUP pid,这时候master并不会干掉本身全部的worker而后自杀,而是从新加载nginx.conf后,从新启动一批worker,在这以后的请求所有由新的worker进行处理,而老的worker也并非当即终止,而是在运行完当前的请求后,被终止掉,接下来的请求就所有交给新的worker了,固然这个方式后来被改为了
nginx
-s reload
这个命令从新加载配置和上面的略有不同,其会新启动一个nginx而后向Master发送信号,固然接下来就和上面的过程一致了
worker进程
而基本的网络事件,则是放在worker进程中来处理了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是能够设置的,通常咱们会设置与机器cpu核数一致,这里面的缘由与nginx的进程模型以及事件处理模型是分不开的。
那么worker是怎么作的呢,worker从master fork出来后,由master进行监听端口,当有相应的链接来以后,由worker争抢accept_mutex互斥锁,同一时刻此请求只能由一个worker争抢成功,并进行链接的读取、解析、处理而后断开链接
着总体是Nginx的工做的大体原理,Nginx依旧有不少细节和设计值得去深究学习,本篇博客先总结到此,后续有了更深刻的了解,也会分享出来,谢谢