22

这些 Nginx 常见异常,帮你快速定位故障

 4 years ago
source link: http://news.51cto.com/art/201912/608025.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

提示:文章前面部分是关于 nginx 下 https 连接 curl 请求被 reset 的处理经历,不想看可以直接跳到最后看nginx快速定位异常,建议收藏!

uuAv2qu.png!web

问题描述

网站上线后,添加了https证书,浏览器访问正常,通过curl请求,请求被reset,如上图。

一路艰难

先 curl 请求同域名下http的url,返回正常,说明两边起码80端口网络正常

接着curl请求网站同服务器下其他https域名,返回正常,说明两边443端口网络正常

难道是证书问题?查看证书未到期,通过myssl.com查询证书详情,没有问题。

怀疑加密套件配置文件,添加兼容性更高的加密套件后尝试,依然无果

附兼容性加密套件:

"ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4" 

仍然无果后,决定tcpdump两边抓包,用wireshark分析

me6BvqZ.jpg!web

从发起请求到 reset,总过16个包,看到是两端握手完成,发起数据传输之后,开始传输数据的第一个确认包就被 reset 了,百思不得其解

难道是客户端发送的数据太大,nginx 的 buffer 不够?

修改了nginx关于client的相关设置如下:

client_header_buffer_size 64k; 
large_client_header_buffers 4 64k; 
client_body_buffer_size 20m; 
keepalive_timeout 120; 

因为从抓包看,还没到fastcgi部分,所以不修改关于fastcgi的buffer部分配置

修改后结果仍然一样,有点方了

nABRjiE.jpg!web

虽然知道应该和证书关系不大,但是还是决定更换一个证书看看,因为之前是RSA的证书,那我换个ECC的证书试试(推荐七牛云SSL证书申请,可以选择ECC证书)

换过之后有新的发现

curl: (35) Cannot communicate securely with peer: no common encryption algorithm(s). 

无法与对等体安全通信:无通用加密算法

问题没解决,还出来新问题了,猜测ECC算法兼容性问题,通过一番google之后,了解到如下信息:

原来Redhat/CentOS服务器上curl默认是使用NSS库的,而在这两个系统上curl默认是禁用ECC加密的,虽然服务端加密套件支持ECC,但是客户端不支持,所以请求失败,需要客户端curl通过指定加密套件来请求

curl --ciphers ecdhe_rsa_aes_128_gcm_sha_256 ... 

指定加密套件后,又回到起点,仍然是原来的错误,看来和证书没有关系

柳暗花明

没办法,仔细对比了其他网站的nginx配置,没什么不一样,只是没有配ssl_session_cache,以我对该参数的了解,该参数只是作为ssl优化的一个配置,起到缓存的作用,减少握手次数,但是现在已经“穷途末路”了,先配上再说

万万没想到,好了

uu2Erqa.jpg!web

抑制着想要吃涮羊肉的心情,又去nginx官网查了下ssl_session_cache参数的解释

jA3U3mn.jpg!web

总结如下:

ssl_session_cache有4个可选参数

  • off

严禁使用session缓存:nginx明确告诉客户端session可能不会被重用

  • none

session缓存的使用被禁止:nginx告诉客户端session可能会被重用,但实际上并不会将session参数存储在缓存中

  • builtin

在OpenSSL中构建的缓存;仅由一个工作进程使用。缓存大小在session中指定。如果没有给出大小,则等于20480个会话。使用内置高速缓存可能导致内存碎片

  • shared

所有工作进程之间共享缓存。缓存大小以字节为单位指定;一兆字节可以存储大约4000个session。每个共享缓存都应该有一个任意名称。具有相同名称的缓存可以用于多个虚拟服务器

反正就是,你要做缓存的话,就两个参数,builtin和shared,而且这两个参数可以同时开启,但是建议只使用shared,性能要更高一些

但是看完我仍然理解不了,为什么加了这个参数,curl就不报reset了,于是我再次抓包对比并和之前的做对比

YnAZvmB.jpg!web

n2aEja3.jpg!web

在数据传输之前,除了没有做Server Key Exchange外,其他没有任何不同

(reset的连接过程中,多了Server Key Exchange),通过google查询,拜读了大神的文章《Winreshark抓包理解HTTPS请求流程》了解到,密钥交换阶段,这个步骤是可选步骤,对 Certificate 阶段的补充,只有在这几个场景存在:

  • 协商采用了RSA加密,但是服务端证书没有提供RSA公钥
  • 协商采用了DH(EC Diffie-Hellman)加密,但是服务端证书没有提供DH参数
  • 协商采用了fortezza_kea加密,但是服务端证书没有提供参数

NBZ3YjA.png!web

可以从包里看到,是协商使用Diffie-Hellman算法

分析到这里,我仍然不知道为什么ssl_session_cache参数会影响到curl的请求,无奈只能这样了,这里有大神了解的,请留言告知我,感激涕零。

下面整理了nginx日志中常见的 error 日志

1.”upstream prematurely(过早的) closed connection”

请求uri的时候出现的异常,是由于upstream还未返回应答给用户时用户断掉连接造成的,对系统没有影响,可以忽略

2.”recv() failed (104: Connection reset by peer)”

(1)服务器的并发连接数超过了其承载量,服务器会将其中一些连接Down掉;

(2)客户关掉了浏览器,而服务器还在给客户端发送数据;

(3)浏览器端按了Stop

3.”(111: Connection refused) while connecting to upstream”

用户在连接时,若遇到后端upstream挂掉或者不通,会收到该错误

4.”(111: Connection refused) while reading response header from upstream”

用户在连接成功后读取数据时,若遇到后端upstream挂掉或者不通,会收到该错误

5.”(111: Connection refused) while sending request to upstream”

Nginx和upstream连接成功后发送数据时,若遇到后端upstream挂掉或者不通,会收到该错误

6.”(110: Connection timed out) while connecting to upstream”

nginx连接后面的upstream时超时

7.”(110: Connection timed out) while reading upstream”

nginx读取来自upstream的响应时超时

8.”(110: Connection timed out) while reading response header from upstream”

nginx读取来自upstream的响应头时超时

9.”(110: Connection timed out) while reading upstream”

nginx读取来自upstream的响应时超时

10.”(104: Connection reset by peer) while connecting to upstream”

upstream发送了RST,将连接重置

11.”upstream sent invalid header while reading response header from upstream”

upstream发送的响应头无效

12.”upstream sent no valid HTTP/1.0 header while reading response header from upstream”

upstream发送的响应头无效

13.”client intended to send too large body”

用于设置允许接受的客户端请求内容的最大值,默认值是1M,client发送的body超过了设置值

14.”reopening logs”

用户发送kill  -USR1命令

15.”gracefully shutting down”

用户发送kill  -WINCH命令

16.”no servers are inside upstream”

upstream下未配置server

17.”no live upstreams while connecting to upstream”

upstream下的server全都挂了

18.”SSL_do_handshake() failed”

SSL握手失败

19.”ngx_slab_alloc() failed: no memory in SSL session shared cache”

ssl_session_cache大小不够等原因造成

20.”could not add new SSL session to the session cache while SSL handshaking”

ssl_session_cache大小不够等原因造成


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK