Linux: Nginx proxy_pass域名解析引发的故障

背景

业务架构:

clipboard.png

部署细节:
  两容器均部署在同一机器上,通过 docker-compose 编排,并且通过link方式链接。

故障描述

在有次更新代码时,发现前端能够打开,但是所有接口请求全是502(Bad GateWay)

clipboard.png

故障排查

查看前端容器compose_ui_1的日志,刷了一大波502(Bad GateWay)

clipboard.png

UI没问题的话,第一反映就是 compose_api_1 跪了,所以直接去容器看看日志
clipboard.png

容器日志看起来很正常,没有崩溃,而且这个日志就好像从来没收到请求那样,但是很明显我前端肯定有访问的,感觉很奇怪。将接口取出来单独访问试试看:
clipboard.png

接口单独访问结果还是很残暴的502(Bad GateWay),感觉还是不太可信,是不是端口或者主机什么访问错误了?
本机开启 wireshark 抓包确认下请求的主机和端口:
clipboard.png

这样就很确保前端compose_ui_1访问的主机和端口是正确的,而且确切结果是502(Bad GateWay),这样只能从compose_api_1下手排查了。

之前也是遇到相似的问题,因为compose_api_1是通过uwsgi部署的python flask,那会总是用法觉得有点问题,改过uwsgi配置之后消停了一会。现在又卷土重来了。

先判断下compose_api_1是不是真的跪了。。。虽然对这个没抱什么希望。。。

直接访问 后端api 接口
clipboard.png

额。。。尴尬。。。仿佛冤枉错好人了。这不对吧,抓包看看再次确认下先:
clipboard.png

仿佛真的是。。。再 see see 容器日志:
clipboard.png

额。。。好吧。。。我错了,compose_api_1没跪。

于是问题来了。。。后端接口没问题,前端访问出错了,见鬼了?

有种预感是容器的特性导致的问题。但愿不要。。

先进去compose_ui_1容器抓包分析下,看看整个请求链有没有问题:
clipboard.png

似乎发现了点猫腻,Flags[R.]是代表 tcp链接 被 reset 重置 了,但是为什么平白无故重置呢?

看到 172.17.0.5.8080 返回的, 先 telnet 问问先:
clipboard.png

What???这就很迷了,首先这个 172.17.0.5.8080 哪来的呢?其次就是为毛端口不通?

突然想到一个很重要的问题:

容器之间是怎么知道它要把请求发给谁呢 ?

在前面已经交代过,这两个容器是通过 link 的方式链接的,像下面这样:

clipboard.png

谷歌搜了下 link 工作原理:

link机制通过环境变量的方式提供了这些信息,除此之外像db的密码这些信息也会通过环境变量提供,docker将source container中定义的环境变量全部导入到received container中,在received container中可以通过环境变量来获取连接信息。使用了link机制后,可以通过指定的名字来和目标容器通信,这其实是通过给/etc/hosts中加入名称和IP的解析关系来实现的

所以就是说在 compose_ui_1 的 根据指定的名字并在 /etc/hosts 翻译出具体的ip然后进行通信咯?
看看容器的名字是啥?

clipboard.png

compose_ui_1/etc/hosts

root@e23430ed1ed7:/# cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.4    detectapi fc1537d83fdf compose_api_1
172.17.0.3    authapi ff83f8e3adf2 compose_authapi_1
172.17.0.3    authapi_1 ff83f8e3adf2 compose_authapi_1
172.17.0.3    compose_authapi_1 ff83f8e3adf2
172.17.0.4    api_1 fc1537d83fdf compose_api_1
172.17.0.4    compose_api_1 fc1537d83fdf
172.17.0.6    e23430ed1ed7

如果真是按照资料所说,那 172.17.0.4:8080 才是 compose_api_1 的地址隐射才对吧?,试下先
clipboard.png
虽然返回了 auth product is None,但其实这是有效的请求。

再看看 compose_api_1 容器的日志:
clipboard.png

所以基本没跑了, 为什么前端访问直接就是 502, 原因就是 ui容器向错误的地址发送请求了

那么为什么会这样呢?平白无故抽风了?

刚才根据 host 的记录实验了,按照它的映地址发起接口请求,是没有问题的:

查看下 compose_ui_1nginx 日志
clipboard.png

尴尬。。。 nginx 日志居然直接连接到标准输出和标准错误。。。
那为了简单点,还是直接用 docker logs 查看吧
clipboard.png

看来 nginx 的转发已经是错误的,为什么会转发到 172.17.0.5, 看看 nginx 关于转发的配置:
clipboard.png

这个 detectapi 和 上面贴出的 hosts 表能找到正确的地址 172.17.0.4 呀?搞不明白为什么会转发到 172.17.0.5

难道是系统的域名解析错误了?
clipboard.png

尼玛这真是太神奇了。

男人的直觉告诉我 nginx 有猫腻!

重启下容器的 nginx,然而容器也被重启了。。。
clipboard.png

再访问页面,居然可以了。。。
clipboard.png

再看看容器的nginx日志,已经转发成功了
clipboard.png

这样子的话,其实应该能定位到,问题是出在了 nginx 上面?

故障定位

只是为什么 nginx 会有这样的错误呢?不太应该呀。。 感觉应该是 nginx 内部域名解析缓存问题。

然后查了下资料,呵呵,还真有。https://www.zhihu.com/questio...

clipboard.png

这就非常尴尬了。对这个问题抱有点怀疑,咨询了资深大佬,然后大佬的回复就是:

如果 proxy_pass 后面跟的域名的话,在 nginx 启动的时候就会初始化好,以后就只会复用这个值;参考:ngx_http_upstream_init_round_robin 函数
如果 proxy_pass 后面跟的是upstream,配置才会走解析和缓存的逻辑;

改善措施

  1. 不直接 proxy_pass 真实域名,而是转发到 upstream 配置;
  2. 也可参考刚才的知乎链接处理方案:https://www.zhihu.com/questio...;

延展问题

  1. 为什么 compose_ui_1 指定的 compose_api_1 会出错?
  2. proxy_pass 如果后面跟真实域名,是真的直接复用还是有时间缓存?

本来想用 gdb 调试下这个问题,然而花了一天时间,毛都没有。不过也有点小收获,那就是如何配置nginx来支持gdb

1.修改编译配置文件:auto/cc/conf

ngx_compile_opt="-c"  改成 ngx_compile_opt="-c -g"

2../configure 时,增加编译参数:--with-cc-opt='-O0', 避免编译器优化;
例如:./configure --prefix=/usr/local/nginx --with-cc-opt='-O0' ....
如果不这样的话,编译器会优化代码,导致调试过程中,循环中的一些变量值无法打印,会报下面的错误:

value optimized out

下面可以看下调试的效果:
nginx worker process 处理入口:ngx_http_static_handler

clipboard.png
欢迎各位大神指点交流, QQ讨论群: 258498217
转载请注明来源: https://segmentfault.com/a/11...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/277980.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Oracle建立全文索引详解

Oracle建立全文索引详解1.全文检索和普通检索的区别 不使用Oracle text功能,当然也有很多方法可以在Oracle数据库中搜索文本,比如INSTR函数和LIKE操作: SELECT *FROM mytext WHERE INSTR (thetext, Oracle) > 0; SELECT * FROM mytext WHE…

面向全球用户的Teams app之夏令时篇

我在前两篇文章里分享了Global Ready的teams app时会遇到的不同挑战。这篇我继续分享在夏令时方面的挑战。 夏令时,主要是为了节约能源,英文里通常缩写成DST(Daylight Saving Time)。一般在天亮早的夏季人为将时间调快一小时,可以使人早起早…

爬取全部的校园新闻

1.从新闻url获取新闻详情: 字典,anews 2.从列表页的url获取新闻url:列表append(字典) alist 3.生成所页列表页的url并获取全部新闻 :列表extend(列表) allnews *每个同学爬学号尾数开始的10个列表页 4.设置合理的爬取间隔 import time import…

面向全球用户的Teams app之合规性篇

我在前两篇文章里分享了Global Ready的app时会遇到的不同挑战。这篇我继续分享在合规性方面的挑战。 说到合规性compliance,不得不说GDPR标准,当我们发布了一个teams app后,微软会要求开发人员做一个security self assessment,这…

C进阶 - 内存四驱模型

一.内存四驱模型 不知我们是否有读过 《深入理解 java 虚拟机》这本书,强烈推荐读一下。在 java 中我们将运行时数据,分为五个区域分别是:程序计数器,java 虚拟机栈,本地方法栈,java 堆,方法区。…

行内元素中去掉文字的上下间距,使得文字所在元素的高度同字体高度一致的方法...

之前在p这类块元素中的文字,给line-hight1;就可以去掉文字自带的上下间距, 像这样: 最近突然发现这个方法在行内块和块元素上好使,可当用在span或者a这类内联元素上都不好使,除了转为块元素的方法来去掉上下间距&#…

VSCode的Teams插件

随着今年在线的Build大会的结束,又是一大波的 Teams 新功能,新工具,新SDK。我接下来几篇博客就会详细和大家一一介绍。我今天先从VSCode的插件开始。 打开VS Code,搜索Teams,就可以找到Microsoft Teams Toolkit插件&a…

ADB原理,Wi-Fi连接,常用命令及拓展

Android 开发笔记 onGithub 文章多处链接需要科学上网 本文按顺序主要讲解了ADB的原理,使用Wi-Fi连接设备,ADB常用命令,在Java代码中执行shell命令,使用ddmlib进行扩展。 ADB的原理 参考 官方文档 ADB(Android Debug B…

使用Flow快速开发Teams小应用

继续我的上一篇博客,这篇继续介绍BUILD大会里的内容:Flow。 Flow是微软power平台的一个服务,通过简单的拖拽就可以完成一个业务逻辑的处理,现在Flow和Teams的结合十分紧密。我们来试一下。 先点击Teams左边的Flow菜单。 如果你的…

python正则中如何匹配汉字以及encode(‘utf-8’)和decode(‘utf-8’)的互转

正则表达式&#xff1a;  [\u2E80-\u9FFF]$ 匹配所有东亚区的语言   [\u4E00-\u9FFF]$ 匹配简体和繁体   [\u4E00-\u9FA5]$ 匹配简体   <input type"text" name"username" οnkeyup"valuevalue.replace([\u4E00-\u9FA5]$)"> 正则表…

【区块链】认识区块链的基本概念

2018年区块链技术风卷全球&#xff0c;似乎大家都在谈论区块链&#xff0c;那到底什么区块链&#xff0c;区块链到底能干什么&#xff0c;对普通人会有什么影响&#xff0c;很多人还是稀里糊涂&#xff0c;那么就谈谈我的一些理解吧&#xff0c;抛砖引玉欢迎探讨。 我是如何接触…

Java 分割、合并byte数组

场景&#xff1a;上传文件较大&#xff0c;把存放文件内容byte数组拆分成小的。下载的时候按照顺序合并。 起初觉得挺麻烦的&#xff0c;写完觉得挺简单。 切割&#xff1a; /*** 拆分byte数组* * param bytes* 要拆分的数组* param size* 要按几个组成一…

Java版本的Bot Framework SDK

微软为了鼓励Java开发人员开发bot&#xff0c;在上个月推出了Java的Bot SDK v4.6版本&#xff0c;目前还在Preview版本&#xff0c;相信不用多久就可以赶上其他版本了。 我的java还停留在 n 年前的水平&#xff0c;但是处于好奇&#xff0c;决定玩一下这套sdk。 这套sdk目前建…

jquery方法.serializeArray()获取name和value并转为json数组

jquery的.serializeArray()方法可以获取形如以下 [ {name: firstname, value: Hello}, {name: lastname, value: World}, ] name value组成的对象数组&#xff0c;如果我们想得到key为name,value为value的json对象&#xff0c;则如下转换&#xff1a; var m {}; $.each($(&quo…

Teams Bot 如何使用新的 System.Text.Json 库

我最近把 LuckyDraw的代码升级到了 .net core 3.1&#xff0c;当然我也很想使用最新的微软json库&#xff0c;System.Text.Json这个库的性能比之前Newtonsoft.Json速度更快&#xff0c;而且就我本人爱好来说&#xff0c;更加喜欢System.Text.Json的命名&#xff0c;之前一直觉得…

将Teams Template升级到dotnet core 3.1

为了方便开发者开发Teams应用&#xff0c;我在2018年做了dotnet c#的一套模板&#xff0c;这套模块一共有三种类型&#xff0c;一个是Teams OutgoingWebhook&#xff0c;一个是MessagingExtension&#xff0c;还有一个就是Tab。 今天特地去nuget上看了一下&#xff0c;下载量还…

【动态规划】cf1034C. Region Separation

质因数分解套路的复杂度分析的动态规划 题目大意 有一颗$n$个节点有点权的树&#xff0c;初始整棵树为$1$号区域&#xff0c;要求满足下列规则&#xff1a; 除非$i$是最后一个等级&#xff0c;否则每一个$i$级区域都要被分成至少两个$i1$级区域对于每种等级&#xff0c;每个点必…

阿里大鱼短信介入demo分享

下面是关于大鱼短信平台对接的例子&#xff0c;发短信的话&#xff0c;可以用这个&#xff0c;很好用 /*** 通过阿里短信接口发送短信验证码* ***/ public class SendSmsUtil {private static Logger logger Logger.getLogger(SendSmsUtil.class);/*** 生成验证码* return*/pu…

GraphAPI 1.0中新增加的Teams API

这篇继续介绍BUILD大会里的内容&#xff1a;两个新加入GraphAPI 1.0的关于Teams的API。 这两个新增api是关于在频道Channel里发送消息和回复消息的。实际上这两个api在beta版本中早就已经加入&#xff0c;上个月build大会中公布的只是把这两个api正式发布到1.0版本&#xff0c…

【数据结构】线性表(一):顺序列表

线性表(linear_list)是最常用且最简单的一种数据结构&#xff0c;简言之&#xff0c;一个线性表是n个数据元素的有序序列。 例如&#xff1a;&#xff08;a1 , ... , ai-1 , ai , ai1 , ... , an)&#xff1a;ai-1 是 ai 的直接前驱&#xff0c;ai1 是 ai 的直接后驱。 并且&am…