Nginx相关&理解

nginx是一个非常好的技术点,javaWeb可以用到。php更是与nginx有lnmp的组合说法。网站开发可以说nginx是炙手可热的一个技术点了。本篇博客把我对nginx的了解记载下来。后续对nginx的了解也会补充到这篇文章。文章会从如下几方面进行记载。

一.nginx是干什么用的?

二.nginx的优势是什么?

三.nginx的优势是怎么做到的?

四.配置文件相关。

五.nginx的常规操作&一些疑惑解答

六.https相关


 

一.nginx是干什么用的?

Nginx是一款轻量级高性能的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器

(1)上述说的反向代理服务器是什么?

反向代理(Reverse Proxy)方式是指以代理服务器(nginx)来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器(真实处理请求的服务器),并将从内部网络上的服务器上得到的结果返回给Internet上请求连接的客户端。

比如你想访问一个PHP网站。此时你只需要访问nginx上配置的域名www.hello.com→(172.30.22.173)并监听listen一个port 80。 而你真实请求的资源来源是 192.3.4.5:9000这个端口给的。

而你打开网站访问的是www.hello.com你根本不知道192.3.4.5:9000 的存在。

正向代理指的是,一个位于客户端和原始服务器之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。

比如你想访问Google 被墙了。这时你可以访问谷歌在中国的代理服务器,然后代理服务器根据你的请求去Google服务器获取相应并返回给你。

二. nginx的优势是什么?

Nginx可以轻松处理高并发。而且占用的资源相对其他服务器较少,CPU消耗时间少。

性价比高。没有那么多线程之间切换的花销。

其他优势:延迟处理,SSL(安全套接字层),静态内容,压缩和缓存,连接和请求限制所需的关键功能,甚至可以从应用程序中传输HTTP媒体流层到更有效的Web服务器层。

三.Nginx的优势是怎么做到的?

Nginx 采用的是多进程(单线程) & 多路IO复用模型(epoll)。使用了 I/O 多路复用技术是”并发事件驱动“的服务器。

1.进程&线程&协程之间的关系是什么?

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,也是基本的执行单元,是操作系统结构的基础。

每个进程都有自己的独立内存空间,不同进程通过(管道,信号量,共享内存,socket,消息队列等)来通信。由于进程比较重量,占据独立的内存,所以进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。

线程是操作系统能够进行运算调度的最小单位!!意味着一定是通过多线程来实现多核CPU的利用的。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

关于协程的一些额外描述:

一个线程可以多个协程,即一个内核线程对应多个用户协程(用户进程)。
进程、线程,都是有内核进行调度,有CPU时间片的概念,进行抢占式调度(有多种调度算法)
协程的调度与内核无关,完全有程序进行控制。只能进行非抢占式调度。
线程进程都是同步机制,而协程则是异步。
协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

在实现多任务时, 线程切换从系统层面远不止保存和恢复 CPU上下文这么简单。

操作系统为了程序运行的高效性,每个线程都有自己缓存Cache等数据,操作系统会自动实现数据的恢复操作,所以线程的切换非常耗性能。

但是协程的切换只是单纯的操作CPU的上下文,所以一秒钟切换个上百万次系统都抗的住。

以上:如果是单线程所述的异步都是由协程完成的。但是还是由一个CPU调度的,线程是CPU调度的最小单位。即使我们看到的现象是一个异步的现象。但底层实际上是一个线程不断切换协程来实现的。所以单核的切换速度并不变快反而更慢。

一个线程运行多个协程就像一个人推箱子,先推箱子A,推一会推箱子B,箱子AB的位置是被保留现场的。但实际上就一个人。多个人推多个箱子就像多线程多协程工作。

因此如果想利用多核CPU的优势,要么开启多线程,使多协程多线程一起跑。  要么开多进程,使多进程多协程一起跑,来达到异步的效果。

而Nginx就是采用的多进程多协程的事件驱动运行方式来实现的。

golang  python 都是有协程的这个概念的。 golang的 goroutines  Python的gevent 查了一下发现java居然也有,但是我没用过。。 看网上说java的Quasar也是可以的。

2.什么叫多路IO复用?

IO多路复用,将IO过程分为等待内核数据准备好和读取/写入内核两部分。一个IO函数监控多个IO可读/可写事件,任意1个IO设备准备好时返回(需要代码中轮询查看是哪个IO文件描述符,什么事件),再调用对应的read/write函数操作,减少不必要的等待时间,高效了很多。具体的实现有select、poll和epoll三种。

nginx采用的是epoll ,线程主函数不断接收请求。epoll的实现是通过事件驱动。

通过3个函数来实现,更加高效,当前使用也最多。在epoll_ctl中注册事件到epoll文件描述符中,把fd全部拷贝进内核,而不是在epoll_wait中重复拷贝。实现中内核通过为每个fd指定一个回调函数,当fd就绪时调用回调函数把就绪fd加入一个就绪链表,epoll_wait只需要查看这个就绪链表是否有就绪fd就可。可监控文件描述符数是系统可同时打开文件数
原型:
     int epoll_create(int size);  //返回epoll文件描述符,size表示要监听的数目 (这个返回的fd要记得close)
     int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); //epoll事件注册函数
          epfd是epoll_create返回的值
          op是动作:EPOLL_CTL_ADD/EPOLL_CTL_MOD/EPOLL_CTL_DEL分别表示:注册fd到epfd,修改已注册的fd,从epfd删除1个fd
          fd是要监听的fd
          event是告诉内核要监听什么事件
          struct epoll_event{
               __uint32_t events;  //epoll events
               epoll_data_t data; //user data variable
          }
          event是宏的集合:EPOLLIN可读;EPOLLOUT可写;EPOLLPRI紧急数据可读;EPOLLERR发生错误;EPOLLHUP被挂断;EPOLLET将EPOLL设置为边缘触发模式;EPOLLONESHOT只监听1次事件
     int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);  //等待事件发生,events是返回的事件链表;maxevents是events链表元素个数,timeout是等待毫秒数(0表示立即返回,非阻塞;正值表示等待的毫秒数;负值表示无限等待,阻塞模式 ),函数返回值是需要处理的事件数,通过events返回需要处理的事件。(通过events[i].data.fd和events[i].events匹配判断)

当某个进程调用epoll_create方法时,linux内核会创建一个eventpoll结构体,这个结构体中有两个成员与epoll的使用方式密切相关。

struct eventpoll

{

  struct rb_root rbr;//红黑树的根结点,这棵树中存储着所有添加到epoll中的事件,也就是这个epoll监控的事件。线程间共享内存。一个全局变量相当于。

  struct list_head rdllist;//双向链表rdllist保存着将要通过epoll_wait返回给用户的满足条件的事件

};

每一个epoll对象都有一个独立的eventpoll结构体,这个结构体会在内核空间中创造独立的内存,用于存储使用epoll_ctl方法向epoll对象中添加进来的事件。这些事件都会挂到rbr红黑树中,这样,重复添加的事件就可以通过红黑树高效地识别出来。

当相应的事件发生时会调用这里的回调方法,这个回调方法在内核中叫做ep_poll_callback,它会把这样的事件放到上面的rdllist双向链表中。当调用epoll_wait检查是否有发生事件的连接时,只是检查eventepoll对象中的rdllist双向链表是否有epitem元素而已,如果rdllist链表不为空,则把这里的事件复制到用户态内存中,同时将事件数量返回给用户。

3.什么叫事件驱动?

有了线程之后,我们处理并发最直观的做法就是加线程,为了减少线程的启动时间,我们开始使用线程池,预先启动一些线程。随着并发进一步提高,加上外部请求基本上都是IO密集型,使用线程带来的效益开始下降,也就是说在线程的生命周期中IO等待时间远远大于CPU计算时间,另外每个线程大约需要4M的内存,由于内存的限制,单机线程数不会很多。所以初期的Apache、tomcat服务器通常只能处理几千的并发。为了突破单机下的并发问题,以nginx为首的一种叫事件驱动的方案开始流行。

事件驱动编程的架构是预先设计一个事件循环,这个事件循环程序不断地检查目前要处理的信息,根据要处理的信息运行一个触发函数。

在一个进程一个线程中,server接收客户端的请求。创建function解决IO,如果发生阻塞就执行别的请求。不断的循环。

事件驱动和协程的对比

共性

其目的都是为了消除IO阻塞的问题

都是使用单个或少量的线程,减少线程切换带来的性能消耗

不同点

事件驱动较之比较初级,需要用异步回调的方式来写代码

协程可以使用同步的方式写代码,通过库或者语言的调度来实现并发

 

四.配置文件相关。

可以在nginx.conf中引用别的配置文件。很清晰。   include /etc/nginx/conf.d/*.conf;   这个指令写在http里面。然后加一个配置文件  xxx.conf 引用外部的配置文件,拆的比较清晰。

server {
        listen  80;
        server_name www.hello.com;
        root /etc/nginx/html;
        index index.html;
        location / {

        }
}
需要注意这里面的   server_name 所配置的域名。如果你想访问得在  /etc/hosts中配置  127.0.0.1     www.hello.com   使本地dns可以解析到。

然后你其他机器想访问配置   www.hello.com 到上面这个主机的ip就行了。

几个顶级指令
events   一般连接处理
http     HTTP协议流量
mail     Mail协议流量
stream   TCP协议流量

内部指令

location有两种类型的参数: 前缀字符串和正则表达式
前缀字符串
location /home/asd {
    
}
正则表达式
location ~ \.php {    # ~ 表示区分大小写。    ~* \.php  这个 ~*表示不区分大小写  其余规则就是Perl中的正则表达式。
    
}

nginx 日志相关
nginx日志相关的配置有:access_log(访问日志)、log_format(日志格式)、open_log_file_cache、log_not_found、log_subrequest、rewrite_log、error_log。

下面以一个nginx配置文件的所有配置为例。

#定义Nginx运行的用户和用户组
user www www; 

#nginx进程数,通常设置成和cpu的数量相等   #这个是配置用几个CPU跑nginx。  相似的go里面的goroutines设置的 runtime.GOMAXPROCS 一个意思。
worker_processes 4; 

#全局错误日志定义类型,[debug | info | notice | warn | error | crit]     #error_log   file  level  错误日志可配置全局和server的。level尽量高,不然垃圾日志多。
#error_log  /data/nginx/logs/error.log;
#error_log  /data/nginx/logs/error.log  notice;

#日志文件存放路径 access_log path [format [buffer=size | off]]
access_log /data/nginx/logs/lazyegg.com/web/access.log combinedio;   #这个就是客户端访问生成的日志。比如访问403  404  等等你可以来这里看、
#combinedio 是日志格式名称    access_log  file  format   gzip
																	 
#进程pid文件  里面存一个数。这个数正好是ps 命令查出来的那个进程的pid   
#root     15774     1  0 Dec10 ?        00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
#pid        logs/nginx.pid;

#指定进程可以打开的最大描述符:数目
#工作模式与连接数上限
##这个指令是指当(一个nginx进程!!!!)打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx进程数相除,但是nginx分配请求并不是那么均匀,所以最好与ulimit -n 的值保持一致。
#这是因为nginx调度时分配请求到进程并不是那么的均衡,所以假如填写10240,总并发量达到3-4万时就有进程可能超过10240了,这时会返回502错误。
worker_rlimit_nofile 65535;

event

##########  events  #######  这个模块一般配置的是全局的一些东西,连接、请求等等。
events {
    #参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型
    use epoll                                       #epoll 是最顶级的模型
    #单个进程最大连接数(最大连接数=连接数+进程数)
    worker_connections  1024;

#默认是on  使每个可用的worker进程逐个接受新连接。 设置成off会导致惊群现象。会唤醒不必要的worker进程。
    accept_mutex on;  
    
    #keepalive 超时时间
    keepalive_timeout 60;
    
    #客户端请求头部的缓冲区大小。
    client_header_buffer_size 4k;
    
#这个将为打开文件指定缓存,默认是没有启用的,max指定缓存数量,建议和打开文件数一致,inactive是指经过多长时间文件没被请求后删除缓存。
    open_file_cache max=65535 inactive=60s;
    #这个是指多长时间检查一次缓存的有效信息。
    open_file_cache_valid 80s;
#open_file_cache指令中的inactive参数时间内文件的最少使用次数,如果超过这个数字,文件描述符一直是在缓存中打开的,如上例,如果有一个文件在inactive时间内一次没被使用,它将被移除。
    open_file_cache_min_uses 1;
#语法:open_file_cache_errors on | off 默认值:open_file_cache_errors off 使用字段:http, server, location 这个指令指定是否在搜索一个文件是记录cache错误.
    open_file_cache_errors on;
}

http

##############################   http    ##################################

#设定http服务器,利用它的反向代理功能提供负载均衡支持
http{
    #文件扩展名与文件类型映射表
    #Nginx通过服务器端文件的后缀名来判断这个文件属于什么类型,再将该数据类型写入HTTP头部的Content-Type字段中,发送给客户端。
	#比如,当我们打开一个页面,看到一个PNG格式的图片的时候,Nginx是这样发送格式信息的:
	#服务器上有asd.png这个文件,后缀名是png;
	#根据mime.types,这个文件的数据类型应该是image/png;
	#将Content-Type的值设置为image/png,然后发送给客户端。
    include mime.types;
    #默认文件类型  这个类型是直接下载而不是浏览。下载文件的时候可以用这个类型。
    default_type application/octet-stream;
    #默认编码
    charset utf-8;
    #服务器名字的hash表大小
    server_names_hash_bucket_size 128;
    #客户端请求头部的缓冲区大小。
    client_header_buffer_size 32k;
    #客户请求头缓冲大小。
    large_client_header_buffers 4 64k;
    #允许客户端请求的最大单个文件字节数
    client_max_body_size 8m;
    #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
    sendfile on;
    #开启目录列表访问,适合下载服务器,默认关闭。
    autoindex on;
    #此选项允许或禁止使用socke的TCP_CORK的选项,此选项仅在使用sendfile的时候使用
    tcp_nopush on; 
    tcp_nodelay on;
    #长连接超时时间,单位是秒
    keepalive_timeout 120;
#FastCGI相关参数是为了改善网站的性能:减少资源占用,提高访问速度。下面参数看字面意思都能理解。
    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 128k;
    #gzip模块设置
    gzip on; #开启gzip压缩输出。 在响应给client时进行压缩,可以有效的节约带宽,提高响应速度。  不建议压图片视频还有大文件资源,消耗CPU。
    gzip_min_length 1k;    #最小压缩文件大小
    gzip_buffers 4 16k;    #压缩缓冲区
    gzip_http_version 1.0; #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
    gzip_comp_level 2;     #压缩等级
    gzip_types text/plain application/x-javascript text/css application/xml;    #压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn。
    gzip_vary on;
    #开启限制IP连接数的时候需要使用
    #limit_zone crawler $binary_remote_addr 10m;

upstream 负载均衡(这个也是属于http下面)

 upstream lazyegg.net {
  
        #upstream的负载均衡,weight是权重,可以根据机器配置定义权重。weigth参数表示权值,权值越高被分配到的机率越大。
        server 192.168.80.121:80 weight=3;
        server 192.168.80.122:80 weight=2;
        server 192.168.80.123:80 weight=3;

        #nginx的upstream目前支持4种方式的分配
        #1、轮询(默认)
        #每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
        #2、weight
        #指定轮询机率,weight和访问比率成正比,用于后端服务器性能不均的情况。
        #例如:
        #upstream bakend {     #注意此处的bakend(名称自定义)  在配置server的时候需要配置  proxy_pass   http://bakend; 代理到这个服务器组中的一台机器上。
#某台Server允许请求失败的次数,超过最大次数后,在fail_timeout时间内,新的请求将不会分配给这台机器。如果设置为0,Nginx会将这台Server置为永久无效状态
 #默认为10秒。某台Server达到max_fails次失败请求后,在fail_timeout期间内,nginx会认为这台Server暂时不可用,不会将请求分配给它
#    server 192.168.0.14 weight=10 max_fails=3 fail_timeout=15; #max_fails默认为1
#    server 192.168.0.15 backup;     # 后面注明backup表示其余机器挂掉了/都忙时使用这个机器。备胎、
#    server 192.168.0.16 max_conns=100;     # 默认为0.不限制  表示限制分配给这台机器的最大连接数量。
        #}
        #2、ip_hash
#每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。 
#一个主机多次请求时访问的是一个后台服务器。但是这个挂掉了,就凉了。别的机器没有用户的session
        #例如:
        #upstream bakend {
        #    ip_hash;                       #这块加这条命令就代表使用ip_hash方式
        #    server 192.168.0.14:88;
        #    server 192.168.0.15:80;
        #}
        #3、fair(第三方)
#按后端服务器的响应时间来分配请求,响应时间短的优先分配。 就是谁处理的快就表示谁请求少,就让他处理。
        #upstream backend {
        #    server server1;
        #    server server2;
        #    fair;
        #}
        #4、url_hash(第三方)
#按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
#例:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法
        #upstream backend {
        #    server squid1:3128;
        #    server squid2:3128;
        #    hash $request_uri;
        #    hash_method crc32;
        #}

        #tips:
        #upstream bakend{#定义负载均衡设备的Ip及设备状态}{
        #    ip_hash;
        #    server 127.0.0.1:9090 down;
        #    server 127.0.0.1:8080 weight=2;
        #    server 127.0.0.1:6060;
        #    server 127.0.0.1:7070 backup;
        #}
        #在需要使用负载均衡的server中增加 proxy_pass http://bakend/;

        #每个设备的状态设置为:
        #1.down表示单前的server暂时不参与负载
        #2.weight为weight越大,负载的权重就越大。
        #3.max_fails:允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream模块定义的错误
        #4.fail_timeout:max_fails次失败后,暂停的时间。
        #5.backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。

        #nginx支持同时设置多组的负载均衡,用来给不用的server来使用。
        #client_body_in_file_only设置为On 可以讲client post过来的数据记录到文件中用来做debug
        #client_body_temp_path设置记录文件的目录 可以设置最多3层目录
        #location对URL进行匹配.可以进行重定向或者进行新的代理 负载均衡
    }

server (server也是属于http的)

   #虚拟主机的配置
    server {
        #监听端口
        listen 80;
        #域名可以有多个,用空格隔开
        server_name lazyegg.net;
        #默认入口文件名称      这个是相对于root的相对路径
        index index.html index.htm index.php;
        #你要访问的项目的目录  这个要绝对路径
        root /data/www/lazyegg;
        #对******进行负载均衡
        location ~ .*.(php|php5)?$
        {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
#配置URL重写和重定向  这个语法是 rewrite  src  desc  command;    将src的请求重定向到 desc 注意这个是在当前location的基础上搞得。
            #这个重定向操作是很有价值的。
            rewrite .*.a.php /found/  redirect; 
            include fastcgi.conf;
        }
        #图片缓存时间设置
        location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$
        {
            expires 10d;
        }
        #JS和CSS缓存时间设置
        location ~ .*.(js|css)?$
        {
            expires 1h;
        }
        #日志格式设定
        #$remote_addr与$http_x_forwarded_for用以记录客户端的ip地址;
        #$remote_user:用来记录客户端用户名称;
        #$time_local: 用来记录访问时间与时区;
        #$request: 用来记录请求的url与http协议;
        #$status: 用来记录请求状态;成功是200,
        #$body_bytes_sent :记录发送给客户端文件主体内容大小;
        #$http_referer:用来记录从那个页面链接访问过来的;
        #$http_user_agent:记录客户浏览器的相关信息;
        #通常web服务器放在反向代理的后面,这样就不能获取到客户的IP地址了,通过$remote_add拿到的IP地址是反向代理服务器的iP地址。反向代理服务器在转发请求的http头信息中,可以增加x_forwarded_for信息,用以记录原有客户端的IP地址和原来客户端的请求的服务器地址。
        log_format access '$remote_addr - $remote_user [$time_local] "$request" '
        '$status $body_bytes_sent "$http_referer" '
        '"$http_user_agent" $http_x_forwarded_for';
        #定义本虚拟主机的访问日志
        access_log  /usr/local/nginx/logs/host.access.log  main;
        access_log  /usr/local/nginx/logs/host.access.404.log  log404;
        #对 "/connect-controller" 启用反向代理
        location /connect-controller {
            proxy_pass http://192.168.1.100:8888; #不能监听127.0.0.1:80
            proxy_redirect off;             
            proxy_set_header X-Real-IP $remote_addr;
            #后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  
            #以下是一些反向代理的配置,可选。
            proxy_set_header Host $host;
            #允许客户端请求的最大单文件字节数
            client_max_body_size 10m;
            #缓冲区代理缓冲用户端请求的最大字节数,
            #如果把它设置为比较大的数值,例如256k,那么,无论使用firefox还是IE浏览器,来提交任意小于256k的图片,都很正常。如果注释该指令,使用默认的client_body_buffer_size设置,也就是操作系统页面大小的两倍,8k或者16k,问题就出现了。
            #无论使用firefox4.0还是IE8.0,提交一个比较大,200k左右的图片,都返回500 Internal Server Error错误
            client_body_buffer_size 128k;
            #表示使nginx阻止HTTP应答代码为400或者更高的应答。
            proxy_intercept_errors on;
            #后端服务器连接的超时时间_发起握手等候响应超时时间
            #nginx跟后端服务器连接超时时间(代理连接超时)
            proxy_connect_timeout 90;
            #后端服务器数据回传时间(代理发送超时)
            #后端服务器数据回传时间_就是在规定时间之内后端服务器必须传完所有的数据
            proxy_send_timeout 90;
            #连接成功后,后端服务器响应时间(代理接收超时)
            #连接成功后_等候后端服务器响应时间_其实已经进入后端的排队之中等候处理(也可以说是后端服务器处理请求的时间)
            proxy_read_timeout 90;
            #设置代理服务器(nginx)保存用户头信息的缓冲区大小
            #设置从被代理服务器读取的第一部分应答的缓冲区大小,通常情况下这部分应答中包含一个小的应答头,默认情况下这个值的大小为指令proxy_buffers中指定的一个缓冲区的大小,不过可以将其设置为更小
            proxy_buffer_size 4k;
            #proxy_buffers缓冲区,网页平均在32k以下的设置
            #设置用于读取应答(来自被代理服务器)的缓冲区数目和大小,默认情况也为分页大小,根据操作系统的不同可能是4k或者8k
            proxy_buffers 4 32k;
            #高负荷下缓冲大小(proxy_buffers*2)
            proxy_busy_buffers_size 64k;
            #设置在写入proxy_temp_path时数据的大小,预防一个工作进程在传递文件时阻塞太长
            #设定缓存文件夹大小,大于这个值,将从upstream服务器传
            proxy_temp_file_write_size 64k;
        }
        #本地动静分离反向代理配置
        #所有jsp的页面均交由tomcat或resin处理
        location ~ .(jsp|jspx|do)?$ {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:8080;
        }
    }
}

五.nginx的常规操作&一些疑惑解答

下面以ubuntu直接apt-get install 安装的nginx为例。
配置文件的位置在/usr/local/nginx/conf, /etc/nginx, 或 /usr/local/etc/nginx
ubuntu16.04:  /etc/nginx/nginx.conf

ubuntu安装的nginx 在/etc/nginx/sites-available  下的default文件中有默认的配置。指向  /var/www/html  可以改这个文件。

改完了   nginx  -s reload 然后再访问就可以了、

1.fastCGI 代理。  快速通用网关接口  common gateway interface
PHP有这个服务器。(php-fpm)  其他程序也可以装。 php-fpm fastCGI process manager进程管理器。
FastCGI也是语言无关的。其主要行为是将CGI解释器进程保持在内存中并因此获得高效的性能。下面来个配置例子。
server {
    location \.php(.*)$ {
        fastcgi_pass   localhost:9000;    # 如果是PHP一般php-fpm默认是9000端口。按照路由规则将请求路由到PHP服务器
        fastcgi_index  index.php;
        include        fastcgi.conf;      #这个是关键。使用fastcgi.conf文件中的参数,而不是fastcgi_param     

    }
}

两者有区别。            变量$fastcgi_script_name的值是请求的uri
#fastcgi.conf的 SCRIPT_FILENAME是  $document_root$fastcgi_script_name; 表示脚本执行前面有根目录。
#fastcgi_param 中的那个参数是没有document_root的。会导致404 也可以用fastcgi_param 并在location中重写。建议用conf

nginx是多进程的反向代理服务器。 包括一个master分支和多个worker分支。  master负责管理worker分支和读取nginx.conf配置文件。  改完worker会保持原有的配置。直到reload后worker进程才会加载新的配置文件。

2.windows  windows的nginx使用有一些小问题。
使用  start nginx 后台启动nginx   默认使用 conf/nginx.conf配置文件。

关掉nginx 使用 taskkill /F /IM nginx.exe  全干掉。  因为别的 quit什么的命令不知道什么原因有时候没作用。

nginx -s reload 也可以重新加载配置文件。  但是nginx在windows需要非常注意这个命令执行的位置  保证在nginx.exe这个文件夹里执行。
配置环境变量也不行。应该是nginx.conf  配置文件中有一些相对路径的原因导致的。

对于阿里云服务器。  有一个坑。 配置nginx的域名 访问需要在阿里云进行备案


3.有关master进程的强杀和优雅杀掉的区别。
kill -9 (sigkill) 和普通 kill (默认 sigteam) 传给进程的信号量不一样产生的结果。 
kill sigteam 是默认不加数字参数传递的信号量。  进程接到信号量执行类似 nginx -s quit(或stop)的命令 会将worker和master都杀掉、
kill  sigkill  sigkill 信号不能被捕获。 所以进程不知道自己咋死的。因此捕获不了master就没法控制worker进程.从而导致worker进程仍是运行状态,还可以接受请求。

nginx -s quit 会等现有的连接请求处理完再关闭。  nginx -s stop 就直接关闭了。 nginx -s reload 是重新加载配置文件。 不会杀master会杀worker


4.nginx 进程间通信的方式
信号量、socket套接字、共享内存
1.其中信号量是我们执行nginx -s quit等这种命令是通过信号量进行通信给master进程的,然后master进程在作为对应的相应。
2.socket套接字是在master与worker进程之间,通过发送socket进行通信。
3.共享内存,master和worker是父子进程,正常是不会有共享内存的。共享内存我们知道一般是存在在多线程的环境下。而nginx中的master进程会开辟一块内存空间作为共享内存来进行与worker进行一些数据的同步,例如http的连接数信息等。worker与worker进程之间的通信也是通过共享内存来实现的。
nginx有一个现象较惊群现象,就是来了一个请求,正常交给一个worker进程来处理就好了。但是如果共享变量没有加互斥锁的话会导致大量worker进程监听到这个请求,但是真正能拿走这个请求的worker进程只能有一个。这就会导致一个问题。就是其余的worker被唤醒从而增加了CPU开销和资源的消耗。因此共享内存中变量加个互斥锁就会解决这个问题。

5.为什么worker与master采用socketpair这种套接字进行通信? 
nginx会将这个socketpair加入到epoll中,通过事件模块获取该套接字。

6.一些重要指令的用法

location ~ \.php{
    set $var_test "index.php";  #定义变量名为 var_test 值为 index.php  在使用时 $var_test 这么用。 只有字符串类型。
    #配置URL重写和重定向  这个语法是 rewrite  src  desc  command;    将src的请求重定向到 desc 注意这个是在当前location的基础上搞得。
    #这个重定向操作是很有价值的。  需要注意  src的位置必须是 regex正则表达式。
    rewrite .*.a.php /found/  redirect; 
    return 404 http://www.hello.com;  #这个是可选的。可以仅返回状态码,也可以还返回重定向的uri
}

rewrite 后面的那个指令有四个  last  break  permanent  redirect 
last 和break 出现在location外差不多。都是rewrite这行命令之后直接跳转到 desc指定的location了。  
如果在location里面写rewrite是last表示跳出当前location,重新一个请求重走server路、   break就是停止了。

try_files 在上下文的root目录下进行处理。指令可用于检查指定的文件或目录是否存在并进行内部重定向,如果没有指定的文件或目录,则返回特定的状态代码如下这个try_files 可以应对yii框架 将路由写在index.php?controller/action 这种。如果不进行内部uri重写,访问不到的。

location / {
    try_files  $uri/  /index.php?$args @backend ;   #比如请求admin-zy.com 然后没找到。就会重写为 /index.php?admin-zy.com  然后走yii的逻辑。还可以重定向到location
}  

location @backend {
    proxy_pass http://www.s.com;
    sendfile on;                      #默认情况下,nginx会自动处理文件传输,并在发送文件之前就将其复制到缓冲区中。sendfile将直接从一个fd复制到另一个fd
    sendfile_max_chunk 1m;          #设置调用单个sendfile()传输的数据量、
    tcp_nopush    on;               #与sendfile一起用。使nginx通过sendfile获取数据块之后,在一个数据包中发送http响应头。
    tcp_nodelay   on;               #默认就是on 禁用nagle算法。这个算法发包是有大概200ms延迟的并将小包组成大包一起发。禁用了就直接发了。省去延时。
}

location / {
    proxy_pass http://backend;  #这个是一个负载均衡的 upstream配置,配置名为 backend 其中有三个ip
    proxy_bind 192.168.172.38;  #这个就是绑定到这个ip这样每次访问代理不会发生负载均衡操作。
}

关于location的匹配。 先查前缀表达式,再查正则表达式。  前缀表达式的结果作为备胎使用, 正则表达式也匹配则使用正则表达式的location。只有正则表达式不匹配时才用之前的前缀location

location值匹配URI部分,参数是啥跟匹配没关。除非你定义一个  / 的location 然后定义try_files重定向。

如果过程中发生的重定向,将重新匹配location。例如访问 / 然后重定向到 /index.php  会找匹配 /index.php的location 去匹配。

请求匹配要处理的server是通过Host请求头信息
多个server,当访问的域名映射的ip是你的nginx时,会先查找listen的端口,找完端口会寻找server_name 如果有对应就会返回,没有对应的就返回这个listen监听的端口的默认server
这个默认server可以在listen  80  default_server;  声明这个default_server就可以了。  如果没声明就把相同listen的第一个server作为默认server

如果不允许一个没有host头的请求,可以server_name "";
server {
    listen 80;
    server_name "";
    return 444;  #444是一个nginx走向。
}

六.https相关

https 是在 http 和 TCP 中间加上一层加密层 SSL 

浏览器向服务端发送消息时:本质上是浏览器(客户端)使用服务端的公钥来加密信息,服务端使用自己的私钥解密,
浏览器从服务端获取消息是:服务端使用自己私钥加密,浏览器(客户端)使用服务端的公钥来解密信息

在这个过程中,需要保证服务端给浏览器的公钥不是假冒的。证明服务端公钥信息的机构是 CA(数字认证中心)

https默认的端口是443端口。http默认端口是80  所以如果是https的网址不写端口号默认是443

https相对于http消耗的资源要多很多。http是tcp三次握手建立连接。 而https除了这三次握手还需要ssl握手的9个包。

openssl生成证书server.key server.crt  生成这个证书是需要域名的。本地可以测试的。随便生成一个域名。做HTTPS的测试
Key是私用秘钥,通常是RSA算法

Csr是证书请求文件,用于申请证书。在制作csr文件时,必须使用自己的私钥来签署申,还可以设定一个密钥。

crt是CA认证后的证书文,签署人用自己的key给你签署凭证。

key的生成(第一步)
openssl genrsa -out server.key 2048

这样是生成RSA密钥,openssl格式,2048位强度。server.key是密钥文件名。

csr的生成 (第二步)(基于刚刚生成的server.key)
openssl req -new -key server.key -out server.csr,需要依次输入国家,地区,组织,email。最重要的是有一个common name,可以写你的名字或者域名。如果为了https申请,这个必须和域名吻合,否则会引发浏览器警报。生成的csr文件讲给CA签名后形成服务端自己的证书。

crt的生成 (第三步)(基于上两步生成的csr key)
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
注意: 生成的这个目录nginx一定要有访问权限 不然403

如果想将http的请求重定向到https,则还需配置一个server 监听80端口然后跳到https

server {
    listen 443 ssl;
    server_name hello-zy.cn;
    ssl_certificate       /etc/nginx/ssl/server.crt;
    ssl_certificate_key   /etc/nginx/ssl/server.key;
    ssl   on;
    root  /etc/nginx/html;
    index index.html;
    location / {

    }
}

server {
    listen 80;
    server_name hello-zy.cn;
    root /etc/nginx/html;
    index 80index.html;
    location / {
        #return  301 https://$server_name$request_uri;
        #rewrite ^(.*)$  https://$host$1 permanent;     #跟上面这种都行。就是重定向。 permanent就是301的永久重定向。
    }
}

linux curl 301 的问题

需要使用-L参数  如果访问的是https 还需要加 --insecure参数

curl --insecure -L hello-zy.cn 
curl --insecure https://hello-zy.cn

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章