一、Nginx简介
1.简介
Nginx 是高性能的 HTTP 和反向代理的服务器,处理高并发能力是十分强大的,能经受高负载的考验,有报告表明能支持高达 50,000 个并发连接数。
Nginx三大功能:
- 反向代理:暴露的是代理服务器地址,隐藏了真实服务器 IP 地址。
- 负载均衡:增加服务器的数量,然后将请求分发到各个服务器上,将原先请求集中到单个服务器上的情况改为将请求分发到多个服务器上,将负载分发到不同的服务器,也就是我们所说的负载均衡
- 动静分离:动静分离将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问。将静态资源放到nginx中,动态资源转发到tomcat服务器中
2.安装及运行
首先从阿里云镜像仓库拉取我们需要的nginx镜像
docker pull nginx
为了便于我们在后期容器外部宿主机对docker的配置文件进行修改,因此我们需要将nginx的相关配置文件以数据卷的形式挂载在宿主机上,首先我们以交互的方式随便进入一个nginx容器中获取相关配置文件的路径以及内容
docker run -it nginx /bin/bash
进入容器以后分别在以下路径寻找相关文件
- 配置文件路径 /etc/nginx/nginx.conf
- 默认配置文件路径/etc/nginx/conf.d/default.conf
- 默认首页文件夹/usr/share/nginx/html
- 日志文件路径/var/log/nginx
随后以上容器可以将其删除,我们在本地建一个存储nginx相关文件的文件夹
mkdir -p /data/nginx/{conf,conf.d,html,logs}
在conf中挂载配置文件数据卷,conf.d中挂载默认配置文件数据卷,html和logs亦然
同时将上一步查找到的nginx.conf和default.conf文件内容拷贝到本地数据卷中
然后运行一个新的容器,并将数据卷映射关系填好。
docker run --name mynewnginx -d -p 80:80 -v/data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v /data/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf -v /data/nginx/logs:/var/log/nginx nginx
这是通过宿主机80端口就可以访问得到nginx服务器首页了
3.配置文件
#这个值越大,可以支持的并发处理量也越多,会受到硬件、软件等设备的制约
worker_processes 1;
events {
worker_connections 1024;
}
http{
include mime.types;
default_type application/octer-stream;
sendfile on;
keepalive_timeout 65;
server{
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location= /50x.html {
root html;
}
}
}
根据上述文件,我们可以很明显的将nginx.conf配置文件分为三部分
第一部分:全局块
从配置文件开始到events块之间的内容,主要会设置一些影响nginx服务器整体运行的配置指令,主要包括配置运行Nginx服务器的用户(组)、允许生成的worker process数、进程PID存放路径、日志存放路径和类型以及配置文件的引入等。
第二部分:events块
events {
worker_connections 1024;
}
events块涉及的指令主要影响Nginx服务器与用户的网络连接,常见的设置包括是否开启对多work process下的网络连接进行序列化,是否允许同时接收对个网络连接,选取哪种事件驱动模型来处理连接请求,每个wordprocess可以同时支持的最大连接数等。上述例子中就表示每个workprocess支持的最大连接数为1024,这部分的配置对Nginx的性能影响较大,在实际中应该灵活配置
第三部分:http块
这算是 Nginx 服务器配置中最频繁的部分,代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里。需要注意的是:http 块也可以包括 http全局块、server 块。
- http全局块
http全局块配置的指令包括文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。
- server 块
这块和虚拟主机有密切关系,虚拟主机从用户角度看,和一台独立的硬件主机是完全一样的,该技术的产生是为了 节省互联网服务器硬件成本。
每个 http 块可以包括多个 server 块,而每个 server 块就相当于一个虚拟主机。 而每个 server 块也分为全局 server 块,以及可以同时包含多个 locaton 块。
1、全局 server 块
最常见的配置是本虚拟机主机的监听配置和本虚拟主机的名称或IP配置。
2、location 块
一个 server 块可以配置多个 location 块。
这块的主要作用是基于 Nginx 服务器接收到的请求字符串(例如 server_name/uri-string),对虚拟主机名称 (也可以是IP 别名)之外的字符串(例如 前面的 /uri-string)进行匹配,对特定的请求进行处理。地址定向、数据缓 存和应答控制等功能,还有许多第三方模块的配置也在这里进行。
二、三大功能
1.反向代理
1.反向代理方式一
1.实现效果
打开浏览器,在浏览器地址栏输入地址www.123.com,跳转到 liunx系统 tomcat 主页面中
2.准备工作
在本地机C:\Windows\System32\drivers\etc目录下修改hosts文件,添加本地linux域名映射,192.168.19.128就是我们的linux服务器的IP地址
192.168.19.128 123.com
通过docker启动tomcat,使用默认端口8080
docker run -d -p 8080:8080 tomcat:8.5.31
修改本地/data/nginx/conf.d/defalut.conf
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
proxy_pass http://172.17.0.1:8080;
proxy_redirect default;
}
}
在docker中访问宿主的地址即为172.17.0.1
当我们在浏览器输入123.com时,本地ENS解析域名为192.168.19.128地址,随后我们访问该地址80端口,又由于我们的80端口与nginx容器80端口建立了映射关系,所以这个请求直接发到了nginx服务器的80端口,在以上配置文件中,我们设置了nginx监听80端口,并将这个端口收到得请求全部转发到宿主机的8080端口,而宿主机的8080端口又与tomcat容器的8080端口建立了映射,所以这个请求最终由tomcat收到。
注意:当防火墙开启时,nginx的转发请求会被宿主机拒绝,因此我们需要关闭宿主机的防火墙
systemctl status firewalld #查看防火墙状态
systemctl stop firewalld #暂时关闭,服务器重启时又会打开
systemctl disable firewalld #永久关闭
2.反向代理方式二
1.实现效果
使用 nginx反向代理,根据访问的路径跳转到不同端口的服务中nginx 监听端口为9001,
访问 http://123.com/dev/ 直接跳转到 127.0.0.1:8080
访问 http:// 123.com/vod/ 直接跳转到 127.0.0.1:8081
2.准备工作
创建一台端口为8081的tomcat容器实例,并添加数据卷映射关系
docker run -d -p 8081:8080 -v /data/tomcat/tomcat1:/usr/local/tomcat/webapps/vod tomcat:8.5.31
创建一台端口为8080的tomcat容器实例,并添加数据卷映射关系
docker run -d -p 8080:8080 -v /data/tomcat/tomcat2:/usr/local/tomcat/webapps/dev tomcat:8.5.31
分别在tomcat1、tomcat2文件夹下建两个html文件,以便后期容易看出反向代理的效果
在nginx的default.conf中添加如下内容
server {
listen 80;
server_name localhost;
location ~/dev/ {
proxy_pass http://172.17.0.1:8080;
proxy_redirect default;
}
location ~/vod/ {
proxy_pass http://172.17.0.1:8081;
proxy_redirect default;
}
}
2.负载均衡
1.实现效果
浏览器地址栏输入地址 http://123.com/dev/a.html,负载均衡效果,访问平均打到8080和 8081端口中
2.准备工作
- 准备两台tomcat容器,一台8080端口,一台8081端口
- 在两台 tomcat 里面 webapps 目录中,创建名称是dev文件夹,在dev文件夹中创建页面 a.html,用于测试
- 将原本在反向代理中添加的/dev/映射删掉
docker run -d -p 8080:8080 -v /data/tomcat/tomcat1:/usr/local/tomcat/webapps/dev tomcat:8.5.31
docker run -d -p 8081:8080 -v /data/tomcat/tomcat2:/usr/local/tomcat/webapps/dev tomcat:8.5.31
location /{
proxy_pass http://myserver;
}
#以下这个放在server{}外边,http{}里边
upstream myserver{
server 192.168.19.128:8080;
server 192.168.19.128:8081;
}
配置完成之后在浏览器输入123.com/dev/a.html,即可看到负载均衡效果
Nginx 提供了几种分配方式(策略):
- 轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除。
weight: weight 代表权,重默认为 1,权重越高被分配的客户端越多。指定轮询几率,weight 和访问比率成正比,用于后端服务器性能不均的情况。 例如:
upstream server_pool{ server 192.168.5.21 weight=10; server 192.168.5.22 weight=10; }
ip_hash :每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决 session 的问题。 例如:
upstream server_pool{ ip_hash; server 192.168.5.21:80; server 192.168.5.22:80; }
fair(第三方):按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream server_pool{ server 192.168.5.21:80; server 192.168.5.22:80; fair; }
3.动静分离
Nginx 动静分离简单来说就是把动态跟静态请求分开,不能理解成只是单纯的把动态页面和 静态页面物理分离。严格意义上说应该是动态请求跟静态请求分开,可以理解成使用 Nginx 处理静态页面,Tomcat 处理动态页面。动静分离从目前实现角度来讲大致分为两种:
- 把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案
- 是动态跟静态文件混合在一起发布,通过 nginx 来分开
通过 location 指定不同的后缀名实现不同的请求转发。通过 expires 参数设置,可以使浏览器缓存过期时间,减少与服务器之前的请求和流量。具体 Expires 定义:是给一个资 源设定一个过期时间,也就是说无需去服务端验证,直接通过浏览器自身确认是否过期即可, 所以不会产生额外的流量。此种方法非常适合不经常变动的资源。(如果经常更新的文件, 不建议使用 Expires 来缓存),我这里设置3d,表示在这 3 天之内访问这个 URL,发送 一个请求,比对服务器该文件最后更新时间没有变化,则不会从服务器抓取,返回状态码 304,如果有修改,则直接从服务器重新下载,返回状态码 200。
在nginx配置文件中添加如下:
location ~* \.(jsp|png|css)$ {
proxy_pass http://172.17.0.1:8080; #jsp|png|css等文件转发给8080端口的tomcat处理
}
三、原理
master-workers 的机制的好处
首先,对于每个 worker 进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销, 同时在编程以及问题查找时,也会方便很多。其次,采用独立的进程,可以让互相之间不会 影响,一个进程退出后,其它进程还在工作,服务不会中断,master 进程则很快启动新的 worker 进程。当然,worker 进程的异常退出,肯定是程序有 bug 了,异常退出,会导致当 前 worker 上的所有请求失败,不过不会影响到所有请求,所以降低了风险。
需要设置多少个 worker
Nginx 同 redis 类似都采用了 io 多路复用机制,每个 worker 都是一个独立的进程,但每个进 程里只有一个主线程,通过异步非阻塞的方式来处理请求, 即使是千上万个请求也不在话 下。每个 worker 的线程可以把一个 cpu 的性能发挥到极致。所以 worker 数和服务器的 cpu 数相等是最为适宜的。设少了会浪费 cpu,设多了会造成 cpu 频繁切换上下文带来的损耗。
设置 worker 数量
worker_processes 4
#work 绑定 cpu(4 work 绑定 4cpu)
worker_cpu_affinity 0001 0010 0100 1000
#work 绑定 cpu (4 work 绑定 8cpu 中的 4 个) 。
worker_cpu_affinity 0000001 00000010 00000100 00001000
连接数 worker_connection
这个值是表示每个 worker 进程所能建立连接的最大值,所以,一个 nginx 能建立的最大连接 数,应该是 workerconnections workerprocesses。当然,这里说的是最大连接数,对于 HTTP 请 求 本 地 资 源 来 说 , 能 够 支 持 的 最 大 并 发 数 量 是 worker_connections workerprocesses,如果是支持 http1.1 的浏览器每次访问要占两个连接,所以普通的静态访 问最大并发数是: worker_connections workerprocesses /2,而如果是 HTTP 作 为反向代 理来说,最大并发数量应该是 worker_connections worker_processes/4。因为作为反向代理服务器,每个并发会建立与客户端的连接和与后端服 务的连接,会占用两个连接。
附录-配置汇总
复制代码
user nobody; 主模块命令, 指定Nginx的worker进程运行用户以及用户组,默认由nobody账号运行。
worker_processes 1; 指定Nginx要开启的进程数,一般设置为CPU数*核数。
//error log:用来定义全局错设日志文件的路径和日志名称。
日志输出级别有debug,info,notice,warn,error,crit 可供选择,
其中debug输出日志最为详细,crit输出日志最少。
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid; 用来指定进程id的存储文件位置。
//event:设定nginx的工作模式及连接数上限,其中参数use用来指定nginx的工作模式(
这里是epoll,epoll是多路复用IO(I/O Multiplexing)中的一种方式),
nginx支持的工作模式有select ,poll,kqueue,epoll,rtsig,/dev/poll。
其中select和poll都是标准的工作模式,kqueue和epoll是高效的工作模式,
对于linux系统,epoll是首选。
events {
use epoll;
worker_connections 1024;设置nginx每个进程最大的连接数,默认是1024,所以nginx最大的连接数
max_client=worker_processes * worker_connections。
进程最大连接数受到系统最大打开文件数的限制,需要设置ulimit。
}
//以上这块配置代码是对nginx全局属性的配置。
#下面部分是nginx对http服务器相关属性的设置
http {
include mime.types; 主模块命令,对配置文件所包含文件的设定,减少主配置文件的复杂度,相当于把部分设置放在别的地方,然后在包含进来,保持主配置文件的简洁
default_type application/octet-stream; 默认文件类型,当文件类型未定义时候就使用这类设置的。
#log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 指定nginx日志的格式
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on; 开启高效文件传输模式(zero copy 方式),避免内核缓冲区数据和用户缓冲区数据之间的拷贝。
#tcp_nopush on;
#keepalive_timeout 0; 客户端连接超时时间
keepalive_timeout 65;
#gzip on; 设置是否开启gzip模块
#server段是虚拟主机的配置 这里可以写在别的文件中 然后在包含进来,比如写在/usr/local/nginx/vhost/xxx.conf 目录某文件中 然后在包含进来,可以包含多个文件 include /usr/local/nginx/vhost/*;
server {
listen 80; 虚拟主机的监听服务端口
server_name localhost; 用来指定ip或者域名,多个域名用逗号分开
#charset koi8-r;
#access_log logs/host.access.log main;
location / { 地址匹配设置,支持正则匹配,也支持条件匹配,这里是默认请求地址,用户可以location命令对nginx进行动态和静态网页过滤处理
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$ { 将以php为后缀的文件转发到 FastCGI处理. 使用FastCGI默认配置。本地8088端口处理
fastcgi_pass http://127.0.0.1:8088;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
#静态文件,nginx自己处理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root /var/www/public/images;
expires 30d; #缓存时间30天,静态文件更新不多,过期时间可以设大一点。
}
#配置Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
auth_basic_user_file conf/htpasswd;
}
#配置nginx负载均衡的服务器列表
upstream mysvr {
#weigth参数表示权值,权值越高被分配到的几率越大
#本机上的Squid开启3128端口
server 192.168.199.1:88 weight=5;
server 192.168.199.1:80 weight=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;
# }
#}
}