Java进阶-Nginx基础

Nginx简介

  1. Nginx (engine x) 一个高性能的HTTP(网络静态资源服务器)和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。
    1. 也就是说Nginx有2大作用
      1. 第一作用作为网络静态资源服务器:用来部署web的静态资源
      2. 第二作用是作为反向代理服务器:作为n个tomcat服务器的代理
    2. 动态请求:需要后台程序处理逻辑,比如:查询数据库数据-》后台技术:web技术
    3. 静态请求:处理静态资源(html、js、css)
    4. Nginx只能处理静态请求,Tomcat技能处理动态请求也能处理动态请求。
  2. Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日、开源。也有商业版本:Nginx plus–> 商业版
  3. 其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
  4. Tomcat: 150并发; Nginx: 并发量官方文档5w,实际3w没有问题,而且占用内存150M左右
  5. 总结:
    1. Nginx就是一个后台服务器软件,跟tomcat一样,把项目包放到软件某个目录下即可
    2. Tomcat既可以存放静态资源、也可以存放动态资源;Nginx专门用来存放静态资源

正向代理和反向代理

正向代理

  1. 正向代理:比如要访问youtube,但是不能直接访问,只能先找个翻墙软件,通过翻墙软件才能访问youtube. 这种方式就叫做正向代理

    图1

  2. 分析
    1. 客户端做代理服务器的相关配置(代理服务器的地址等),然后访问推特网站
    2. 代理服务器会将推特访问包装成访问代理服务器的请求
    3. 防火墙没有对代理服务器进行限制,会访问到墙外部署的代理服务器
    4. 代理服务器获取到封装请求,解封装去访问推特网站服务器
    5. 推特网站响应数据,代理服务器将响应数据进行包装,翻墙到客户端
    6. 客户端拿到包装的响应进行解包展示
  3. 正向代理的特点:
    1. 客户端是知道目标访问地址(代理服务器的地址)
    2. 代理服务器专门对客户端工作的
    3. 这台服务器专门为客户端工作,就是一个代理,所以叫代理服务器

反向代理

  1. 反向代理:指的是用户要访问youtube,但是youtube悄悄地把这个请求交给后台N台服务器中的其中一台来做,这种方式就是反向代理了。

    图1

  2. 分析:
    1. 客户端发送域名请求数据
    2. 由于请求量并发量非常大,因此后台部署了n台服务器
    3. 客户端请求数据先到nginx服务器
    4. nginx服务器来进行分配具体的目标服务器
    5. 目标服务器响应数据给nginx服务器,然后返回给客户端
    6. 这里的nginx服务器也是一个代理作用,但是它不是为客户端做代理,而是为服务器做代理,因此也叫反向代理服务器
  3. 反向代理特点:
    1. 主要给后台应用提供服务,代理的就是服务端,保护服务端,防止对外暴露,客户端有请求找我就行
    2. 对于客户端来说根本不知道请求的URI是有哪个服务器提供的服务
  4. 总结:
    1. 正向与反向:前端->后台,这是代表正方向,代理前端发请求就是正向代理,代理后端接收请求就是反向代理
    2. 正向代理服务就是代替客户端(前端)去向已知的服务器发送请求
    3. 反向代理服务器就是代替后端服务器去接收客户端的请求

负载均衡

常见的负载均衡策略

  1. 使用硬件负载均衡策略,如使用F5,Array等负载均衡器.(比较贵)
  2. 使用软件进行负载均衡Nginx, 自己封装的负载均衡服务器
  3. 如使用阿里云服务器均衡SLB
  4. 使用Nginx+Keepalived
  5. 其他软件负载均衡如LVS(Linux Virtual Server),haproxy等技术

Nginx优点

  1. Nginx 可以在大多数 Unix、Linux OS 上编译运行,并有 Windows 移植版。 Nginx 的1.4.0稳定版已经于2013年4月24日发布,一般情况下,对于新建站点,建议使用最新稳定版作为生产版本,已有站点的升级急迫性不高。
  2. Nginx 的源代码使用 2-clause BSD-like license。
  3. Nginx 是一个很强大的高性能Web和反向代理服务器,它具有很多非常优越的特性:
    1. 在连接高并发的情况下,Nginx是Apache服务器不错的替代品:Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一。能够支持高达 50,000 个并发连接数的响应,感谢Nginx为我们选择了 epoll and kqueue作为开发模型。

nginx安装(单机)

Linux环境

  1. 下载安装包
    1. 打开网址https://nginx.org/,点击右侧download,下载最新的Stable version,点击nginx-1.20.1即可下载nginx-1.20.1.tar.gz
  2. 将安装包上传到Linux的文件目录下:/usr/local/software文件夹下
  3. 安装所需要的依赖库文件:

     yum install pcre -y
     yum install pcre-devel -y
     yum install zlib -y
     yum install zlib-devel -y
    
  4. 将安装包源码解压到指定安装目录

     tar -zxvf nginx-1.20.1.tar.gz -C /usr/local/src
    
  5. cd /usr/local/src/nginx-1.20.1中,ls查看,会发现有个configure命令
  6. ./configure --prefix=/usr/local/nginx 配置将源码编译到哪个目录下
  7. 编译安装: 当前目录下执行 make && make install
  8. 在 /usr/local/nginx目录下,可以看到如下4个目录

     conf 配置文件目录
     html 默认的HTML页面目录 
     logs 日日志存放目录 
     sbin 执行命令目录
    
  9. 常用命令

     启动命令:/usr/local/nginx/sbin/nginx
     关闭命令:/usr/local/nginx/sbin/nginx -s stop
     重启命令:/usr/local/nginx/sbin/nginx -s reload
    
    1. 注意:nginx默认使用的是80端口
    2. 可以使用netstat -ano| grep 80 查看端口
  10. 访问浏览器:http://192.168.122.133(看到欢迎页面说明没问题)
  11. 注意:如果出现这个错误:./configure: error: C compiler cc is not found
    1. 执行这个命令:yum -y install gcc gcc-c++ autoconf automake make

MacOS环境

  1. 安装(可以用 brew 安装)

     //安装(可以用 brew 安装)
     brew install nginx
     //查看 nginx 版本
     nginx -v
     //启动 nginx
     nginx
     //也可以使用下面的命令启动,但是配置文件nginx.conf修改后用这个命令执行不生效,故不建议使用:    
     brew services start nginx
        
     //查看 nginx 是否启动成功
     //在浏览器中访问http://localhost:8080,如果出现欢迎界面,证明成功.
     //备注:端口号是在配置文件 nginx.conf 里面配置的,默认端口是 8080 ,配置文件的位置 /usr/local/etc/nginx
        
     //关闭nginx
     nginx -s stop
        
     //也可以使用下面的命令启动,但是配置文件nginx.conf修改后用这个命令执行不生效,故不建议使用:
    
     brew services stop nginx
     //修改配置后,重新加载nginx
     nginx -s reload
     //可能遇到的问题
     端口被占用: 解决方法,修改 nginx.conf 文件里的端口号
    

Nginx的配置文件

Nginx基础概念

  1. 多进程模式
    1. 在Nginx中会启动Master和Worker两种进程
      1. 启动nginx之后,可以执行ps -ef |grep nginx命令查看,当前默认有1个master 2个worker 进程运行
    2. 其中Master进程主要的工作:
      1. 接收客户端的请求
      2. 向Worker进程发送信号
      3. 监控Worker进程的状态
      4. 当Worker进程退出以后, 会自动重新启动新的Worker进程
    3. 其中Worker进程主要是用来处理客户端的连接
    4. 就是Master进程用来管理,Worker进程用来具体处理任务
    5. 至于多少个Worker进程,在nginx.conf中配置

       //2个worker进程
       worker_processes  2;
       events {
           # 每个worker进程的最大请求连接数
           worker_connections  1024;
       }
      
  2. 配置文件结构
    1. 在/usr/local/nginx/conf目录下有个nginx.conf文件
    2. nginx.conf由多个块组成,最外面的块是main,main包含events和http,http包含多个upstream和多个server,server又包含多个location:
      1. main(全局设置)、server(虚拟主机设置)、upstream(上游服务设置, 负载均衡服务器设置)和 location(URL匹配特定位置的设置)。

         main块设置的指令将影响其他所有设置;
         server块的指令主要用于指定主机和端口;如果有多个服务器,那么对应的就有多个server
         upstream指令主要用于负载均衡,设置一系列的后端服务器;
         location块用于匹配网页位置,就是url中IP地址、域名后面的路径,到底去哪访问
        
      2. 这四者之间的关系式:server继承main,location继承server,upstream既不会继承其他设置也不会被继承。

Nginx通用语法

  1. 配置文件有指令和指令块构成
  2. 每条指令以分号(;)结尾, 指令和参数之间用空格符号进行分隔
  3. 指令块以{}大括号将多条指令组织在一起
  4. include语句允许组合多个配置文件以提升可维护性,导入其他配置文件
  5. 使用#符号添加注释, 提高可读性
  6. 使用$符号引用变量
  7. 部分指令的参数支持正则表达式

常用配置

1.虚拟主机配置

//用于设置监听客户端访问的IP地址、域名 + 端口
server {
    #端口 一个server就对应一个服务,每个服务都有端口
    listen       80;
    #域名
    server_name  localhost;
    
    #资源路径,可以有多个location,用于匹配请求路径
    location / { # /代表默认路径,根,如果找不到其他的路径,就默认到这个路径下
        # nginx服务器的根目录
        root   html;
        # 目录下的文件
        index  index.html index.htm;
    }
}
  1. 一旦访问 http://localhost:80,则就会来到这个server,然后到html文件夹下找到index.html文件

2.日志文件

  1. nginx访问日志放在log/host.access.log下,并且使用main格式(支持自定义格式)
  2. 对于main格式配置如下:

     #日志文件输出格式这个位置相当于全局设置,就是每一通到nginx的日志信息格式
     #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;
        
     查看日志内容命令:tail -n 100 -f access.log
    
  3. 日志文件切分
    1. 系统运行起来之后,我们需要对nginx日志的分析,得到响应耗时的url,请求时间,以及这段时间的请求量和并发量.通过分析找到优化系统的方案.所以需要运维人员对nginx的日志进行切割和分析处理.我们会通过定时器定时将日志按天/小时进行备份.
    2. 实现定时备份日志:
      1. 第一步:分析如何去实现日志切分,编写shell脚本(backuplog.sh)

         #!/bin/sh
         BASE_DIR=/usr/local/nginx
         BASE_FILE_NAME=access.log
                    
         CURRENT_PATH=$BASE_DIR/logs
         BAK_PATH=$BASE_DIR/datalogs
                    
         CURRENT_FILE=$CURRENT_PATH/$BASE_FILE_NAME
         BAK_TIME=`/bin/date -d yesterday +%Y%m%d%H%M`
         BAK_FILE=$BAK_PATH/$BAK_TIME-$BASE_FILE_NAME
         mv $CURRENT_FILE $BAK_FILE
                    
         $BASE_DIR/sbin/nginx -s reopen
        
      2. 修改脚本文件的访问权限:chmod +x backuplog.sh
      3. 第二步:定时任务对脚本进行调度:

         //添加定时调度,会打开一个文本编辑,用于添加任务内容
         crontab -e
         //执行的任务内容,每隔1分钟,执行一下backuplog.sh脚本
         */1 * * * * sh /usr/local/nginx/sbin/backuplog.sh
        

3.location配置(就是要在location中写哪些东西)

  1. 语法规则
    1. 语法规则: location [=|~|~*|^~] /uri/ { … }

       = 开头表示精确匹配
       ^~ 开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码
       ,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)。
       ~ 开头表示区分大小写的正则匹配
       ~*开头表示不区分大小写的正则匹配
       / 通用匹配,任何请求都会匹配到。
       多个location配置的情况下匹配顺序为:
       首先匹配 =,其次匹配^~, 其次是按文件中顺序的正则匹配,最后是交给 / 通用匹配。当
       有匹配成功时候,停止匹配,按当前匹配规则处理请求。
      
  2. 举例使用
    1. 匹配规则如下:

       location = / {
          #规则A
       }
       location = /login {
          #规则B
       }
       location ^~ /static/ {
          #规则C
       }
       location ~ \.(gif|jpg|png|js|css)$ {
          #规则D
       }
       location ~* \.png$ {
          #规则E
       }
              
       location / {
          #规则H
       }
      
    2. 生产效果如下

       访问根目录/, 比如http://localhost/ 将匹配规则A
       访问 http://localhost/login 将匹配规则B
       http://localhost/register 则匹配规则H
       访问 http://localhost/static/a.html 将匹配规则C
       访问 http://localhost/a.gif, http://localhost/b.jpg 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用,而 http://localhost/static/c.png 则优先匹配到 规则C
       访问 http://localhost/a.PNG 则匹配规则E, 而不会匹配规则D,因为规则E不区分大小写。
       访问 http://localhost/a.xhtml 不会匹配规则F和规则G,http://localhost/a.XHTML不会匹配规则G,因为不区分大小写。规则F,规则G属于排除法,符合匹配规则但是不会匹配到,所以想想看实际应用中哪里会用到。
       访问 http://localhost/category/id/1111 则最终匹配到规则H,因为以上规则都不匹配,这个时候应该是nginx转发请求给后端应用服务器,比如FastCGI(php),tomcat(jsp),nginx作为方向代理服务器存在。
      
  3. 实际应用配置如下

     # 不输入任何路径,只输入域名+端口,就直接到首页
     #直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
     #这里是直接转发给后端应用服务器了,也可以是一个静态首页
     # 第一个必选规则
     location = / {
         # proxy_pass 配置反向代理,转发给其他服务
         proxy_pass http://tomcat:8080/index;
     }
         
     # 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
     # 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
     location ^~ /static/ {
         # root代表到当前nginx服务器的目录中去寻找
         root /webroot/static/;
     }
     location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
         root /webroot/res/;
     }
         
     # 没找到任何路径,就会到这个
     #第三个规则就是通用规则,用来转发动态请求到后端应用服务器
     #非静态文件请求就默认是动态请求,自己根据实际把握
     #毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了
     location / {
         proxy_pass http://tomcat:8080/
     }
    

4.全局变量

  1. 官方内置的一些全局变量,配置文件中可以直接使用

     官方配置:http://nginx.org/en/docs
     $args						#请求中的参数值
     $query_string				#同 $args
     $arg_NAME				#GET请求中NAME的值
     $is_args						#如果请求中有参数,值为"?",否则为空字符串
     $uri							#请求中的当前URI(不带请求参数,参数位于$args),可以不同于浏览器传递的$request_uri的值,它可以通过内部重定向,或者使用index指令进行修改,$uri不包含主机名,如"/foo/bar.html"。
     $document_uri			#同 $uri
     $document_root			#当前请求的文档根目录或别名
     $host						#优先级:HTTP请求行的主机名>"HOST"请求头字段>符合请求的服务器名
     $hostname                #主机名
     $https						#如果开启了SSL安全模式,值为"on",否则为空字符串。
     $binary_remote_addr	#客户端地址的二进制形式,固定长度为4个字节
     ...还有很多。。。
    

5.rewrite语法

  1. 用户重定向转发使用,客户端发送一个请求,可以使用rewrite语法重定向到其他地址
  2. if(条件为: =~~*) return、break、rewrite

     if  ($remote_addr = 192.168.122.1)  {
     	   return 401;
     }	
    
  3. rewrite是实现URL重写的关键指令,根据regex(正则表达式)部分内容,重定向到replacement,结尾是flag标记。

     rewrite    <regex>    <replacement>    [flag];
     关键字      正则             替代内容          flag标记
    
    1. 关键字:其中关键字rewrite不能改变
    2. 正则:兼容正则表达式语句进行规则匹配
    3. 替代内容:将正则匹配的内容替换成replacement
    4. flag标记:rewrite支持的flag标记
  4. flag标记说明:
    1. last #本条规则匹配完成后,继续向下匹配新的location URI规则
    2. break #本条规则匹配完成即终止,不再匹配后面的任何规则
    3. redirect #返回302临时重定向,浏览器地址会显示跳转后的URL地址
    4. permanent #返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
  5. rewrite 可以配置在server,location,ifs

6.反向代理配置

  1. 在配置反向代理:

     //proxy_pass url;
     proxy_pass http://192.168.182.100:8080
    
  2. 注意:反向代理之后,服务端获取客户端ip地址为nginx服务器地址,那么如何获取客户端地址呢?需要nginx设置真实的ip地址:

     #设置客户端真实ip地址
     # proxy_set_header x-real-ip $remote_addr;
        
     location = / {
         #设置客户端真实ip地址
         proxy_set_header x-real-ip $remote_addr;
         # proxy_pass 配置反向代理
         proxy_pass http://tomcat:8080/index;
     }
    
    1. $remote_addr:是全局变量,客户端的地址
    2. proxy_set_header:设置请求头
    3. 服务器端要从请求头中获取客户端的真实地址
  3. 使用步骤

    1. 把后台服务搭建好
      1. 部署数据库mysql,运行jar包
    2. 修改配置文件,把请求转发到后台应用
      1. 在/usr/local/nginx/conf/nginx.conf中的location中配置

7.负载均衡配置

  1. 就是一个地址对应n台服务器,那么nginx如何进行转发呢?这里就是配置转发的规则
  2. 设定负载均衡的服务器列表在Server模块配置

     #upstream myproject {
         # 这里可以配置负载均衡的策略,默认是Round Robin 
         #weigth参数表示权值,权值越高被分配到的几率越大
         #max_fails 当有#max_fails个请求失败,就表示后端的服务器不可用,默认为1,将其设置为0可以关闭检查
         #fail_timeout 在以后的#fail_timeout时间内nginx不会再把请求发往已检查出标记为不可用的服务器
     #}
    
  3. 使用默认Round Robin 举例

     #webapp
     upstream myapp {  
         # 这里默认值 Round Robin 
         server 192.168.122.133:8080 weight=1 max_fails=2 fail_timeout=30s;   
         server 192.168.122.134:8080 weight=1 max_fails=2 fail_timeout=30s;   
     } 
    
  4. 负载均衡的策略
    1. upstream第一行可以设置负载均衡的策略,就是当一个地址有n台服务器对应时,以什么规则转发到某个服务器
     Round Robin  每个轮流转发 默认
     Least Connections 最少连接数,那个转发的少就转发到哪个
     IP Hash 客户端请求的ip进行Hash运算
     Generic Hash 自定义Hash的一个取值
     Random 随机发送
    
  5. 举例

     # 定义p2p
     upstream p2p {   
         ip_hash;
         server 192.168.11.130:8888 weight=1;   
         server 192.168.11.194:8888 weight=1; 
         server 192.168.11.225:8888 weight=1; 
     }
     # 转向p2p
     location / {
          proxy_pass http://p2p;
     }
    

动静分离

  1. 静态资源交给nginx处理最合适,动态资源转发给tomcat

    图1

  2. 举例:

     //静态资源访问地址 
     location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
         root /datas/crm/static/;
     }
     //动态请求访问地址
     location / {
         proxy_pass http://localhost:8080;
     }
    
    1. 第一步: 把静态资源存放到nginx可以访问的目录
    2. 第二部: 配置静态资源的目录
  3. 文件上传问题
    1. 文件、图片上传肯定是走动态资源,图片上传到tomcat服务器,那么会将文件资源存储到oss云存储,或者本地磁盘,如果存到了本地磁盘(oss云存储直接通过http访问,无需同步),那么这些静态资源如何同步到 nginx呢?
    2. 解决办法: nginx服务器有个网络磁盘,可以通过ntfs把网络磁盘映射为本地磁盘(百度查询)
  4. 对于静态资源的压缩处理
    1. 满足的条件
      1. 客户端发送的HTTP报头必须含有 “Accept-Encoding” 字段,且其值包含 “gzip” 这个压缩类型。一般浏览器都会发 “Accept-Encoding:gzip, deflate, sdch” 这样的报头。
      2. 服务器启用了gzip压缩,那么响应头会包含 Content-Encoding:gzip, 客户端根据这个来判断服务器返回的内容是否真正为gzip压缩过的内容。
    2. nginx.conf做如下配置
      1. 打开配置文件后,默认是#gzip on;注释的
       # 开启gzip压缩    
       gzip  on;
       # 文件达到多大开始压缩
       gzip_min_length 1k;
       # 压缩基本, 1-9 级别越高, 越消耗cpu, 默认值为1
       gzip_comp_level 2;
       # 压缩文件的类型, 对于jpg,png图片压缩效率不高
       gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript;
       #根据客户端的HTTP头来判断,是否需要解压缩
       gzip_vary on;
      
    3. 做压缩的目的是,会将js等静态资源进行压缩发送给浏览器,浏览器然后进行解压,提高传输效率
Table of Contents