记一次 Nginx 调参的踩坑经历

最近在基于SSE(Server Sent Events)做服务端单向推送服务,本地开发时一切顺利,但是在部署到预发环境时就碰到1个很诡异的问题,这里需要简单介绍下我们的整体架构:

整体架构

架构

可以看到所有的请求都会先到统一的网关层(对应 example.com 这个一级域名),然后发到不同的应用对应的docker镜像上,这里不同的应用可以简单地用不同的域名来做表示,例如应用 A 的域名是A.example.com,应用 B 的域名是 B.example.com,且这里的每1个应用都是1个SPA单页应用,这样的话前端和服务端就是完全分离的,前端这边完全掌控页面和路由的跳转,对于数据获取和更新只需要请求对应的接口和服务即可,这也算是现在比较流行的一种架构了。
因为历史原因,我们的服务有多个,且这些服务的域名是不一样的,例如对于应用A来说,所依赖的底层服务有 serviceA(域名是serviceA.example.com)和serviceB(域名是serviceB.example.com),所以在应用A的docker上会存在1个 Nginx ,用来对A.example.com 下的不同接口的请求做反向代理,确保能转发到不同的服务上。
例如当用户请求A.example.com/doc/update/这个接口时,本质上会发送请求到 doc.example.com/update这个接口上,并得到数据。
好了,背景介绍得差不多了,现在开始上重点。

真实场景

现在我们做了1个 SSE(Server Sent Events)服务在doc.example.com/sse,那么我们需要Nginx将 A.example.com/doc/sse给转发到doc.example.com/sse 上即可
SSE的全称是(Server Sent Events),简单来说服务器发送事件,是客户端与服务端建立单向的长连接通信的一种方式,客户端可以通过 EventSource 来订阅事件通知,等待服务端去推送消息
在咨询了ChatGPT 4之后,最精简的配置如下:

server {listen  80;charset utf-8;... # 省略配置信息location /doc/sse {        # 转发到对应的域名下proxy_pass https://doc.example.com/sse; # Disable buffering for SSEproxy_buffering off;# Other necessary SSE headersproxy_set_header Cache-Control 'no-cache';proxy_set_header Connection 'keep-alive';# Standard proxy headersproxy_set_header Host $http_host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;}}

但是在连接后就发现1个很奇怪的问题,sse 无法连接,会被重定向到 A.example.com/sse 这个域名下,而不是我们想要的 doc.example.com/sse
上面的配置看起来无比正确,但就是存在问题。那么话不多说,直接二分排查。

这里抽象一个解决的方法论,即先保留一个最小的正确问题的现场,然后通过二分搜索的方式去找到具体的原因

问题本质

经过层层筛选,最后发现问题出在proxy_set_header Host $http_host;这条语句上。
当在 Nginx 中同时使用proxy_set_headerproxy_pass指令时,Host 头部的处理步骤如下:

第一步:请求到达 Nginx

客户端发起请求,该请求到达运行 Nginx 的服务器。该请求会包含一个 Host 头部,通常是用来指定服务器的域名或IP地址。

第二步:匹配 Location 块

Nginx 根据请求的 URI 匹配相应的 location 块。例如,如果请求的是 /doc/sse,Nginx 将匹配包含proxy_passproxy_set_header 指令的 location /doc/sse 块。

第三步:处理 proxy_set_header 指令

如果在 location 块中使用了 proxy_set_header Host $http_host; 指令,Nginx 将修改或添加 Host 请求头部,将其值设置为 $http_host 变量的值。这个变量通常包含客户端在请求中发送的 Host 头部的值。

第四步:处理 proxy_pass 指令

proxy_pass 指令告诉 Nginx 将请求转发到指定的后端服务。如果配置为 proxy_pass https://doc.example.com/sse,Nginx 将请求转发到 https://doc.example.com/sse

第五步:设置请求头部

重点来了,在将请求转发给后端服务之前,Nginx 将根据 proxy_set_header 指令设置的值来修改请求头部。在这个过程中,Nginx 会将 Host 头部设置为客户端请求中的 Host 头部的值,而不是 proxy_pass 中指定的后端服务的域名。
也就是说,我们请求的地址经历了以下的变化:

  1. A.example.com/doc/sse
  2. doc.example.com/sse
  3. A.example.com/sse(由proxy_set_header执行)

那么相当于发生了1次不受 Nginx 管控的重定向。

正确答案:

最精简的完整配置如下:

location /doc/sse {        proxy_pass https://doc.example.com/sse; # Disable buffering for SSEproxy_buffering off;}

这里可能有的同学会好奇,为什么一定要关闭代理缓存呢?如果不关闭会怎么样呢?下面我们来简单讲讲:

为什么要关闭代理缓存?

对于(SSE)来说,关闭代理缓冲非常重要,原因主要在于SSE的工作机制和数据流的特性。

  1. SSE工作机制: SSE允许服务器通过一个持久的HTTP连接向客户端实时推送数据。服务器发送的数据流是一个持续的过程,不是一次性完成的。
  2. 代理缓冲的影响: 如果代理服务器对传入的响应进行缓冲,它可能会等待缓冲区填满或达到某个特定的数据量后,才将数据一次性发送给客户端。这样做的结果是客户端不能实时接收到服务器推送的数据,从而破坏了SSE的实时性。
  3. 实时性要求: SSE的主要用途是为了实现实时通信。如果代理服务器对数据进行缓冲,则实时通信的效果会被大大降低,因为客户端接收数据的速度会受到影响。
  4. 连接保持: 除了实时性之外,SSE连接需要保持打开状态,以便服务器可以持续发送数据。如果代理服务器对连接进行了不当的处理(例如,由于长时间不活动而关闭连接),这也可能干扰SSE的正常工作。

因此,对于SSE来说,关闭代理服务器的响应缓冲是确保数据能够及时、连续地发送给客户端的关键。这样可以保持数据流的连续性,确保客户端能够实时接收到服务器端发送的每一条消息。

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

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

相关文章

STM32移植LVGL图形库

1、问题1:中文字符keil编译错误 解决方法:在KEIL中Options for Target Flash -> C/C -> Misc Controls添加“--localeenglish”。 问题2:LVGL中显示中文字符 使用 LVGL 官方的在线字体转换工具: Online font converter -…

阿里云Code的代码仓库忘了升级导致现在找不到了怎么办?

阿里云Code的代码仓库忘了升级了,找不到了怎么办?如何找回丢失的阿里云代码? 1.1 问题背景1.2 修复方案 1.1 问题背景 众所周知,在之前,阿里云代码仓库托管使用的是 code.aliyun.com,后来迁移到了 codeup.aliyun.com &#xff0…

解锁JDK 12的奇妙之旅:新特性详解

欢迎来到我的博客,代码的世界里,每一行都是一个故事 解锁JDK 12的奇妙之旅:新特性详解 前言switch表达式拓展NumberFormat对复杂数字的格式化字符串支持transform、indent操作新增方法Files.mismatch(Path, Path)Teeing Collector支持unicode…

map容器的基本使用

文章目录 mapmap模板参数默认构造迭代器[ ]{ }inserterasefindlower_bound && upper_boundcountequal_range map和set容器,multimap和multiset是树形结构的关联式容器,这四种容器底层原理都是红黑树,容器中的元素是一个有序序列。 ma…

Windows系统安装 ffmpeg

下载及解压 ffmpeg官方下载地址:https://ffmpeg.org/download.html 下载好后将其解压至你想保存的位置中。 环境变量设置 打开Windows设置,在搜索框输入:系统高级设置。 新建环境变量,并输入bin目录具体位置。 安装检查 按住 w…

Ubuntu 系统的基础操作和使用

文章目录 前言常用命令1. 基本操作lscdpwd 2. 对文件的操作touchcatechovim 3. 对目录的操作mkdirrm 4. 移动文件 / 目录的操作cpmv 5. 总结基本操作6. 必不可少的实用操作mangreppsnetstat 总结 前言 本文内容为一些超常用命令, 内容不多且十分实用, 这些命令是每一个开发人员…

Head First Design Patterns - 策略模式

策略模式 策略模式:策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口 和 具体行为的实现。策略模式最大的特点是行为的变化,行为之间可以相互替换。每个if判断都可以理解为就是一个策略。本模式使得算法可…

每日一练(编程题-C/C++)

目录 CSDN每日一练1. 2023/2/27- 一维数组的最大子数组和(类型:数组 难度:中等)2. 2023/4/7 - 小艺照镜子(类型:字符串 难度:困难)3. 2023/4/14 - 最近的回文数(难度:中等)4. 2023/2/1-蛇形矩阵(难度:困难)…

算法通关村第十关—归并排序(黄金)

归并排序 一、归并排序原理 归并排序(MERGE-SORT)简单来说就是将大的序列先视为若干个比较小的数组,分成几个比较小的结构,然后是利用归并的思想实现的排序方法,该算法采用经典的分治策略(分就是将问题分(divide)成一些小的问题分…

BIT-6-指针(C语言初阶学习)

1. 指针是什么 2. 指针和指针类型 3. 野指针 4. 指针运算 5. 指针和数组 6. 二级指针 7. 指针数组 1. 指针是什么? 指针是什么? 指针理解的2个要点: 指针是内存中一个最小单元的编号,也就是地址平时口语中说的指针,通常…

【FPGA】分享一些FPGA视频图像处理相关的书籍

在做FPGA工程师的这些年,买过好多书,也看过好多书,分享一下。 后续会慢慢的补充书评。 【FPGA】分享一些FPGA入门学习的书籍【FPGA】分享一些FPGA协同MATLAB开发的书籍 【FPGA】分享一些FPGA视频图像处理相关的书籍 【FPGA】分享一些FPGA高速…

【什么是反射机制?为什么反射慢?】

✅ 什么是反射机制?为什么反射慢? ✅典型解析✅拓展知识仓✅反射常见的应用场景✅反射和Class的关系 ✅典型解析 反射机制指的是程序在运行时能够获取自身的信息。在iava中,只要给定类的名字,那么就可以通过反射机制来获得类的所有…