Nginx
我们之前有分析过,单台服务器可能会遇到的问题,比如服务器宕机,或者并发用户太多,单台服务器不够等问题,所以需要集群架构,就是将项目部署到多台服务器。
但这样会出现新的问题:
- 用户发送的请求会被发送到哪台服务器?
- 如果是有软件帮助分发,怎么做到尽量均衡?
对于这些问题的出现,我们可以用Nginx来解决,除此以外,Nginx还可以帮助我们区分动态服务器和静态服务器。
Nginx (engine x) 是一个高性能的Http服务器和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。它可以用做反向代理服务器,邮件服务器,实现负载均衡和动静分离。
稳定性强、丰富的功能集、简单的配置文件和低系统资源的消耗,占用内存少,并发能力强。
中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
docker pull daocloud.io/library/nginx:latest
docker images
docker run -d -p 80:80 --name nginx 29
先进入Nginx容器内部
docker exec -it 容器id bash #进入容器的终端,可以执行一些如ls pwd等一些简单的shell命令
再进入容器的etc/nginx目录下:
将nginx.conf文件的内容复制出来
# 全局块
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
#events块
events {
worker_connections 1024;
}
http {
include /etc/nginx/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 /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
全局块:
从配置文件开始到 events 块之间的内容,主要会设置一些影响nginx 服务器整体运行的配置指令,主要包括配置运行 Nginx 服务器的用户(组)、允许生成的 worker process 数,进程 PID 存放路径、日志存放路径和类型以及配置文件的引入等。
worker_processes 1 #这是 Nginx 服务器并发处理服务的关键配置,worker_processes 值越大,可以支持的并发处理量也越多,但是会受到硬件、软件等设备的制约。
events 块:
events 块涉及的指令主要影响 Nginx 服务器与用户的网络连接,常用的设置包括是否开启对多 work process 下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型来处理连接请求,每个 word process 可以同时支持的最大连接数等。 上述例子就表示每个 work process 支持的最大连接数为 1024. 这部分的配置对 Nginx 的性能影响较大,在实际中应该灵活配置。
http块:
http模块顾名思义,就是关于http服务请求的配置。这些配置包括http请求的文件类型(MIME-TYPE)的定义,http请求日志的输出,http连接的超时时长,单连接请求上限的配置。
http块的最后一句#include /etc/nginx/conf.d/*.conf ,是指引入了conf.d目录下的以.conf为结尾的配置文件。我们找到他们。
default.conf内容如下:
server {
listen 80;
listen [::]:80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/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 /usr/share/nginx/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;
#}
}
去掉注释部分
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
将其替换到nginx.conf文件中的include /etc/nginx/conf.d/*.conf,然后可以看到http块的内容为:
http {
include /etc/nginx/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 /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
http块结构包含:
server块: 每一个Server模块就是一个独立的虚拟主机,每个虚拟的主机可配置不同的域名或IP地址
listen:代表nginx监听的端口号
Location模块:每一台虚拟主机下可能因请求URI的不同而进行不同的响应,所以对这些不同的请求进行 分组,每一个组可以称为一个location
root:将接收到的请求根据/usr/share/nginx/html去查找静态资源
index:默认去上述root里的路径中找到index.html或者index.htm文件
根据上一节的分析,我们知道未来我们需要在nginx容器内部创建不同的的conf文件用来配置nginx,那么可以通过配置数据卷的方式将创建的conf文件放在容器外部。
创建docker-compose.yml文件
version: '3.0'
services:
nginx:
restart: always
image: daocloud.io/library/nginx:latest
container_name: nginx
ports:
- 80:80
volumes:
- /wang/docker_nginx/conf.d/:/etc/nginx/conf.d
运行docker-compose.yml文件
docker-compose up -d
在数据卷中手动创建conf配置文件
cd /wang/docker_nginx/conf.d
vi default.conf
在default.conf文件中输入
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
保存退出
重启docker-compose
docker-compose restart
运行:
代理其实就是一个中介,A和B本来可以直连,中间插入一个C,C就是中介。
刚开始的时候,代理多数是帮助内网client访问外网server用的。
正向代理隐藏了用户,用户的请求被代理服务器接收代替,到了服务器,服务器并不知道用户是谁。
比如我们国内访问谷歌,直接访问访问不到,我们可以通过一个正向代理服务器,请求发到代理服,代理服务器能够访问谷歌,这样由代理去谷歌取到返回数据,再返回给我们,这样我们就能访问谷歌了。
正向代理的用途:
(1)访问原来无法访问的资源,如google
(2) 可以做缓存,加速访问资源
(3)对客户端访问授权,上网进行认证
(4)代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息
反向代理(Reverse Proxy)是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
用户发送请求到服务器,访问的其实是反向代理服务器,用户不知道最终访问的是哪台服务器。
反向代理的作用:
(1)保证内网的安全,阻止web攻击,大型网站,通常将反向代理作为公网访问地址,Web服务器是内网
(2)反向代理服务器是配置在服务端的,客户端不知道访问的到底是哪一台服务器
(3)负载均衡,通过反向代理服务器来优化网站的负载
docker-compose.yml
version: '3.0'
services:
tomcat_01:
restart: always
image: daocloud.io/library/tomcat:8.5.16-jre8
container_name: tomcat_01
ports:
- 8085:8080
environment:
TZ: Asia/Shanghai
volumes:
- /wang/data/tomcat_01_webapps:/usr/local/tomcat/webapps
- /wang/data/tomcat_01_logs:/usr/local/tomcat/logs
tomcat_02:
restart: always
image: daocloud.io/library/tomcat:8.5.16-jre8
container_name: tomcat_02
ports:
- 8086:8080
environment:
TZ: Asia/Shanghai
volumes:
- /wang/data/tomcat_02_webapps:/usr/local/tomcat/webapps
- /wang/data/tomcat_02_logs:/usr/local/tomcat/logs
在两台服务器根目录下分别创建一个index.html页面,用作测试页面。
测试一下:
启动一个nginx服务器,上一章已启动过
找到nginx数据卷目录中创建的default.conf文件
输入命令 vi default.conf 进入编辑状态
修改内容如下:
server {
listen 80;
server_name localhost;
#使用nginx实现反向代理 当访问 http://42.192.12.30/ 时会转到http://42.192.12.30:8085/下
location /{
proxy_pass http://42.192.12.30:8085/;
}
}
运行结果:
在tomcat_02服务器上部署swagger项目后
继续修改default.conf文件
server {
listen 80;
server_name localhost;
#使用nginx实现反向代理 当访问 http://42.192.12.30/swagger 时会转到http://42.192.12.30:8086/swagger下
location /swagger{
proxy_pass http://42.192.12.30:8086;
}
#使用nginx实现反向代理 当访问 http://42.192.12.30/ 时会转到http://42.192.12.30:8085/下
location /{
proxy_pass http://42.192.12.30:8085/;
}
}
我们输入的网址叫做请求URI,nginx用请求URI与location中配置的URI做匹配。
比如我们请求的URI是:http://42.192.12.30/swagger/swagger-ui.html
根据配置文件,当请求主机是http://42.192.12.30 代表进入了Nginx,当路径中有/swagger代表进入了location /swagger,也就是会访问http://42.192.12.30:8086,后面加上相对路径swagger/swagger-ui.html
location是Nginx中的块级指令(block directive),,location指令的功能是用来匹配不同的url请求,进而对请求做不同的处理和响应。
- 首先精确匹配 =
- 其次前缀匹配 ^~
- 其次是按文件中顺序的正则匹配
- 然后匹配不带任何修饰的前缀匹配
- 最后是交给 / 通用匹配
- 当有匹配成功时候,停止匹配,按当前匹配规则处理请求
匹配的时候依照最佳匹配规则,按照能匹配到的最多的规则进行匹配。
如 location ^~ /user/add/ 和 location ^~ /user/,请求 http://localhost/user/add/1.html,会匹配location ^~ /user/add/
绝对路径
location /reg{
proxy_pass http://42.192.12.30:8085/;
}
当访问 http://127.0.0.1/reg 时,nginx匹配到/reg路径,把请求转发给42.192.12.30:8085服务,实际请求路径为
http://42.192.12.30:8085,nginx会去掉匹配的“/reg”。
相对路径
location /reg {
proxy_pass http://42.192.12.30:8085;
}
当访问http://127.0.0.1/reg 时,nginx匹配到/reg路径,把请求转发给42.192.12.30:8085服务,实际请求代理服务器的路径为
http://42.192.12.30:8085/reg, 此时nginx会把匹配的“/reg”也代理给代理服务器。
location = / {#规则A}
location = /login {#规则B}
location ^~ /static/ {#规则C 匹配任何以 /static/ 开头的查询并且停止搜索。任何正则表达式将不会被测试}
location ~ \.(gif|jpg|png|js|css)$ {#规则D}
location ~* \.png$ {#规则E}
location !~ \.js$ {#规则F}
location !~* \.js$ {#规则G}
location / {#规则H}
访问根目录/, 比如http://localhost/ 将匹配规则A
访问 http://localhost/login 将匹配规则 B,http://localhost/register 则匹配规则H
访问 http://localhost/static/a.html 将匹配规则C
访问 http://localhost/b.png 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用
访问 http://localhost/static/c.png 将匹配规则C,D和规则E,但优先匹配到规则C
访问 http://localhost/a.PNG 则匹配规则E, 而不会匹配规则D,因为规则E不区分大小写。
访问 http://localhost/index.js 不会匹配规则F和规则G
访问 http://localhost/index.JS 不会匹配规则G,因为不区分大小写。
规则F,规则G属于排除法,符合匹配规则但是不会匹配到。
访问 http://localhost/goods/id/1 则最终匹配到规则H,因为以上规则都不匹配。
Nginx实现负载均衡的策略包含自带的三种策略和第三方提供的插件方式。
自带的三种策略为:
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
修改default.conf文件
upstream server-list{
server 42.192.12.30:8085;
server 42.192.12.30:8086;
}
server {
listen 80;
server_name localhost;
location /{
proxy_pass http://server-list/;
}
}
upstream模块里面包含了一组upstream服务器,upstream服务器是指上游服务器,也就是nginx所代理的后端服务器。这些服务器可能被赋予了不同的权重、不同的类型甚至可以基于维护等原因被标记为down。
重启nginx服务器测试
结果如下:两个服务器交换。
指定轮询几率,weight和访问比率成正比,也就是权重越高,被分配的几率越大,用于后端服务器性能不均的情况。
修改default.conf文件
upstream server-list{
server 42.192.12.30:8085 weight=6;
server 42.192.12.30:8086 weight=2;
}
server {
listen 80;
server_name localhost;
location /{
proxy_pass http://server-list/;
}
}
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session共享的问题。
修改default.conf文件
upstream server-list{
ip_hash;
server 42.192.12.30:8085 weight=6;
server 42.192.12.30:8086 weight=2;
}
server {
listen 80;
server_name localhost;
location /{
proxy_pass http://server-list/;
}
}
相同ip 进入的是同一台服务器。
之前我们讲过动静分离结构,就是将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开。那么部署的时候呢?
部署的时候也应该分开部署,这样可以提高用户访问静态代码的速度,降低对后台应用访问。
比如我们可以将静态资源放到nginx中,动态资源转发到tomcat服务器中。
修改docker-compose.yml文件
添加静态文件数据卷:
version: '3.0'
services:
nginx:
restart: always
image: daocloud.io/library/nginx:latest
container_name: nginx
ports:
- 80:80
volumes:
- /wang/docker_nginx/conf.d/:/etc/nginx/conf.d
- /wang/docker_nginx/static/:/static #设置nginx根目录下的static文件夹对应到/wang/docker_nginx/static目录
修改conf.d目录下的default.conf文件:
配置静态资源路径
upstream server-list{
ip_hash;
server 42.192.12.30:8085 weight=6;
server 42.192.12.30:8086 weight=2;
}
server {
listen 80;
server_name localhost;
location /html{
root /static; # 根目录下的static对应的是/wang/docker_nginx/static
index index.html index.htm;
}
location /js{
root /static; # 根目录下的static对应的是/wang/docker_nginx/static
autoindex on;
}
location /{
proxy_pass http://server-list/;
}
}
测试:
docker-compose down
docker-compose up -d