记一次 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.mzph.cn/news/240350.shtml

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

相关文章

2024 年 22 款顶级免费数据恢复软件比较 [Windows 和 Mac]

适用于 Windows 和 Mac 用户的最佳数据恢复软件下载列表和比较,可快速恢复丢失的数据、已删除的文件、照片或格式化的分区数据: 数据恢复软件是一种从任何存储介质恢复丢失文件的应用程序。它可以恢复由于病毒攻击、硬盘故障或任何其他原因而意外删除或…

NIO的实战教程(简单且高效)

1. 参考 建议按顺序阅读以下三篇文章 为什么NIO被称为同步非阻塞? Java IO 与 NIO:高效的输入输出操作探究 【Java.NIO】Selector,及SelectionKey 2. 实战 我们将模拟一个简单的HTTP服务器,它将响应客户端请求并返回一个固定的…

Maven核心概念

1 Maven工程的GAVP Maven 中的 GAVP 是指 GroupId、ArtifactId、Version、Packaging 等四个属性的缩写,其中前三个是必要的,而 Packaging 属性为可选项。 这四个属性主要为每个项目在maven仓库中做一个标识,方便项目之间相互引用。 GAV G 即…

桶装水送水小程序:提升服务质量的利器

随着移动互联网的发展,越来越多的消费者通过手机在线购物和订购商品。如果你是一名桶装水供应商,想要拓展线上业务,那么开发一个桶装水微信小程序将是一个明智的选择。本文将指导你从零开始开发一个桶装水微信小程序,让你轻松完成…

Coze在手,GPTsDALLE免费用

1. 关于Coze Coze 是一个应用程序编辑平台,旨在开发下一代人工智能聊天机器人。 你可以使用无代码创建各种类型的聊天机器人,并将其部署到各种社交平台和消息应用程序。 链接: Coze 2. Coze的特点 Coze有5个特点。下面由我来详细介绍一下!…

高级数据结构 <二叉搜索树>

本文已收录至《数据结构(C/C语言)》专栏! 作者:ARMCSKGT 目录 前言正文二叉搜索树的概念二叉搜索树的基本功能实现二叉搜索树的基本框架插入节点删除节点查找函数中序遍历函数析构函数和销毁函数(后序遍历销毁)拷贝构造和赋值重载(前序遍历创建)其他函数…

蓝牙物联网与嵌入式开发如何结合?

蓝牙物联网与嵌入式开发可以紧密结合,以实现更高效、更智能的物联网应用。以下是一些结合的方式: 嵌入式开发为蓝牙设备提供硬件基础设施和控制逻辑:嵌入式系统可以利用微处理器和各种外设组成的系统,为蓝牙设备提供硬件基础设施和…

基于ERC20代币协议实现的去中心化应用平台

文章目录 内容简介设计逻辑ERC20TokenLoanPlatform 合约事件结构体状态变量函数 Remix 运行实现部署相关智能合约存款和取款贷款和还款 源码地址 内容简介 使用 solidity 实现的基于 ERC20 代币协议的借贷款去中心化应用平台(极简版)。实现存款、取款、贷款、还款以及利息计算的…

爬虫API|批量抓取电商平台商品数据,支持高并发

随着互联网的快速发展,电商平台如雨后春笋般涌现,为消费者提供了丰富的购物选择。然而,对于许多商家和数据分析师来说,如何快速、准确地获取电商平台上的商品数据成为了一个难题。为了解决这个问题,我们开发了一个爬虫…

ModuleNotFoundError: No module named ‘tensorflow‘

直接运行pip install tensorflow安装成功之后,发现版本是tensorflow2.15.0 python的版本是3.9版本 导入包:import tensorflow 打包xxx.exe,调用之后提示错误 ModuleNotFoundError: No module named tensorflow 最后发现特定的python的版本对应特定的t…

基础数据结构(2):栈

1.栈的定义 栈是仅限在表尾进行插入和删除的线性表,栈又被称为后进先出的线性表 1.1栈顶和栈底 栈是一个线性表,我们允许插入和删除的一端称为栈顶 栈底和栈顶相对,实际上栈底的元素不需要关心 1.2入栈和出栈 栈元素的插入操作叫做入栈&…

润和软件HopeStage与亚信安全云主机深度安全防护系统完成产品兼容性互认证

近日,江苏润和软件股份有限公司(以下简称“润和软件”)HopeStage 操作系统与亚信科技(成都)有限公司(以下简称“亚信安全”)云主机深度安全防护系统完成兼容性测试。 测试结果表明,企…

12 Vue3中使用v-if指令实现条件渲染

概述 v-if指令主要用来实现条件渲染,在实际项目中使用得也非常多。 v-if通常会配合v-else-if、v-else指令一起使用,可以达到多个条件执行一个,两个条件执行一个,满足一个条件执行等多种场景。 下面,我们分别演示这三…

tamarin manual总结笔记2(tamarin实例)

最初的例子 我们将从一个简单的协议示例开始&#xff0c;该协议仅由两条消息组成&#xff0c;在这里以所谓的Alice-and-Bob表示法编写: C -> S: aenc(k, pkS) C <- S: h(k)在该协议中&#xff0c;客户端C生成一个新的对称密钥k&#xff0c;用服务器S的公钥pkS (aenc代表…

2023 英特尔On技术创新大会直播 |AI科技创新的引路者

英特尔大会 前言英特尔人工智能英特尔创新技术基于英特尔架构的科学计算总结 前言 英特尔技术创新大会是一个令人激动和启发的盛会。在这次大会上&#xff0c;我有幸观看了许多令人瞩目的科技创新和前沿技术的展示。这些展示不仅展示了英特尔作为科技巨头的实力&#xff0c;更…

浏览器原理篇—渲染阻塞

渲染阻塞 1.DOM 的解析 html 文档 边加载边解析 的&#xff1b;网络进程和渲染进程之间会建立一个共享数据的管道&#xff0c;网络进程接收到数据实时传递给渲染进程&#xff0c;渲染进程的 HTML 解析器&#xff0c;它会动态接收字节流&#xff0c;并将其解析为 DOM 2.字节流…

[每周一更]-(第38期):Go常见的操作消息队列

在Go语言中&#xff0c;常见的消息队列有以下几种&#xff1a; RabbitMQ&#xff1a;RabbitMQ是一个开源的AMQP&#xff08;高级消息队列协议&#xff09;消息代理软件&#xff0c;用于支持多种编程语言&#xff0c;包括Go语言。RabbitMQ提供了可靠的消息传递机制和灵活的路由…

基于SSM的在线学习系统的设计与实现论文

基于SSM的在线学习系统的设计与实现 摘要 随着信息互联网购物的飞速发展&#xff0c;一般企业都去创建属于自己的管理系统。本文介绍了在线学习系统的开发全过程。通过分析企业对于在线学习系统的需求&#xff0c;创建了一个计算机管理在线学习系统的方案。文章介绍了在线学习…

【习题】运行Hello World工程

判断题 1. DevEco Studio是开发HarmonyOS应用的一站式集成开发环境。 正确(True)错误(False) 正确(True) 2. main_pages.json存放页面page路径配置信息。 正确(True)错误(False) 正确(True) 单选题 1. 在stage模型中&#xff0c;下列配置文件属于AppScope文件夹的是&am…

信号与线性系统翻转课堂笔记7——信号正交与傅里叶级数

信号与线性系统翻转课堂笔记7——信号正交与傅里叶级数 The Flipped Classroom7 of Signals and Linear Systems 对应教材&#xff1a;《信号与线性系统分析&#xff08;第五版&#xff09;》高等教育出版社&#xff0c;吴大正著 一、要点 &#xff08;1&#xff0c;重点&a…