• nginx使用记录


    本文档仅记录在试用过程中遇到的问题及注意事项,将根据使用经验不断完善。

    本文内容:

    1. 支持websocket的ws://协议,并记录windows中配置添加成功后仍报404错误的解决思路。
    2. SaaS模式下,根据不同的域名、端口、请求路径,代理到不同地址、端口的应用服务器
    3. 开启大文件传输支持,由于系统中没有做分片上传,又有单次500+m的上传量,现在nginx配置中解决问题,后期还是要优化系统上传机制

    使用nginx

    支持websocket (ws://)

    1. 环境

      操作系统:windows Server 2016/windows 10

      nginx版本:nginx 1.15.7

      tomcat + websocket + java

    2. nginx配置支持websocket协议

    location{
    	...
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        ...
    }
    

    404问题

    nginx关于websocket的配置:

    server {
    	   listen       9999;
           server_name  test1.com.cn;
           location  /ws {
                proxy_http_version 1.1;
                proxy_pass       http://abc.def.ghi.123:9999/ws;
                proxy_set_header Origin "";
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
                proxy_connect_timeout 60s;
                proxy_read_timeout 120s;
                proxy_send_timeout 120s;
    
            }
    }
    

    问题描述

    开发环境没问题,可正常连接websocket服务并接收消息。

    测试环境(无nginx代理),通过域名、公网ip访问也都没有问题。

    生产环境(通过nginx代理),出现问题:

    ​ 配置好nginx后,在控制台输入nginx -t检查配置文件无问题,nginx -s reload刷新nginx配置。

    ​ 客户端(浏览器)通过域名访问项目时(websocket请求链接为ws://abc.def.ghi.123:9999/ws),浏览器console报错404

    问题排查

    排查:

    1. 配置问题(各种百度后,都是加proxy_http_version 1.1、及两个 upgrade将协议升级成websocket协议的配置就可以),排查后不是nginx配置的问题

    2. 协议问题,有资料说需要ssl协议证书,不过这是针对wss方式的,项目中使用实现的websocket的方式为ws,所以也不是这个问题。

    3. 客户端请求地址路径错误问题

      1. 最开始一看到报错就先怀疑的路径问题,查了nginx日志发现代理过去了,又去应用服务器查看tomcat的日志,发现tomcat返回了404;

        websocket第一次握手时是http协议,仍然会请求tomcat,握手后才会告诉服务端“我是websocket”进而将协议升级为upgrade/websocket协议。

      2. 使用websocket在线测试工具,例如:http://www.websocket-test.com/,发现也访问不到ws://abc.def.ghi.123:9999/ws,于是想着线下模拟场景排查一下。

      3. 在线下模拟配置相似环境(windows10+nginx1.15.7+tomcat9),发现路径没问题,可以访问到。

      4. 也就是在线下模拟的时候,发现了一个问题,执行 nginx -s reload,nginx配置并没有立即生效,为了验证,又重新改了一下配置文件并reload刷新,新加的nginx配置仍未生效,查看系统进程,发现nginx起了十几个进程,这下忽然就看到了希望。

        把nginx停掉,然后把系统进程里的nginx进程全部杀掉,再次启动一个nginx,发现新增配置生效。

      5. 去线上把nginx停掉,重新启动,发现websocket可正常访问了。

    小结

    ​ windows版本的nginx 1.15.7更新配置后执行nginx -s reload,有时候会重新启动一个进程但是并不结束之前正在运行的进程,因此新修改的nginx配置也没有生效,所以我目前若更改完配置文件后都会先nginx -s stop停止nginx,然后再start nginx,这样配置文件是生效的。

    支持websocket (wss://)

       需要在nginx中配置ssl安全证书。
       此项还没有深入了解,项目中目前没有使用到,闲余会继续尝试,补充本文档。
    

    nginx代理配置

    根据“ 域名:端口号 ”代理到不同/相同服务ip的不同端口

    #映射到web服务(80端口),客户端请求地址 test1.com.cn
    server {
            listen       80;
            server_name  test1.com.cn;
            location / {
    		proxy_pass       http://abc.def.ghi.123;
    		proxy_set_header Host      $host;
    		proxy_set_header X-Real-IP $remote_addr;
    		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    	}
    }
    #映射到跟web服务在同一服务器的websocket服务(9999端口),客户端请求地址 ws://test1.com.cn:9999/ws
    server {
    	listen       9999;
        server_name  test1.com.cn;
        location  /ws {
    		proxy_http_version 1.1;
    		proxy_pass       http://abc.def.ghi.123:9999/ws;
    		proxy_set_header Host $host:$server_port;
    		proxy_set_header Origin "";
    		proxy_set_header Upgrade $http_upgrade;
    		proxy_set_header Connection "upgrade";
    		proxy_connect_timeout 60s;
    		proxy_read_timeout 120s;
    		proxy_send_timeout 120s;
    		
    	}
    }
     server {
    	listen       80;
        server_name  test3.com.cn;
        location  / {
    		proxy_http_version 1.1;
    		proxy_pass       http://abc.def.ghi.124;  #代理到不同ip地址的服务器
    		proxy_set_header Host $host:$server_port;
    		proxy_set_header Origin "";
    		proxy_set_header Upgrade $http_upgrade;
    		proxy_set_header Connection "upgrade";
    		proxy_connect_timeout 60s;
    		proxy_read_timeout 120s;
    		proxy_send_timeout 120s;
    		
    	}
    }
    

    开启大文件配置

    在http模块中添加配置

    http{
        ...
        client_max_body_size       1024m; 
        client_body_buffer_size    10m; 
        ...
        server{
            ....
        }
        server{
            ....
        }
    }
    
    

    client_max_body_size
    client_max_body_size 默认 1M,表示 客户端请求服务器最大允许大小,在“Content-Length”请求头中指定。如果请求的正文数据大于client_max_body_size,HTTP协议会报错 413 Request Entity Too Large。就是说如果请求的正文大于client_max_body_size,一定是失败的。如果需要上传大文件,一定要修改该值。
    client_body_buffer_size
    Nginx分配给请求数据的Buffer大小,如果请求的数据小于client_body_buffer_size直接将数据先在内存中存储。如果请求的值大于client_body_buffer_size小于client_max_body_size,就会将数据先存储到临时文件中,临时文件在client_body_temp 指定的路径中,linux中默认该路径值是/tmp/.

    关于nginx对于请求头请求体的配置,直接复制一篇博客过来,之后会根据实践再整理一下

    以下内容出处:
    https://www.cnblogs.com/zh-dream/p/12825289.html
    1、内存及磁盘资源分配
    1.1 在磁盘中存储HTTP请求体
    语法: client_body_in_file_only on|clean|off;
    默认: client_body_in_file_only off;
    配置块: http、 server、 location
    当值为非off时, 用户请求中的HTTP包体一律存储到磁盘文件中, 即使只有0字节也会存储为文件。

    当请求结束时,如果配置为on,则这个文件不会被删除(该配置一般用于调试、定位问题),但如果配置为clean,则会删除该文件。

    1.2 HTTP包体尽量写入到一个内存buffer中
    语法:client_body_in_single_buffer on|off;
    默认:client_body_in_single_buffer off;
    配置块:http、server、location
    用户请求中的HTTP包体一律存储到内存buffer中。当然,如果HTTP包体的大小超过了下面client_body_buffer_size设置的值,包体还是会写入到磁盘文件中。

    1.3 存储HTTP头部的内存buffer大小
    语法:client_header_buffer_size size;
    默认:client_header_buffer_size 1k;
    配置块:http、server
    上面配置项定义了正常情况下Nginx接收用户请求中HTTP header部分(包括HTTP行和HTTP头部)时分配的内存buffer大小。有时,请求中的HTTP header部分可能会超过这个大小,这时large_client_header_buffers定义的buffer将会生效。

    1.4 存储超大HTTP头部的内存buffer大小
    语法:large_client_header_buffers number size;
    默认:large_client_header_buffers 4 8k;
    配置块:http、server
    large_client_header_buffers定义了Nginx接收一个超大HTTP头部请求的buffer个数和每个buffer的大小。如果HTTP请求行(如GET/index HTTP/1.1)的大小超过上面的单个buffer,则返回"Request URI too large"(414)。请求中一般会有许多header,每一个header的大小也不能超过单个buffer的大小,否则会返回"Bad request(400)。当然,请求行和请求头部的总和也不可以超过 buffer个数 * buffer 大小。

    1.5 存储HTTP包体的内存buffer大小
    语法:client_body_buffer_size size;
    默认:client_body_buffer_size 8k/16k;
    配置块:http、server、location
    上面配置项定义了Nginx接收HTTP包体的内存缓冲区大小。也就是说,HTTP包体会先接收到指定的这块缓存中,之后才决定是否写入磁盘。

    注意:如果用户请求中含有HTTP头部Content-Length,并且其标识的长度小于定义的buffer大小,那么Nginx会自动降低本次请求所使用的内存buffer,以降低内存消耗。

    client_max_body_size
    语法: client_max_body_size size;

    默认: client_max_body_size 1m;

    配置块: http, server, location
    设置客户端请求主体的最大允许大小,在“Content-Length”请求头字段中指定。如果请求中的大小超过了配置值,则将413(请求实体过大)错误返回给客户端。请注意浏览器不能正确显示此错误。将大小设置为0禁用客户端请求主体大小的检查。

    浏览器在发送含有较大HTTP包体的请求时, 其头部会有一个Content-Length字段,client_max_body_size是用来限制Content-Length所示值的大小的。 因此, 这个限制包体的配置非常有用处, 因为不用等Nginx接收完所有的HTTP包体——这有可能消耗很长时间——就可以告诉用户请求过大不被接受。例如, 用户试图上传一个10GB的文件, Nginx在收完包头后, 发现Content-Length超过client_max_body_size定义的值, 就直接发送413("Request EntityToo Large")响应给客户端。

    1.6 HTTP包体的临时存放目录
    语法:client_body_temp_path dir-path[level1[level2[level3]]]
    默认:client_body_temp_path client_body_temp;
    配置块:http、server、location
    上面配置项定义HTTP包体存放的临时目录。在接收HTTP包体时,如果包体的大小大于client_body_buffer_size,则会以一个递增的整数命名并存放到client_body_temp_path指定的目录中。后面跟着的level1、level2、level3,是为了防止一个目录下的文件数量太多,从而导致性能下降,因此使用了level参数,这样可以按照临时

    件名最多再加三层目录。例如:client_body_temp_pathoptnginx/client_temp 1 2;如果新上传的HTTP包体使用00000123456作为临时文件名,就会被存放在这个目录中。optnginx/client_temp/6/45/00000123456

    1.7 connection_pool_size
    语法:connection_pool_size size;
    默认: connection_pool_size ;
    配置块: http、 server
    Nginx对于每个建立成功的TCP连接会预先分配一个内存池,上面的size配置项将指定这个内存池的初始大小(即ngx_connection_t结构体中的pool内存池初始大小,),用于减少内核对于小块内存的分配次数。需慎重设置,因为更大的size会使服务器消耗的内存增多,而更小的size则会引

    更多的内存分配次数。一般不设置

    1.8 request_pool_size
    语法:request_pool_size size;
    默认:request_pool_size 4k;
    配置块:http、server
    Nginx开始处理HTTP请求时,将会为每个请求都分配一个内存池,size配置项将指定这个内存池的初始大小(即ngx_http_request_t结构体中的pool内存池初始大小),用于减少内核对于小块内存的分配次数。TCP连接关闭时会销毁connection_pool_size指定的连接内存池,HTTP请求结束

    会销毁request_pool_size指定的HTTP请求内存池,但它们的创建、销毁时间并不一致,因为一个TCP连接可能被复用于多个HTTP请求。

    2、网络连接设置
    2.1 读取HTTP头部的超时时间
    语法:client_header_timeout time(默认单位:秒);
    默认:client_header_timeout ;

    配置块:http、server、location
    客户端与服务器建立连接后将开始接收HTTP头部,在这个过程中,如果在一个时间间隔(超时时间)内没有读取到客户端发来的字节,则认为超时,并向客户端返回408( " Request timed out " )响应。

    2.2 读取HTTP包体的超时时间
    语法:client_body_timeout time(默认单位:秒);
    默认:client_body_timeout ;
    配置块:http、server、location
    此配置项与client_header_timeout相似,只是这个超时时间只在读取HTTP包体时才有效。如果超时,同样报408( " Request timed out " )响应

    2.3 发送响应的超时时间
    语法:send_timeout time;
    默认:send_timeout ;
    配置块:http、server、location
    这个超时时间是发送响应的超时时间,即Nginx服务器向客户端发送了数据包,但客户端一直没有去接收这个数据包。如果某个连接超过send_timeout定义的超时时间,那么Nginx将会关闭这个连接。

    2.4 lingering_close
    语法:lingering_close off|on|always;
    默认:lingering_close on;
    配置块:http、server、location
    该配置控制Nginx关闭用户连接的方式。always表示关闭用户连接前必须无条件地处理连接上所有用户发送的数据。off表示关闭连接时完全不管连接上是否已经有准备就绪的来自用户的数据。on是中间值,一般情况下在关闭连接前都会处理连接上的用户发送的数据,除了有些情况下在业务上认定这之后的数据是不必要的。

    2.5 lingering_time
    语法:lingering_time time;
    默认:lingering_time 30s;
    配置块:http、server、location
    lingering_close启用后,这个配置项对于上传大文件很有用。上文讲过,当用户请求的 Content-Length大于max_client_body_size配置时,Nginx服务会立刻向用户发送413(Requestentity too large)响应。

    但是,很多客户端可能不管413返回值,仍然持续不断地上传HTTP body,这时,经过了lingering_time设置的时间后,Nginx将不管用户是否仍在上传,都会把连接关闭掉。

    2.6 lingering_timeout
    语法:lingering_timeout time;
    默认:lingering_timeout 5s;
    配置块:http、server、location
    lingering_close生效后,在关闭连接前,会检测是否有用户发送的数据到达服务器,如果超过lingering_timeout时间后还没有数据可读,就直接关闭连接;否则,必须在读取完连接缓冲区上的数据并丢弃掉后才会关闭连接。

    2.8 对某些浏览器禁用keepalive功能
    语法:keepalive_disable[msie6|safari|none]...
    默认:keepalive_disablemsie6 safari
    配置块:http、server、location
    HTTP请求中的keepalive功能是为了让多个请求复用一个HTTP长连接,这个功能对服务器的性能提高是很有帮助的。但有些浏览器,如IE 6和Safari,它们对于使用keepalive功能的POST请求处理有功能性问题。因此,针对IE 6及其早期版本、Safari浏览器默认是禁用keepalive功能的。

    2.9 keepalive超时时间
    语法:keepalive_timeout time(默认单位:秒);
    默认:keepalive_timeout ;
    配置块:http、server、location
    一个keepalive连接在闲置超过一定时间后(默认的是75秒),服务器和浏览器都会去关闭这个连接。当然,keepalive_timeout配置项是用来约束Nginx服务器的,Nginx也会按照规范把这个时间传给浏览器,但每个浏览器对待keepalive的策略有可能是不同的。,MSIE关闭保持活动连接为60秒

    2.10 一个keepalive长连接上允许承载的请求最大数
    语法:keepalive_requests n;
    默认:keepalive_requests ;
    配置块:http、server、location
    一个keepalive连接上默认最多只能发送100个请求。

    2.11 tcp_nodelay
    语法:tcp_nodelay on|off;
    默认:tcp_nodelay on;
    配置块:http、server、location
    确定对keepalive连接是否使用TCP_NODELAY选项。它在SSL连接上启用,用于无缓冲的代理,以及用于WebSocket代理。

    2.12 tcp_nopush
    语法:tcp_nopush on|off;
    默认:tcp_nopush off;
    配置块:http、server、location
    在打开sendfile选项时,确定是否开启FreeBSD系统上的TCP_NOPUSH或Linux系统上的TCP_CORK功能。打开tcp_nopush后,将会在发送响应时把整个响应包头放到一个TCP包中发送。

    3、对客户端请求的限制
    3.1 按HTTP方法名限制用户请求
    语法: limit_except method...{...}
    配置块: location
    Nginx通过limit_except后面指定的方法名来限制用户请求。 方法名可取值包括: GET、HEAD、 POST、 PUT、 DELETE、 MKCOL、 COPY、 MOVE、 OPTIONS、 PROPFIND、PROPPATCH、 LOCK、 UNLOCK或者PATCH。 例如:

    limit_except GET {
    allow 192.168.1.0/;
    deny all;
    }
    注意, 允许GET方法就意味着也允许HEAD方法。 因此, 上面这段代码表示的是禁止GET方法和HEAD方法, 但其他HTTP方法是允许的。

    3.2 对请求的限速
    语法: limit_rate speed;
    默认: limit_rate ;
    配置块: http、 server、 location、 if
    此配置是对客户端请求限制每秒传输的字节数。 speed可以使用多种单位, 默认参数为0, 表示不限速。针对不同的客户端, 可以用$limit_rate参数执行不同的限速策略。 例如:

    server {
    if ($slow) {
    set $limit_rate 4k;
    }
    }
    3.3 limit_rate_after
    语法: limit_rate_after time;
    默认: limit_rate_after 1m;
    配置块: http、 server、 location、 if
    此配置表示Nginx向客户端发送的响应长度超过limit_rate_after后才开始限速。 例如:

    limit_rate_after 1m;
    limit_rate 100k;
    4、文件操作的优化配置项
    4.1 sendfile系统调用
    语法: sendfile on|off;
    默认: sendfile off;
    配置块: http、 server、 location
    可以启用Linux上的sendfile系统调用来发送文件, 它减少了内核态与用户态之间的两次内存复制, 这样就会从磁盘中读取文件后直接在内核态发送到网卡设备, 提高了发送文件的效率。

    4.2 打开文件缓存
    语法: open_file_cache max=N[inactive=time]|off;
    默认: open_file_cache off;
    配置块: http、 server、 location
    文件缓存会在内存中存储以下3种信息:

    文件句柄、 文件大小和上次修改时间。
    已经打开过的目录结构。
    没有找到的或者没有权限操作的文件信息。
    这样, 通过读取缓存就减少了对磁盘的操作。该配置项后面跟3种参数。

    max: 表示在内存中存储元素的最大个数。 当达到最大限制数量后, 将采用LRU(Least Recently Used) 算法从缓存中淘汰最近最少使用的元素。
    inactive: 表示在inactive指定的时间段内没有被访问过的元素将会被淘汰。 默认时间为60秒。
    off: 关闭缓存功能。
    例如:

    open_file_cache max= inactive=20s;
    4.3 是否缓存打开文件错误的信息
    语法: open_file_cache_errors on|off;
    默认: open_file_cache_errors off;
    配置块: http、 server、 location
    此配置项表示是否在文件缓存中缓存打开文件时出现的找不到路径、 没有权限等错误信息。

    4.4 不被淘汰的最小访问次数
    语法: open_file_cache_min_uses number;
    默认: open_file_cache_min_uses ;
    配置块: http、 server、 location
    它与open_file_cache中的inactive参数配合使用。 如果在inactive指定的时间段内, 访问次数超过了open_file_cache_min_uses指定的最小次数, 那么将不会被淘汰出缓存。

    (8) 检验缓存中元素有效性的频率

    语法: open_file_cache_valid time;
    默认: open_file_cache_valid 60s;
    配置块: http、 server、 location
    默认为每60秒检查一次缓存中的元素是否仍有效。

    5、对客户端请求的特殊处理
    5.1 忽略不合法的HTTP头部
    语法: ignore_invalid_headers on|off;
    默认: ignore_invalid_headers on;
    配置块: http、 server
    如果将其设置为off, 那么当出现不合法的HTTP头部时, Nginx会拒绝服务, 并直接向用户发送400(Bad Request) 错误。如果将其设置为on, 则会忽略此HTTP头部。

    5.2 HTTP头部是否允许下划线语法: underscores_in_headers on|off;
    默认: underscores_in_headers off;
    配置块: http、 server
    默认为off, 表示HTTP头部的名称中不允许带“_”(下划线) 。

    5.3 对If-Modified-Since头部的处理策略
    语法: if_modified_since[off|exact|before];
    默认: if_modified_since exact;
    配置块: http、 server、 location
    出于性能考虑, Web浏览器一般会在客户端本地缓存一些文件, 并存储当时获取的时间。 这样, 下次向Web服务器获取缓存过的资源时, 就可以用If-Modified-Since头部把上次获取的时间捎带上, 而if_modified_since将根据后面的参数决定如何处理If-Modified-Since头部。

    相关参数说明如下。

    off: 表示忽略用户请求中的If-Modified-Since头部。 这时, 如果获取一个文件, 那么会正常地返回文件内容。 HTTP响应码通常是200。
    exact: 将If-Modified-Since头部包含的时间与将要返回的文件上次修改的时间做精确比较, 如果没有匹配上, 则返回200和文件的实际内容, 如果匹配上, 则表示浏览器缓存的文件内容已经是最新的了, 没有必要再返回文件从而浪费时间与带宽了, 这时会返回304 Not Modified, 浏览器收到后会直接读取自己的本地缓存。
    before: 是比exact更宽松的比较。 只要文件的上次修改时间等于或者早于用户请求中的If-Modified-Since头部的时间, 就会向客户端返回304 Not Modified。
    5.4 返回错误页面时是否在Server中注明Nginx版本
    语法: server_tokens on|off;
    默认: server_tokens on;
    配置块: http、 server、 location
    表示处理请求出错时是否在响应的Server头部中标明Nginx版本, 这是为了方便定位问题
    以上内容出处:
    https://www.cnblogs.com/zh-dream/p/12825289.html

  • 相关阅读:
    Codeforces Round #361 (Div. 2) E. Mike and Geometry Problem 离散化+逆元
    bzoj 1270: [BeijingWc2008]雷涛的小猫 简单dp+滚动数组
    codevs 1540 银河英雄传说 并查集
    tyvj 1027 木瓜地 简单模拟
    Codeforces Round #341 (Div. 2) C. Mike and Chocolate Thieves 二分
    UVA 10574
    BZOJ 1296: [SCOI2009]粉刷匠 分组DP
    Good Bye 2015 C. New Year and Domino 二维前缀
    Good Bye 2015 B. New Year and Old Property 计数问题
    Good Bye 2015 A. New Year and Days 签到
  • 原文地址:https://www.cnblogs.com/healkerzk/p/12996626.html
Copyright © 2020-2023  润新知