一、什么是Nginx?
Nginx是一款轻量级高性能的反向代理服务器,支持Web站点和邮件代理。其特点是内存少,并发能力强,结构简单,支持长时间的动作,它通过代理模式将用户的请求转发给不同的服务器,减轻服务器的压力。
二、Nginx负载均衡策略
Nginx支持6种均衡策略,分别为轮询,权重,IP hash(ip 分配),least_conn(最少连接),fair(响应时间),url_hash(url分配)。通过这几种策略来达到不同的业务需求。下面分别介绍下各自的特点:
1、轮询
轮询是策略中最基础的方式,通过upstream模块实现,是默认的均衡策略 在nginx.conf文件里
upstream weburl{
server 127.0.0.1:8080;
server 127.0.0.1:8081 backup;//IP + 端口 +参数配置
}
通过upstram模块 指定后端的服务器列表,每个请求会按时间顺序访问后端的服务器。其中提供一些参数设置:
fail_timeout :时间超出。
max_timeout : 最大超时时间,如超过次数会被认为该服务器为停机状态。
fail_time:请求超时的时间 默认为10s。
backup:标记为该服务为务用服务器,当其中的主机死机后,请求会被备用机接收。
down:表示永远停机。
2、权重策略Weight
权重策略是增加请求次数的几率,可以设置对哪台服务器进行多次的访问:
upstream weburl{
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8082 backup;
}
上面的例子中使用weight参数=2来表示应该服务器的请求次数,会比权重1的要访问的次数高一些,权重分配的越高处理请求次数越多,此策略用于服务器之间配置较大时进行使用,可以和least_conn,ip_hash配合使用。
3、IP_Hash策略
ip_hash策略指定负载均衡按照基于客户端IP的分配方式,将相同的客户端请求发送到同一个服务器进行处理
upstream weburl{
ip_hash;
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8082 ;
}
其中ip_hash不能和backup进行同时使用,该策略适合状态服务(session)。
4、least_conn策略
least_conn策略是将请求交给后端连接数较少的服务器,轮询策略中是将请求平均的分配给后端服务器,这会增加占用请求的时间,least_conn比轮询效果会好一些。
upstream weburl{
least_conn;
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8082 ;
}
5、第三方策略fair
要实现这种策略需要安装第三方插件。
upstream weburl{
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8082;
fair;
}
fair是按照服务器响应时间来进行分配请求,响应时间短的优先分配。
6、url_hash策略
url_hash也是需要第三方插件,url_hash是根据url的hash结果值来分配后端服务器,当多个请求都访问同一个资源,使用url_hash策略可以将同一台服务器之前访问过的资源进行再次分配,从缓存中取出。
upstream weburl{
hash $request_url;
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8082;
}
以上几种策略要根据不同的应用场景进行使用。
三、Nginx如何处理请求
Nginx在启动会解析配置文件,得到需要的端口和IP地址,然后在nginx的主进程里,发先初始化这个监控对象socket绑定到指定的IP地址端口再进行监听listen,然后再通过fork创建一个新的线程worker,多个线程进程之间会相互竟争accept的连接,此时,客户端可以向nginx发起连接,与nginx三次握手(http协议),找到一适合的线程进行连接同时会获得accept的对象(socket),然后创建nginx封装ngx_connection结构体,之后处理之间的读写请求操作进行数据交换,完成之后再进行释放连接。
对于超时的请求nginx会根据设置的超时时间来进行设定,长时间没有得到处理会返回一个状态码(404 501)来标明这个请求出现了错误,nginx提供proxy_next_upstream_tries来进行重试机制,出现了超时的主机,不会再次发送到该主机上,由下一个竟争的节点来进行处理。其中在nginx之前还有一层代理SLB最大的超时时间为一分钟,如果设置多了,会出现多次重复请求的问题。
四、搭建Nginx代理服务器
本文以windows做一个简单的示例,Linux的请查看其它文章。
1、首先从官网下载最新的tar包(http://nginx.org/en/download.html)。
2、下载完后解压到一个盘符下打开conf 下的nginx.conf文件如图:
#user nobody;
worker_processes 2;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
multi_accept on;
accept_mutex on;
}
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;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream weburl{
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8082;
}
error_page 400 http://www.baidu.com;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
proxy_pass http://weburl;
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 8888 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
查看文件的模块结构:
**************************************
全局变量
events{ //nginx与网络连接配置参数
}
http{ //http模块
//局部参数
server{ //服务器模块
location{ //服务地址参数配置
}
}
}
*****************************
这以上为主要的几个模块。后面再来进行相关配置。
五、打包SpringCloud
基于之前的文章使用到的 Spring-cloud-mybatis-jsp 工程 在index.jsp增加一个h1标签来进行标识哪个站点。在工程中复制一份工程。复制工程之后需要修改几个地方
1、pom.xml
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.2.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-cloud-mybatis-jsp2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>spring-cloud-mybatis-jsp2</name>
<description>Demo project for Spring Boot</description>
修改其中的artifactId 和 name值 内容为新的项目名称
2、在工程空间下修改.settings文件下org.eclipse.wst.common.component 文件将其中的deploy-name,context-root,java-output-path都修改成新的工程名称
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="spring-cloud-mybatis-jsp2-0.0.1-SNAPSHOT">
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<property name="context-root" value="spring-cloud-mybatis-jsp2"/>
<property name="java-output-path" value="/spring-cloud-mybatis-jsp2/target/classes"/>
</wb-module>
</project-modules>
3、打包成war文件 首先pom.xml里的<packaging>war</packaging>需要指定的是war值,然后文件中的tomcat需要设置<scope>provided</scope>值
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
最后主程序需要继承SpringBootServletInitializer类重写configure方法 如下:
@SpringBootApplication
public class SpringCloudMybatisJspApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(SpringCloudMybatisJspApplication.class, args);
}
@Override//为了打包springboot项目
protected SpringApplicationBuilder configure(
SpringApplicationBuilder builder) {
return builder.sources(this.getClass());
}
}
满足这几个条件就可以进行war打包, 点击工程 右键选择Run As->Maven install 之后console会显示打包war后的路径 eg:
E:\apache-maven-3.5.3\maven\repository\com\example\spring-cloud-mybatis-jsp2\0.0.1-SNAPSHOT\spring-cloud-mybatis-jsp2-0.0.1-SNAPSHOT.war
之后将文件重命为相同的名称放在tomcat webapp目录。另一个工程同样的方法进行打包。
注意:test文件下的内容不能进行打包,删除就可以了。
4、设置两个Tomcat
从安装好的Tomcat复制一份,修改tomcat的配置文件 主要修改三个地方(配置不同的端口):
<Server port="8006" shutdown="SHUTDOWN">
<Connector port="8081" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8010" protocol="AJP/1.3" redirectPort="8443" />
然后修改bin目录下的两个文件:startup.bat 和catalina.bat 将其中的CATALINA_HOME全替换为新的名称CATALINA_HOME_8080 另一个tomcat就取CATALINA_HOME_8081。
最后运行两个tomcat,tomcat会自动的将war进行解压运行 如图 :

通过两个tomcat 访问各自的项目。
6、配置Nginx
上面的显示例代码也已经出给了,下在进行说明一下,在server 模块的上方通过upstream 服务群名称来指定不同的服务器:
upstream weburl{
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:8081 weight=1;
}
其中server可以指定本机和其它的IP地址,端口就是tomcat的端口号,后面参数可以设置均衡策略。其中在localtion模块中需要将刚刚配置的集群名字放到服务地上模块中进行指定。如下:
location / {
proxy_pass http://weburl; //这里集群名称一致。
root html;
index index.html index.htm;
}
以上就配置好了,本例只是个简单的例子,还有其它的配置比如超时,文件缓存策略、重试等。
之后进入目录(cd /) 启动Nginx 使用命令start nginx启动(nginx -s stop 停止),如果出现错误就查看log文件下的error.log文件,里面指明错误的信息,如果没有错误说明配置没有出现错误,然后查看进程里是否有nginx进程。
最后运行Url: http://localhost/spring-cloud-mybatis-jsp/getusers 连续刷新查看 通过nginx代理可以访问不同的工程,不需要指定端口号,就可以在两个工程之间进行访问。
总结:
以上就是本文通过Nginx+Spring Cloud+Tomcat实现一个简单的负载均衡,Nginx还有很多的配置但都是基于nginx.conf里的参数来进行设置,具体参数需要根据工程需求来进行设置,包括连接的优化,以及响应时间等等要根据实际情况而定。