Ways to keep my body healthy

Discover effective ways to maintain a healthy body through diet, fasting, vitamin intake, exercise, cold water baths, and more. Learn about the benefits of intermittent fasting, multivitamins, and cold water immersion, and address common issues like sleep duration and caffeine consumption.

2023/12/1
articleCard.readMore

Hello gitblog.io

Discover the power of gitblog.io, the ultimate platform for effortlessly publishing your blog.

2023/12/1
articleCard.readMore

tar 命令中 -C 参数的作用

tar 命令中的 -C 参数可切换目录,改变打包结果的目录结构。本文通过示例解释了该参数的作用,包括不使用和使用 -C 参数时的目录结构变化,以及在发布二进制文件和备份文件中的实际应用。

2024/12/23
articleCard.readMore

调用微信 API 时出现 TLS 握手超时可能是 MTU 问题

## 最近在对接微信接口时,遇到一个很诡异的问题: 偶尔会报 TLS 握手超时,但在宿主机 `curl` 是正常的。 这类“偶发性 + 网络相关”的问题最难排查,一开始我陷入了“是不是 SDK 有 bug?”的误区,直到我真正深入底层,才发现——原来是 MTU 惹的祸。 ## 环境 在此之前大部分的生产环境我都是部署在**公网上**,这一次是部署在内网的虚拟化 VM 上。 我的部署环境是这样的: * 宿主机是 Linux * 应用程序跑在**容器里(Docker)** * 使用微信 SDK 与微信服务器通信(HTTPS) * 网络通过 bridge 桥接 * 有防火墙限制,但宿主机 `curl` 请求一切正常 问题场景是这样的:应用偶尔报错`TLS handshake timeout`。不是所有请求都失败,只是偶尔出现,在宿主机执行 `curl -v https://api.weixin.qq.com` 正常,毫无问题。 ### 我排查问题的思路 网络相关的超时问题,常见有几个方向: 1. DNS 解析慢? 2. 服务端网络抖动? 3. SDK 实现问题? 4. 网络丢包或 MTU 不匹配? **第一步:确认 DNS 没问题** 我用 `dig` 和 `curl -w` 分析 DNS 解析时间,DNS 时间非常短,都是 10ms 以下,所以可以排除 DNS 问题。 **第二步:用 curl 模拟请求** 宿主机直接 `curl` 没问题:`curl -v https://api.weixin.qq.com` TLS 握手也很快,毫无异常。 但问题是在容器中运行的服务出现超时。 那我就在容器内也跑一次 `curl`: ```bash curl -v https://api.weixin.qq.com ``` 这时候就有趣了: * 有时候会卡在 `TLS handshake` * 有时候直接 `timeout` 于是可以断定——问题只出现在容器内部。 ### 关键点:MTU 不一致导致握手失败 接下来,我开始怀疑是否存在网络层的问题。 于是我通过 `ip link show` 查看了宿主机和容器内的 MTU 设置。以宿主机为例,结果如下: ```bash # 在宿主机执行 ip link show ``` 结果是这样的: ``` ... 2: ens3: mtu 1442 qdisc fq_codel state UP mode DEFAULT group default qlen 1000 ... ``` 宿主机 MTU 只有 1442,而不是标准的 1500。 而 Docker 网络默认 MTU 是 1500 ,将 Docker 容器的 MTU 修改为 1442 后再次执行 `curl` 请求,TLS 握手变得稳定了。 ## 为什么 MTU 会影响 TLS 握手? TLS 握手初期会交换证书、加密参数等内容,其中证书包往往比较大。如果 MTU 设置过大,导致网络包超过了底层网络(比如 Docker overlay、VPN、bridge)实际支持的最大尺寸,就可能发生 IP 分片。 一旦需要分片,如果中间链路的防火墙丢弃分片,或者因 ICMP 被禁用而导致 PMTU(路径MTU发现)探测失败,数据包便会丢失,最终导致握手超时。**这也解释了为什么问题是“偶尔”出现:并非所有TLS连接(例如会话复用的连接)的握手包都大到需要分片。** ## 解决方案 确定原因后,解决方法就简单了: 1. 把容器内的网卡 MTU 设置为 1442 或更小。 2. 或者在 host 上配置,使 bridge 的 MTU 与物理网卡保持一致。 3. 如果使用 Docker / Docker Compose,可以添加 `--mtu` 参数或在配置文件中指定: ```yaml networks: default: driver: bridge driver_opts: com.docker.network.driver.mtu: "1442" ``` ## 小结 这是一次非常典型的“网络层导致 TLS 握手失败”的问题,不是代码的问题,也不是 SDK 的锅。 从表面上看,是“偶发性超时”,但这次排查揭示了其背后的根源在于: * 真正的根因是 MTU 不一致引起的数据包丢失。 * 而 TLS 握手对丢包非常敏感,一旦关键握手包丢失就会失败。 所以如果你也遇到 HTTPS 或 SDK 请求偶尔超时,一定要检查一下 MTU 设置,特别是在容器或桥接网络场景下。

2025/7/24
articleCard.readMore