Nginx与Spring Boot的错误模拟实践:探索502和504错误的原因

前言

刚工作那会,最常见的报错是500 Internal Server Error ,曾经也碰到过前端反馈502 Bad Gateway 或者 504 Gateway Time-out,那时候傻傻的搞不懂,以为这种都是外部服务或者网络运维部那边的问题。

当时那个服务里正好有个调用日志,平时会记录各种200,4xx状态码的信息。于是我跑到服务日志里去搜索了一下502这个数字,毫无发现。于是跟反映错误的前端说,“服务日志里并没有502的记录,你是不是搞错啦?”

现在想想,果然那时候还是个小白。。。

502和504区别—都是Nginx返回的

我们实际企业级应用,访问肯定是有nginx这层代理的,如下图所示:

有了nginx这一中间层后,客户端从直连服务端,变成客户端直连nginx,再由nginx直连服务端。从一个TCP连接变成两个TCP连接。

于是,当服务器发生异常时,nginx发送给服务器的那条TCP连接就不能正常响应,nginx在得到这一信息后,就会返回5xx错误码给客户端,也就是说5xx的报错,其实是由nginx识别出来,并返回给客户端的,服务端本身,并不会有5xx的日志信息。所以上面说到的,前端收到了我服务的502报错,但我在自己的服务日志里却搜索不到这一信息。

image-20230910114454105

502错误和504错误都表示前端访问后端服务器时出现了问题,但它们之间有以下区别:

502错误(Bad Gateway):

  • 502错误是指反向代理服务器(如Nginx)作为中间代理,在请求转发过程中从后端服务器接收到了无效的响应。
  • 502错误通常与后端服务器的故障、崩溃、无响应或错误配置等问题有关。
  • 反向代理服务器无法获取有效的响应,因此返回502错误给前端客户端。
  • 502错误表示中间代理服务器与后端服务器之间的通信存在问题。

504错误(Gateway Timeout):

  • 504错误是指反向代理服务器在规定的时间内无法从后端服务器获取到有效的响应。
  • 504错误通常与后端服务器的响应超时有关,即后端服务器处理请求的时间超过了反向代理服务器设置的超时时间。
  • 反向代理服务器在规定时间内未收到有效的响应,因此返回504错误给前端客户端。
  • 504错误表示反向代理服务器在等待后端服务器响应时超时。

access.log和error.log介绍

在Nginx中,access.log和error.log是两个重要的日志文件,用于记录服务器的访问和错误信息。下面是关于这两个日志文件的介绍:

  1. access.log:
    • access.log是Nginx服务器记录所有访问请求的日志文件。
    • 它包含了每个请求的详细信息,如访问时间、客户端IP地址、请求方法、请求的URL、HTTP协议版本、返回的状态码、传输字节数等。
    • access.log对于分析和监视服务器的访问模式、流量分析、性能调优和安全审计非常有用。
    • 默认情况下,access.log文件位于Nginx的安装目录下的logs文件夹中,可以通过在配置文件中进行配置来更改日志文件的位置和格式。
  2. error.log:
    • error.log是Nginx服务器记录所有错误和警告信息的日志文件。
    • 它包含了服务器处理请求时发生的错误、异常、警告和其他问题的详细信息。
    • error.log对于故障排除、错误诊断和监视服务器的健康状态非常有用。
    • 默认情况下,error.log文件也位于Nginx的安装目录下的logs文件夹中,可以通过在配置文件中进行配置来更改日志文件的位置和格式。

所以当我们配置了nginx代理以后,每次访问都会在access.log里面有访问记录,报错时,会在error.log记录对应信息

SpringBoot结合Nginx实战502 and 504

实际运用中,我碰到的502正常都是服务挂了,504一般都是服务超时了,现在我就模拟这两种情况

准备工作

Nginx配置

首先将nginx进行配置,当我们访问www.testnginx.com//test502Or504 会自动代理访问到http://localhost:8080/test502Or504

 server{
        listen 80;
        server_name www.testnginx.com; #请求的域名
		proxy_send_timeout 2s;     # 设置发送超时时间,
        proxy_read_timeout 2s;	 # 设置读取超时时间。
        location /test502Or504{
            proxy_pass http://localhost:8080/test502Or504;
        }
    }
host配置
127.0.0.1  www.testnginx.com
SpringBoot
@Slf4j
@RestController
public class TestControllerForThis {

	@RequestMapping("/test502Or504")
	public String test502Or504() {
		ThreadUtil.sleep(3000L);
		return "test502Or504";
	}
}	

直接访问:localhost:8080/test502Or504

image-20231004225401386

502模拟

502很好模拟,由于我们上面进行了配置:www.testnginx.com//test502Or504会自动代理到http://localhost:8080/test502Or504 ,可以直接将我们的SpringBoot工程直接关闭,此时即可模拟出502报错:

直接访问:http://localhost:8080/test502Or504

image-20231004230814832

访问:http://www.testnginx.com/test502Or504

image-20231004230832673

access.log

127.0.0.1 - - [04/Oct/2023:23:06:16 +0800] “GET /test502Or504 HTTP/1.1” 502559 “-” “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36”

error.log
2023/10/04 23:06:14 [error] 15220#11328: *63 connect() failed (10061: No connection could be made because the target machine actively refused it) while connecting to upstream, client: 127.0.0.1, server: www.testnginx.com, request: "GET /test502Or504 HTTP/1.1", upstream: "http://[::1]:8080/test502Or504", host: "www.testnginx.com"
2023/10/04 23:06:16 [error] 15220#11328: *63 connect() failed (10061: No connection could be made because the target machine actively refused it) while connecting to upstream, client: 127.0.0.1, server: www.testnginx.com, request: "GET /test502Or504 HTTP/1.1", upstream: "http://127.0.0.1:8080/test502Or504", host: "www.testnginx.com"

504模拟

我们在Nginx配置了超时时间为2s,所以当我们请求的接口耗时超过2s时,就会出现504 Gateway Time-out

我们在接口里面睡眠了3s超过了配置的2s:

@RequestMapping("/test502Or504")
	public String test502Or504() {
		ThreadUtil.sleep(3000L);
		return "test502Or504";
	}

当然,直接访问http://localhost:8080/test502Or504是正常的,

image-20231004225401386

访问http://www.testnginx.com/test502Or504报错504 Gateway Time-out

image-20231004225559524

access.log

127.0.0.1 - - [04/Oct/2023:23:02:26 +0800] “GET /test502Or504 HTTP/1.1” 504 569 “-” “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36”

error.log
2023/10/04 23:02:24 [error] 15220#11328: *59 upstream timed out (10060: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond) while reading response header from upstream, client: 127.0.0.1, server: www.testnginx.com, request: "GET /test502Or504 HTTP/1.1", upstream: "http://[::1]:8080/test502Or504", host: "www.testnginx.com"
2023/10/04 23:02:26 [error] 15220#11328: *59 upstream timed out (10060: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond) while reading response header from upstream, client: 127.0.0.1, server: www.testnginx.com, request: "GET /test502Or504 HTTP/1.1", upstream: "http://127.0.0.1:8080/test502Or504", host: "www.testnginx.com"

500模拟

修改程序

@RequestMapping("/test502Or504")
	public String test502Or504() {
		if (true){
			throw new NullPointerException("test502Or504");
		}
		ThreadUtil.sleep(3000L);
		return "test502Or504";
	}

直接访问http://localhost:8080/test502Or504

image-20231004231328767

访问:http://www.testnginx.com/test502Or504

image-20231004231347057

access.log

127.0.0.1 - - [04/Oct/2023:23:11:07 +0800] “GET /test502Or504 HTTP/1.1” 500 310 “-” “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36”

error.log

此时不会记录500错误

总结

  • 502错误表示反向代理服务器接收到了无效的响应或与后端服务器之间通信出现问题。
  • 504错误表示反向代理服务器在规定时间内未能从后端服务器获取到有效的响应,即后端服务器响应超时。
  • 502错误主要与后端服务器的故障、崩溃或配置错误有关,而504错误主要与后端服务器的响应超时有关。