说明
部分的服务节点经常再经过了nginx已经进入到了上游服务器服务内部之后,因为一些未知的原因,如第三方接口的请求超时等,也会引起的服务的502的响应异常,如何再此类的情况解决节点不直接的响应返回的502的状态码和结果信息,或者重试。
本实践主要是尝试这种方案的可行性。
应用场景
此场景仅限于自己业务中,比如当某个业务进行到内部服务器且经过第三方接口直充成功的之后,突然的莫名成的程序进程崩溃或无响应的时候,此时重新提交一下相关的接口进行分发核对一下具体的充值接口情况,避免返回给第三方服务商的的接口状态是502的响应。
正常来说充值类的业务最好不要进行二次的确认提交,不过我这边进行加锁处理,目前暂时先这样处理!
环境
首先配置一下具体的服务
nginx 的配置环境
127.0.0.1:5555用于引发502状态码的服务测试。
127.0.0.1:6666 用于引发502状态码引发之后,Nginx 下的 recursive error pages 之后的代理转发到的服务节点
步骤:
PS:因当前服务已安装响应的模块bottle.所以直接的使用它来启动一个简单的服务即可
搭建服务1:
#!/usr/bin/evn python
# coding=utf-8
from bottle import route, run, abort,request
from urllib.parse import quote, unquote
import urllib
def write_request_headers_log():
"""写客户端访问路由的日志记录"""
# 记录客户端提交的参数
request_log = '\nheaders:'
try:
request_log = request_log + '\nheaders:' + urllib.parse.unquote(str(request.headers.__dict__))
except:
request_log = request_log + '\nheaders:' + urllib.parse.unquote(str(request.headers))
try:
pass
# log_helper.request_log(request_log + '\n')
except:
# log_helper.request_log(request_log + '头部记录异常')
pass
print(request_log)
@route('/')
def index():
write_request_headers_log()
print(request.query_string)
print(request.forms)
return "你好"
@route('/hello/502')
def index():
write_request_headers_log()
write_request_headers_log()
print(request.query_string)
print(request.forms)
abort(502)
run(host='127.0.0.1', port=5555,debug=True,reloader=True)
搭建服务2:
#!/usr/bin/evn python
# coding=utf-8
from bottle import route, run, abort,request
from urllib.parse import quote, unquote
import urllib
def write_request_headers_log():
"""写客户端访问路由的日志记录"""
# 记录客户端提交的参数
request_log = '\nheaders:'
try:
request_log = request_log + '\nheaders:' + urllib.parse.unquote(str(request.headers.__dict__))
except:
request_log = request_log + '\nheaders:' + urllib.parse.unquote(str(request.headers))
try:
pass
# log_helper.request_log(request_log + '\n')
except:
# log_helper.request_log(request_log + '头部记录异常')
pass
print(request_log)
@route('/')
def index():
print('我是服务2')
write_request_headers_log()
print(request.query_string)
print(request.forms)
return "你好"
@route('/hello/502')
def index():
print('我是服务2')
write_request_headers_log()
write_request_headers_log()
print(request.query_string)
print(request.forms)
run(host='127.0.0.1', port=6666,debug=True,reloader=True)
nginx 配置(没启用recursive error pages 的情况下)
upstream ceshsihii_test {
server 127.0.0.1:5555 weight=1 max_fails=0 fail_timeout=12s;
}
upstream ceshsihii6666_test {
server 127.0.0.1:6666 weight=1 max_fails=0 fail_timeout=12s;
}
server {
listen 5554;
charset utf-8;
server_name 127.0.0.1;
location / {
proxy_pass http://ceshsihii_test;
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_connect_timeout 300; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 300; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 300; #连接成功后,后端服务器响应时间(代理接收超时)
error_page 502 = @fetch;
}
location @fetch {
proxy_pass http://ceshsihii6666_test;
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_connect_timeout 300; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 300; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 300; #连接成功后,后端服务器响应时间(代理接收超时)
}
access_log /data/logs/nginx/ceshsihii_test.log main;
}
测试启动
[root@web-1 ceshi]# python server_5555.py
Bottle v0.12.10 server starting up (using WSGIRefServer())...
Listening on http://127.0.0.1:5555/
Hit Ctrl-C to quit.
[root@web-1 ceshi]# python server_6666.py
Bottle v0.12.10 server starting up (using WSGIRefServer())...
Listening on http://127.0.0.1:6666/
Hit Ctrl-C to quit.
测试服务响应正常:
[root@web-1 ~]# curl http://127.0.0.1:5554/
你好[root@web-1 ~]#
测试502响应
[root@web-1 ~]# curl http://127.0.0.1:5554/hello/502
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
<title>Error: 502 Bad Gateway</title>
<style type="text/css">
html {background-color: #eee; font-family: sans;}
body {background-color: #fff; border: 1px solid #ddd;
padding: 15px; margin: 15px;}
pre {background-color: #eee; border: 1px solid #ddd; padding: 5px;}
</style>
</head>
<body>
<h1>Error: 502 Bad Gateway</h1>
<p>Sorry, the requested URL <tt>'http://127.0.0.1/hello/502'</tt>
caused an error:</p>
<pre>Unknown Error.</pre>
</body>
</html>
[root@web-1 ~]#
此时5555端口的服务节点的响应也是502:
<bottle.FormsDict object at 0x7f39e0279e80>
127.0.0.1 - - [29/Oct/2020 13:27:27] "GET /hello/502 HTTP/1.0" 502 718
6666服务节点没任何的响应:
查看ngin日志:
127.0.0.1 - 127.0.0.1:5555 [29/Oct/2020:13:27:27 +0800-1603949247.669] "GET /hello/502 HTTP/1.1" [0.006] [0.005]502 718 "" "curl/7.29.0" "" ""
修改Nginx配置信息:(启用recursive error pages 的情况下)
修改Nginx配置信息:
upstream ceshsihii_test {
server 127.0.0.1:5555 weight=1 max_fails=0 fail_timeout=12s;
}
upstream ceshsihii6666_test {
server 127.0.0.1:6666 weight=1 max_fails=0 fail_timeout=12s;
}
server {
listen 5554;
charset utf-8;
server_name 120.77.63.115;
proxy_intercept_errors on;
recursive_error_pages on;
location / {
proxy_pass http://ceshsihii_test;
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_connect_timeout 300; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 300; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 300; #连接成功后,后端服务器响应时间(代理接收超时)
error_page 502 = @fetch;
}
location @fetch {
proxy_pass http://ceshsihii6666_test;
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_connect_timeout 300; #nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 300; #后端服务器数据回传时间(代理发送超时)
proxy_read_timeout 300; #连接成功后,后端服务器响应时间(代理接收超时)
}
access_log /data/logs/nginx/ceshsihii_test.log main;
}
关键修改点,新增:
proxy_intercept_errors on;
recursive_error_pages on;
说明: proxy_intercept_errors on; 当上游服务器响应头回来后,可以根据响应状态码的值进行拦截错误处理,
通常是结合error_page 指令进行使用。用在访问上游服务器出现错误的情况下。
recursive_error_pages on; 可以让下面的location @fetch生效
再进行服务的测试:
访问的经过的Nginx的路由节点:
[root@web-1 ~]# curl http://127.0.0.1:5554/hello/502?5467456=345345
[root@web-1 ~]#
此时:5555服务的节点响应的是502的信息
<bottle.FormsDict object at 0x7fcfb9a88c50>
127.0.0.1 - - [29/Oct/2020 13:35:53] "GET /hello/502?5467456=345345 HTTP/1.0" 502 733
此时:6666服务的节点响应的是200的响应信息
<bottle.FormsDict object at 0x7f9a54317400>
127.0.0.1 - - [29/Oct/2020 13:35:53] "GET /hello/502?5467456=345345 HTTP/1.0" 200 0
查看的最终的nginx日志信息为:
27.0.0.1 - 127.0.0.1:5555 [29/Oct/2020:13:27:27 +0800-1603949247.669] "GET /hello/502 HTTP/1.1" [0.006] [0.005]502 718 "" "curl/7.29.0" "" ""
127.0.0.1 - 127.0.0.1:5555 : 127.0.0.1:6666 [29/Oct/2020:13:31:24 +0800-1603949484.675] "GET /hello/502 HTTP/1.1" [0.005] [0.002 : 0.003]200 0 "" "curl/7.29.0" "" ""
127.0.0.1 - 127.0.0.1:5555 : 127.0.0.1:6666 [29/Oct/2020:13:32:31 +0800-1603949551.442] "GET /hello/502 HTTP/1.1" [0.004] [0.003 : 0.001]200 0 "" "curl/7.29.0" "" ""
127.0.0.1 - 127.0.0.1:5555 : 127.0.0.1:6666 [29/Oct/2020:13:33:26 +0800-1603949606.396] "GET /hello/502?5467456=345345 HTTP/1.1" [0.005] [0.003 : 0.001]200 0 "" "curl/7.29.0" "" ""
127.0.0.1 - 127.0.0.1:5555 : 127.0.0.1:6666 [29/Oct/2020:13:35:53 +0800-1603949753.523] "GET /hello/502?5467456=345345 HTTP/1.1" [0.009] [0.008 : 0.001]200 0 "" "curl/7.29.0" ""
实践结果
说明,错误的响应的时候,可以进行再次的转发了!