这篇文章将先阐述Nginx相关概念,然后介绍Nginx相关环境的安装配置过程(包括Linux下JDK\Tomcat的安装,都是自己动手操作的记录),及反向代理、负载均衡、动静分离、高可用的配置及测试过程,最后总结下Nginx的工作原理。
一、Nginx中的核心概念
Nginx ("engine x") 是一个高性能的 HTTP 和反向代理服务器,特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
代理服务器是介于客户端和Web服务器之间的另一台服务器,有了它之后,浏览器不是直接到Web服务器去取回网页而是向代理服务器发出请求,信号会先送到代理服务器,由代理服务器来取回浏览器所需要的信息并传送给你的浏览器。
Nginx的特点是:
使用Nginx我们可以实现:
简单说下正向代理,它是一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端配置了代理服务器后才能使用正向代理。可以看成客户端和代理服务器是一体的,真正的目标服务器并不知道具体是哪个客户端请求了自己的服务,因为都是经过代理服务器过来的,正向代理过程如下:
正向代理
反向代理可以看成代理服务器和目标服务器是一体的,客户端不知道具体是哪个目标服务器返回的响应,反向代理过程如下:
反向代理反向代理对用户则是不可知的,比如我们访问百度网站,百度的代理服务器对外的域名为 https://www.baidu.com 。具体内部的服务器节点我们不知道,现实中我们通过访问百度的代理服务器后,代理服务器给我们转发请求到他们N多的服务器节点中的一个给我们进行搜索后将结果返回。
反向代理的作用:
负载均衡:反向代理服务器可以做负载均衡,根据所有目标服务器的负载情况,将客户端请求分发到不同的真实服务器上。
总结:
负载均衡,用来在多个服务器(集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到最优化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。
怎么理解?先从没有负载均衡说起,客户端发送大量请求到服务器(并发数较大时),单个服务器的性能就成了瓶颈,服务器可能扛不住这么多的请求而宕机。解决的办法可能就是直接增加物理资源(纵向扩展),提升CPU/内存/网络带宽/硬盘等,问题虽然能够得到缓解但是代价高昂,甚至在一些秒杀或直播场景中只是增加物力资源也是不能解决问题的,单点故障在所难免。
有了负载均衡就好办了, 负载均衡是将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行。是解决高性能,单点故障(高可用),扩展性(水平伸缩)的终极解决方案。
比如:超市买东西结账排队时,要是大家都可着一个收银台排队,那肯定会排很长时间,收银员也累得不轻;但如果把排队的人平均分散到多个收银台,排队时间将大幅减少,收银员的压力也会减少很多。同样的道理,大量请求到来时,若是能通过代理服务器将请求分发到多个目标服务器,那响应效率就会提高很多,压力分摊到多个服务器后,每台服务器的工作量也不大,因此对每台服务器的物理资源要求就不用太高,减低成本。比如有一万个并发请求过来,负载均衡后就会分摊到多个服务器,如下:
负载均衡过程上面的请求分配,若各服务器的物理资源一致情况下,理想中应该平均分配请求树。实际中根据需要,可能需要制定不同的分配策略,Nginx给我们提供了4种负载均衡策略:
就是动态资源(jsp、ftl、thymeleaf)与静态资源(js、css、img)分开部署,分别访问。动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们则根据静态资源的特点将其做缓存操作,因为静态资源访问比较频繁,且tomcat本身处理静态效率不高,还会带来资源开销,定睛分离就能提高响应能力。
主要是多配置几个Nginx代理服务,防止只有一个Nginx服务时,这个唯一的Nginx服务宕机。即配置主Nginx代理服务器和丛Nginx代理服务器,若其中一个宕机另一个马上顶替上开始工作,多个Nginx服务则由统一的虚拟Ip访问,这时还要搭配Keepalived一起使用,才能实现多Nginx高可用部署。过程如下:
高可用
二、Nginx的安装
因为后面要分别配置Nginx的反向代理、负载均衡、动静分离、高可用并测试效果,这些需要一些其他环境,比如JDK\Tomcat等,因此这里顺便梳理下它们在Linux下的安装过程.
首先是下载对应的JDK,地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
根据自己的Linux环境下载对应的JDK包,我用的华为云服务器,Linux 64位,下载的包是:jdk-8u251-linux-x64.tar.gz
下载好JDK之后,还要下载一个WinSCP软件,用来将JDK压缩包文件传输到华为云服务器,打开WinSCP,填写
登录后:
右边是远程服务器的文件目录,将JDK压缩包拖到右边对应的文件夹,我这里自己建了一个jdk文件夹:
然后执行tar -xzvf jdk-8u251-linux-x64.tar.gz 就会多出上面的解压包,然后就是配置Jdk的环境变量,环境变量文件位置在etc/profile,进入该路径执行vim etc/profile:
如上图,在profile文件最后添加:
export JAVA_HOME=/root/jdk/jdk1.8.0_251
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib
export PATH=$JAVA_HOME/bin:$PATH
修改好后执行:source etc/profile,即使文件修改的环境变量生效。这时可以执行java -version命令,验证是否设置成功。
也是先下载tomcat的安装包,地址:https://tomcat.apache.org/download-90.cgi
我这里下载的是apache-tomcat-8.5.57.tar.gz
与JDK安装一样,使用WinSCP进行传输后解压:
可以进入Tomcat的conf目录通过server.xml文件修改下访问的端口号,这里我修改成了8086,然后进入bin目录执行startup.up脚本启动Tomcat。进入logs目录执行tail -f catalina.out命令,查看启动日志,出现下面的日志说明成功启动:
最后在浏览器输入华为云的弹性公网IP + :8086:
这里因为是华为云服务器,如果tomcat正常启动,但是访问不了,可能是安全组没有设置,可以设置安全组如下:
这时弹性公网Ip就可以ping通。
上面如果安全组已经设置但还是访问不了,那就有可能端口防火墙没开,使用:
firewall-cmd --list-all
可以查看防火墙端口设置情况:
上面ports后面的就是已经开放的端口,如要想开放其他端口,执行:
sudo firewall-cmd --add-port=XXXX/tcp --permanent
最后加载更新这个防火墙配置即可:
firewall-cmd --reload
安装Nginx前还要安装它的一些协作(依赖)软件,包含:
步骤:
1.下载pcre安装包:地址:https://zh.osdn.net/projects/sfnet_pcre/releases/ 找到后选择版本右键复制链接地址,wget下载到服务器(也可以下载后用winSCP传输到远程服务器),之后进行解压:
2.进入解压后的目录,执行./configure命令
3.执行make命令,最后执行make install。
输入pcre-config --version出现下面版本号说明安装成功:
三、Nginx有一些常见命令
注意,操作这些命令时需要进入nginx目录中:
如修改了nginx的配置文件nginx.conf,就需要重新加载才能生效,注意不是重启nginx,只是重新加载配置文件
四、Nginx的配置文件
nginx的配置文件在/conf/nginx.conf中:
完整的文件如下:
#user nobody;
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 {
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;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
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 443 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;
# }
#}
}
Nginx的配置文件由3部分组成:
1、全局块
配置文件开始到events之间的内容,主要是一些影响nginx服务器整体运行的指令,例如允许的work process数,进程PID存储路径,日志路径等。
2、events块
影响Nginx服务器和用户的网络连接,worker_connections = 1024;就代表每个work process支持的最大连接数是1024,这部分配置对nginx的性能影响很大,需要灵活配置。
3、http块
这边配置修改是最频繁的,尤其是包含的server配置块。
http块可以包含多个server块,每个server就相当于一个虚拟机,每个server还包含多个location。server块配置本虚拟机的IP和端口;location是对请求进行匹配,对特定的请求进行处理,地址指向、数据缓存和应答控制等也在这里配置。
五、Nginx反向代理配置实例 一
预期效果:通过域名跳转到特定地址,例如:输入www.666.com,跳转到tomcat主页,过程如下:
步骤:
(1)部署tomcat服务器,端口为8086,为了方便把Tomcat和Nginx部署在同一台服务器;
(2)修改nginx配置文件
(3)重启Nginx
(4)修改本地hosts文件
因为以某个域名访问的时候,首先会在本地的hosts文件查找是否有这个域名与ip的映射配置,没有才会走dns域名解析,这里
需要配置域名的映射关系,打开hosts文件,路径C:\Windows\System32\drivers\etc,修改如下:
(5)测试,在浏览器输入www.666.com
总结以上流程:
www.666.com域名通过hosts文件与代理服务器的IP:124.70.206.90绑定,Nginx作为代理服务器,通过820端口监听tomcat服务。
六、Nginx反向代理配置实例 二
预期效果:根据访问路径不同跳转到不同端口的服务中。
比如,我们设置nginx的端口为6666;
访问124.70.206.90:6666/static 访问8086的tomcat
访问124.70.206.90:6666/dynamic 访问8087的tomcat
步骤:
(1)启动两个Tmocat服务,端口分别是8086和8087;
(2)为了更直观,先分别在两个Tomcat服务中创建static 和 dynamic文件夹及相应的页面
(3)在nginx.conf中配置方向代理原来的不动,新增一个server ,修改后更新配置或重启Nginx
(PS:这里 ~ 是匹配符号,表示与后面的路径匹配且区分大小写;~*则表示不区分大小写,一般用前一种比较精确)
(4)测试效果
七、负载均衡配置实例
预期效果:浏览器输入同一个地址,但是后端服务器是切换的,及负载均衡,请求平均分配到8086和8087对应的服务
步骤:
(1)启动两个Tmocat服务,端口分别是8086和8087;
(2)在两个tomcat中都创建一个dynamic文件夹及对应的test.html
(3)在nginx.conf中配置负载均衡,先配置一个默认的策略即轮询策略
(4)重启或更新Nginx后测试轮询效果
因为是轮询,所以每次刷新两个tomcat是交替响应的。
其他的策略配置如下:
效果就不演示了。
八、动静分离配置实例
预期效果:不同的路径访问不同的资源
步骤:
(1)准备动态和静态资源(要放到根目录下)
(2)配置Nginx
(3)访问效果
九、高可用配置实例
预期效果:配置两个Nginx服务,一个停下另一个补位,保证服务不间断,主要借助Keepalived和Nginx联合使用进行实现。
步骤:
(1)需要两台服务器(我这边太穷只有一个服务器,这个环节就不演示了,列出主要步骤)
(2)在两台服务器上都安装Nginx
(3)在两台服务器上都安装Keepalived
(4)配置keepalived
十、Nginx原理
查看Nginx进程是会发现它有两个进程:
一个是worker,一个是master。
工作原理我们可以画个总体的图来说明:
(1)
在nginx启动后,会有一个master进程和多个worker进程,master进程主要用来管理worker进程,包括:接受信号,将信号分发给worker进程,监听worker进程工作状态,当worker进程退出时(非正常),启动新的worker进程。基本的网络事件会交给worker进程处理。多个worker进程之间是对等的,他们同等竞争(争抢)来自客户端的请求,各进程互相之间是独立的 。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。一个worker进程出现问题不会影响别的worker。
(2)
当master接收到重新加载的信号会怎么处理(./nginx -s reload)?,master会重新加载配置文件,然后启动新的进程,使用的新的worker进程来接受请求,并告诉老的worker进程他们可以退休了,老的worker进程将不会接受新的,老的worker进程处理完手中正在处理的请求就会退出。
(3)
worker进程是如何处理用户的请求呢?
首先master会根据配置文件生成一个监听相应端口的socket,然后再根据配置(配置文件中,全局块下work process参数)创建相应数量的worker进程,这样每个worker就可以接受从socket过来的消息(其实这个时候应该是每一个worker都有一个socket,只是这些socket监听的地址是一样的)。当一个连接过来的时候,每一个worker都能接收到通知,所有worker相互争抢,但是只有一个worker能和这个连接建立关系,其他的worker都会连接失败。当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接。为了解决争抢问题,nginx提供一个共享锁accept_mutex,有了这个共享锁后,就会只有一个worker能接收到这个客户端请求,而不是所有worker都能接收到。
worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致。原因是Nginx和Redis类似,都是采用IO多路复用机制,每个worker就是一个进程,和CPU核树一致既能保证性能又能不浪费资源,多了会造成CPU频繁切换上下文损耗,少了则浪费CPU资源。
在配置文件even块中有worker_connections 参数,它就代表了每个worker进程独立的连接池的最大容量。下面代表每个worker最多可以支持1024个连接:
events {
worker_connections 1024;
}
一个Nginx能建立的最大连接数 = work_process * worker_connections。
2个或4个,请求静态资源占2个连接,请求动态资源4个 。
若果是普通静态资源访问,每次请求只占2个连接,支持的并发数就是 work_process * worker_connections/2
若果是动态资源访问,每次请求占4个连接,支持的并发数就是 work_process * worker_connections/4