nginx 学习笔记

nginx

Nginx (engine x) 是一款轻量级的 Web 服务器 、反向代理服务器及电子邮件(IMAP/POP3)代理服务器。


nginx简介

nginx的特点

  • 模块化设计:良好的扩展性,可以通过模块方式进行功能扩展。

  • 高可靠性:主控进程和 worker 是同步实现的,一个 worker 出现问题,会立刻启动另一个 worker。

  • 内存消耗低:一万个长连接(keep-alive),仅消耗 2.5MB 内存。

  • 支持热部署:不用停止服务器,实现更新配置文件,更换日志文件、更新服务器程序版本。

  • 并发能力强:官方数据每秒支持 5 万并发;

  • 功能丰富:优秀的反向代理功能和灵活的负载均衡策略

nginx功能

  • 支持静态资源的 web 服务器。
  • http,smtp,pop3 协议的反向代理服务器、缓存、负载均衡;
  • 支持 FASTCGI(fpm) 、支持模块化,过滤器(让文本可以实现压缩,节约带宽)、ssl 及图像大小调整。 内置的健康检查功能
  • 基于名称和 ip 的虚拟主机
  • 定制访问日志
  • 支持平滑升级
  • 支持 KEEPALIVE
  • 支持 url rewrite
  • 支持路径别名
  • 支持基于 IP 和用户名的访问控制。
  • 支持传输速率限制,支持并发数限制。

nginx的架构

主从模式

       Nginx 采用一主多从的主从架构, master 是使用 root 身份启动的,因为 nginx 要工作在 80 端口。而只有管理员才有 权限启动小于低于 1023 的端口。master 主要是负责的作用只是启动 worker,加载配置文件,负 责系统的平滑升级。其它的工作是交给 worker。那么当 worker 被启动之后,也只是负责一些 web 最简单的工作,而其他的工作都是有 worker 中调用的模块来实现的。

        模块之间是以流水线的方式实现功能的。流水线,指的是一个用户请求,由多个模块组合各自的功能依次实现完成的。比如:第一个模块只负责分析请求首部,第二个模块只负责查找数据,第三个模块只负责压缩数据,依次完成各自工作。来实现整个工作的完成。

        他们是如何实现热部署的呢?其实是这样的,我们前面说 master 不负责具体的工作,而是调用 worker 工作,他只是负责读取配置文件,因此当一个模块修改或者配置文件发生变化,是由 master 进行读取,因此此时不会影响到 worker 工作。在 master 进行读取配置文件之后,不会立即的把 修改的配置文件告知 worker。而是让被修改的 worker 继续使用老的配置文件工作,当 worker 工作完毕之后,直接当掉这个子进程,更换新的子进程,使用新的规则。

sendfile 机制

        Nginx 支持 sendfile 机制。所谓 Sendfile 机制,是指:用户将请求发给内核,内核根据用户的请求调用相应用户进程,进程在 处理时需要资源。此时再把请求发给内核(进程没有直接 IO 的能力),由内核加载数据。内核查找到数据之后,会把数据复制给用户进程,由用户进程对数据进行封装,之后交给内核,内核在进行 tcp/ip 首部的封装,最后再发给客户端。这个功能用户进程只是发生了一个封装报文的过程,却要绕 一大圈。因此 nginx 引入了 sendfile 机制,使得内核在接受到数据之后,不再依靠用户进程给予 封装,而是自己查找自己封装,减少了一个很长一段时间的浪费,这是一个提升性能的核心点。

        简单说就是资源的处理,直接通过内核层进行数据传递,避免了数据传递到应用层,应用层再传递到内核层的开销。目前高并发的处理,一般都采用 sendfile 模式。通过直接操作内核层数据,减少应用与内核层数据传递。

I/O 复用机制

       Nginx 通信模型采用 I/O 复用机制。开发模型:epoll 和 kqueue。支持的事件机制:kqueue、epoll、rt signals、/dev/poll 、event ports、select 以及 poll。

       支持的 kqueue 特性包括 EV_CLEAR、EV_DISABLE、NOTE_LOWAT、EV_EOF,可用数据的数量, 错误代码.支持 sendfile、sendfile64 和 sendfilev;文件 AIO;DIRECTIO;支持 Accept-filters 和 TCP_DEFER_ACCEP.

集群

       一组计算机系统构成一个松耦合的多处理器系统,它们之间通过网络实现进程间的通信,实现分布式计算。在客户端看来就像是只有一个服务器。集群可以利用多个计算机进行并行计算从而获得很高的计算速度,也可以用多个计算机做备份,从而使得任何一个机器坏了整个系统还是能正常运行。主要分成三大类( 高可用集群, 负载均衡集群,科学计算集群)

负载均衡集群

       集群中所有的节点都处于活动状态,它们分摊系统的工作负载。一般Web服务器集群、数据库集群和应用服务器集群都属于这种类型

负载均衡

        面对大量用户访问、高并发请求,海量数据,可以使用高性能的服务器、大型数据库,存储设备,高性能Web服务器,采用高效率的编程语言比如(Go,Scala)等,当单机容量达到极限时,我们需要考虑业务拆分和分布式部署,来解决大型网站访问量大,并发量高,海量数据的问题。

        从单机网站到分布式网站,很重要的区别是业务拆分和分布式部署,将应用拆分后,部署到不同的机器上,实现大规模分布式系统。分布式和业务拆分解决了,从集中到分布的问题,但是每个部署的独立业务还存在单点的问题和访问统一入口问题,为解决单点故障,我们可以采取冗余的方式。将相同的应用部署到多台机器上。解决访问统一入口问题,我们可以在集群前面增加负载均衡设备,实现流量分发。

        负载均衡(Load Balance),意思是将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行。是解决高性能,单点故障(高可用),扩展性(水平伸缩)的终极解决方案。

系统的扩展可分为纵向(垂直)扩展和横向(水平)扩展。纵向扩展,是从单机的角度通过增加硬件处理能力,比如CPU处理能力,内存容量,磁盘等方面,实现服务器处理能力的提升,不能满足大型分布式系统(网站),大流量,高并发,海量数据的问题。因此需要采用横向扩展的方式,通过添加机器来满足大型网站服务的处理能力。比如:一台机器不能满足,则增加两台或者多台机器,共同承担访问压力。这就是典型的集群和负载均衡架构,如下图:

在这里插入图片描述
常见的负载均衡方案:

应用集群:将同一应用部署到多台机器上,组成处理集群,接收负载均衡设备分发的请求,进行处理,并返回相应数据。

负载均衡设备:将用户访问的请求,根据负载均衡算法,分发到集群中的一台处理服务器。(一种把网络请求分散到一个服务器集群中的可用服务器上去的设备)

负载均衡的作用(解决的问题):

(1)解决并发压力,提高应用处理性能(增加吞吐量,加强网络处理能力);

(2)提供故障转移,实现高可用;

(3)通过添加或减少服务器数量,提供网站伸缩性(扩展性);

(4)安全防护(负载均衡设备上做一些过滤,黑白名单等处理);

Nginx 负载均衡策略

       nginx 的负载均衡策略分为两大类: 内置策略扩展策略。内置策略包含加权轮询和 ip hash,在默认情况下这两种策略会编译进 nginx 内核,只需在 nginx 配置中指明参数即可。

       扩展策略有很多,如 fair、通用 hash、consistent hash 等,默认不编译进 nginx 内核。由于在 nginx 版本升级中负载均衡的代码没有本质性的变化,因此下面将以 nginx1.0.15 稳定版为例,从 源码角度分析各个策略。

加权轮询

       Nginx 支持加权轮询(Weighted Round Robin)负载均衡。 轮询的原理很简单,首先我们介绍一下轮询的基本流程。如下是处理一次请求的流程图:

在这里插入图片描述
有两点需要注意,
第一,如果可以把加权轮询算法分为先深搜索和先广搜索,那么 nginx 采用的 是先深搜索算法,即将首先将请求都分给高权重的机器,直到该机器的权值降到了比其他机器低,才开 始将请求分给下一个高权重的机器;
第二,当所有后端机器都 down 掉时,nginx 会立即将所有机器 的标志位清成初始状态,以避免造成所有的机器都处在 timeout 的状态,从而导致整个前端被夯住

Ip Hash

Nginx 支持 Ip Hash 负载均衡。
通过 Ip Hash 这种负载均衡策略,可以实现会话粘滞。

Fair

        fair 策略是扩展策略,默认不被编译进 nginx 内核。其原理是根据后端服务器的响应时间判断负载 情况,从中选出负载最轻的机器进行分流。这种策略具有很强的自适应性,但是实际的网络环境往往不 是那么简单,因此要慎用。

通用 Hash、一致性 Hash

这两种也是扩展策略,在具体的实现上有些差别,通用 hash 比较简单,可以以 nginx 内置的变量 为 key 进行 hash,一致性 hash 采用了 nginx 内置的一致性 hash 环,可以支持 memcache。


Nginx 场景

CGI

        CGI(Common Gateway Interface)是Web服务器与外部程序之间通信方式的标准接口。

        在HTML客户填写了表单,并按下了发送(submit)按钮后,表单的内容被发送到了服务器端,一般的,这时就需要有一个服务器端脚本来对表单的内容 进行一些处理,或者是把它们保存起来,或者是按内容进行一些查询,或者是一些别的什么。没有了CGI,WEB的世界就完全失去了它的交互性,所有的信息都变成单向的了,而不能够有任何的反馈。

        有的人认为可以用JavaScript来代替CGI程序,这其实是一个概念上的错误。JavaScript只能够在客户浏览器中运行,而CGI却是工作在服务器上的。他们所做的工作有一些交集,比如表单数据验证一类的,但是JavaScript是绝对无法取代CGI的。但可以这样说,如果一项工作即能够用 JavaScript来做,又可以用CGI来做,那么绝对要使用JavaScript,在执行的速度上,JavaScript比CGI有着先天的优势。只有那些在客户端解决不了的问题,比如和某个远程数据库交互,这时就应该使用CGI了。

        外部程序能生成HTML、图像等动态内容,而服务器处理的方式与那些非外部程序生成的HTML、图像或其他内容的处理方式是相同的,因此CGI程序使你能生成表单内容从而生成动态内容。使用CGI的原因在于它是一个定义良好并被广泛支持的标准,没有CGI就不可能实现动态的Web页面,除非使用一些服务器中提供的特殊方法。由于C语言在平台无关性上表现不错(几乎在任何的系统平台下都有其相应编译器),而且对大多数程序员而言都算得上很熟悉(不像Perl),因此,C是CGI编程的首选语言之一。

        Web服务器可以解析(handles)HTTP协议。当Web服务器接收到一个HTTP请求(request),会返回一个HTTP响应 (response),例如送回一个HTML页面。为了处理一个请求(request),Web服务器可以响应(response)一个静态页面或图片,进行页面跳转(redirect),或者把动态响应(dynamic response)的产生委托(delegate)给一些其它的程序例如CGI脚本,JSP(JavaServer Pages)脚本,servlets,ASP(Active Server Pages)脚本,服务器端(server-side)JavaScript,或者一些其它的服务器端(server-side)技术。

FastCGI

        FastCGI是一个可伸缩地、高速地在HTTP服务器和动态脚本语言间通信的接口(FastCGI接口在Linux下是socket(可以是文件socket,也可以是ip socket)),主要优点是把动态语言和HTTP服务器分离开来。

        多数流行的HTTP服务器都支持FastCGI,包括Apache、Nginx和lightpd。FastCGI接口方式采用C/S架构,分为客户端(HTTP服务器)和服务端(动态语言解析服务器)。

优点缺点

CGI程序有如下优点:

  • 虽然CGI程序主要由Perl编写,但它可以由多种语言写成,一个有Bug的CGI程序不会使Web服务器崩溃。
  • 程序易于引用,WEB设计人员能够在一个Web页面中引用一个写好的脚本。
  • 因为CGI程序在它们的操作系统shell中执行,这些程序与执行同一个CGI程序的其它HTTP请求不会出现并发冲突,所有服务为CGI程序提供支持。

CGI程序还具有如下明显的缺点:

  • CGI程序的应该答时间很长,因为CGI程序在自己的OS Shell中执行,创建一个 OS shell 对OS来说是个大的开销。
  • CGI不具有升级性,例如,如果访问WEB应该程序的人数从50增加到5000,CGI不能自我调整处理负载。因为一个计算机能运行的操作系统进程数是个有限的值。
  • CGI语言不是安全和面向对象的。
  • CGI脚本用于产中HTMNL应该,因此CGI代码HTML混在一起,这不符合表示和业务逻辑分离原则,脚本语言具有平台依赖性。

因为这些缺点,开始人员需要其它CGI方案,Servlet是处理CGI数据的Java技术方案。

CGI与Servlet的区别和联系

        Servlet是一种服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面。 它担当客户请求(Web浏览器或其他HTTP客户程序)与服务器响应(HTTP服务器上的数据库或应用程序)的中间层。 Servlet是位于Web 服务器内部的服务器端的Java应用程序,与传统的从命令行启动的Java应用程序不同,Servlet由Web服务器进行加载,该Web服务器必须包含支持Servlet的Java虚拟机。

        工作模式:客户端发送请求至服务器;服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器;服务器将响应返回客户端。

        与传统的CGI和许多其他类似CGI的技术相比,Java Servlet具有更高的效率,更容易使用,功能更强大,具有更好的可移植性,更节省投资。在未来的技术发展过程中,Servlet有可能彻底取代CGI。

       在传统的CGI中,每个请求都要启动一个新的进程,如果CGI程序本身的执行时间较短,启动进程所需要的开销很可能反而超过实际执行时间。而在Servlet中,每个请求由一个轻量级的Java线程处理(而不是重量级的操作系统进程)。

       在传统CGI中,如果有N个并发的对同一CGI程序的请求,则该CGI程序的代码在内存中重复装载了N次;而对于Servlet,处理请求的是N个线程,只需要一份Servlet类代码。在性能优化方面,Servlet也比CGI有着更多的选择。

  • 方便,Servlet提供了大量的实用工具例程,例如自动地解析和解码HTML表单数据、读取和设置HTTP头、处理Cookie、跟踪会话状态等。

  • 功能强大,在Servlet中,许多使用传统CGI程序很难完成的任务都可以轻松地完成。例如,Servlet能够直接和Web服务器交互,而普通的CGI程序不能。Servlet还能够在各个程序之间共享数据,使得数据库连接池之类的功能很容易实现。

  • 可移植性好,Servlet用Java编写,Servlet API具有完善的标准。因此,为IPlanet Enterprise Server写的Servlet无需任何实质上的改动即可移植到Apache、Microsoft IIS或者WebStar。几乎所有的主流服务器都直接或通过插件支持Servlet。

Nginx 的 FastCGI

        Nginx不支持对外部动态程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket(可以是文件socket,也可以是ip socket)。为了调用CGI程序,还需要一个FastCGI的wrapper,这个wrapper绑定在某个固定socket上,如端口或者文件socket。当Nginx将CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接收到请求,然后派生出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端,这就是Nginx+FastCGI的整个运作过程。

cgi


nginx 使用

sudo brew install nginx // 安装nginx
nginx -s stop // 快速关闭Nginx,可能不保存相关信息,并迅速终止web服务
nginx -s quit // 平稳关闭Nginx,保存相关信息,有安排的结束web服务
nginx -s reload // 因改变了Nginx相关配置,需要重新加载配置而重载
nginx -t // 不运行,仅仅测试配置文件。nginx 将检查配置文件的语法的正确性,并尝试
打开配置文件中所引用到的文件。
nginx -v  // 显示 nginx 的版本

nginx 配置

#user  nobody;

#启动进程,通常设置成和cpu的数量相等
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#PID文件,记录当前启动的nginx的进程ID
#pid        logs/nginx.pid;

events {
    #单个后台worker process进程的最大并发链接数
    worker_connections  1024;
}


#设定http服务器,利用它的反向代理功能提供负载均衡支持
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 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,对于
    #必须设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,以平衡磁盘与网络I/O处理速度,降低系统的uptime.
    sendfile        on;
    #tcp_nopush     on;

    #连接超时时间
    keepalive_timeout  110;

    #gzip压缩开关
    #gzip  on;

     #设定实际的服务器列表
    upstream zp_server1{
        server 127.0.0.1:8089;
    }

    server {
        listen       8080;

        #定义使用www.xx.com访问
        server_name  www.hua.com;

        #首页
        index index.html;

        #编码格式
        charset utf-8;

        # 设置根目录 location中有,可以覆盖
        root /Users/davidzhang/Desktop/www;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root /Users/davidzhang/Desktop/www/draw;
            index  demo.html;
        }

        #反向代理的路径(和upstream绑定),location 后面设置映射的路径
        location /api {
            proxy_pass http://zp_server1;
        }

        #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;
        #}
    }

    server{
        listen 8888;
        server_name localhost;
        
        location /{
            proxy_pass http://localhost:3000;
        }
        
        location /api{
            proxy_pass https://admin.derify.exchange/api;
        }
    }



    # 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配置参数(选择性配置)
	ssl_session_cache shared:SSL:1m;
 	ssl_session_timeout 5m;

   #数字签名,此处使用MD5
   ssl_ciphers HIGH:!aNULL:!MD5;
   ssl_prefer_server_ciphers on;
   

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    include servers/*;
}



https

  server {
   listen  443 ssl;
   server_name  www.test.com;
   ssl_certificate  my.crt;         #指定证书位置,默认在当前目录寻找
   ssl_certificate_key  my.key;     #指定私钥位置
   


   location / { 
      root   /var/www/html;         #指定网页文件根路径,与http网站路径分开,便于区分
      index  index.html;
  }

}

参考文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值