88 docker 环境下面 前端A连到后端B + 前端B连到后端A
前言
呵呵 最近出现了这样的一个问题, 我们有多个前端服务, 分别连接了对应的后端服务, 前端A -> 后端A, 前端B -> 后端B
但是 最近的时候 却会出现一种情况就是, 有些时候 前端A 连接到了 后端B, 前端B 连接到了 后端A
我们 前端服务使用 nginx 提供前端 html, js, css 的服务, 对于前端业务中的请求, 也是使用的 nginx 来代理到真实的后端服务上面, 后端服务 我们就假定为普通的 tomcat 服务器, 前后端服务都是部署在 docker 上面
然后 就给人造成一种 数据跑掉了的错觉, 呵呵 也是引起了我们同事 使用系统的很大的疑惑, 然后 搞出了一些 "我的数据 再和我做迷藏", "我的数据从成都跑到北京去了" 之类的笑话
然后 你一去检查服务的配置, 等等, 你发现 前端配置, 后端配置 都没得问题, 我最开始以为是 nginx 运行时加载的配置 被修改了?, 加载在内存的配置 和 实际的配置文件不一致?, 但是 实际 看了一下, 发现配置是 没有问题的
对于这个问题 还是很好奇的, 当然 后面也做了一些 探索, 也有一些 初步的推断, 然后 今天的时候[1114] 尝试在本地复现一下这个问题, 也发现了一些 和自己开始的判断 不一样的一些地方
let's go
问题特征
这个问题的出现 和 消失有这样的一些特征
1. 所有的前端, 后端配置都是正常的, 但是 实际接口返回的数据 就是不一样
2. 出现了这个问题之后, 重启一下 前端服务 之后, 前端服务就正常了
3. 一般是后端代码更新了之后, jenkins 自动发版之后 会出现这个问题
前端容器中 也缺少 ping 之类的网络工具, 造成排查的时候 还是存在一些 障碍
问题inspect
最开始 想要处理这个问题, 我得看一下 nginx 最终吧服务转发到了 那一台后端服务器
因此, 在 nginx 配置的地方, 增加了一个 add_header backendIP $upstream_addr; 来获取实际处理 后端请求的服务的信息
然后 后来一次 是因为 后台发版了, 之后 这个问题就复现了, 这也使我观察到了 上面的 特征3
然后 看一下 backendIP, 然后 再 inspect 对应的额后端服务, 发现后端服务的 ip 和这个 backendIP 对不上 ??
所以 问题的大致原因 也就出现了, 发版之后 后端服务的 ip 变化了, 然后 前端服务里面访问的 ip 还是之前的 ip
当然 最开始, 我以为是 前端服务里面的 dns 缓存之类的, 直到今天 测试了一下, 发现 似乎是其他的原因
接下来 我们便来以一个 demo 实际的走一下 这个流程
构造问题
首先 我们需要 一个前端服务, 和 两个后端服务, 前端服务A 只连接 其中的一个 后端服务A
然后 之后我们同时重启 两个后端服务, 然后 再来访问这个 前端服务A, 可能会存在 前端服务A 访问到了 后端服务B 的情况
1. 看下后端服务
一个简单的 SpringBoot 项目, 其中开放了一些简单的接口, 比如这里的 /hello/context, 可以输出 当前应用名称 和 一些上下文的信息
2. 部署后端服务
首先来部署两个后端服务, docker-compose 大致如下
两个服务使用 同一个镜像, 只是传递的环境变量的 APP_NAME 有一些区别, 因此 访问 /hello/context 的时候 appName 的输出会有一些区别
另外使用同一个镜像的原因在于, 更加简单的构造 两个镜像同时重启
version: "2"networks:fuzzy:external: trueservices:app0:container_name: app0image: app0:0.0.1ports:- "7901:7901"environment:APP_NAME: app0networks:- fuzzyapp1:container_name: app1image: app0:0.0.1ports:- "7902:7901"environment:APP_NAME: app1networks:- fuzzy
服务起起来之后 测试一下, 这里把服务映射到了宿主机的端口, 根据这个来测试一下
访问情况如下, 可以看到是 符合我们的预期的, 不是很意外
http://localhost:7901/hello/context
http://localhost:7902/hello/context
3. 部署前端服务
前端服务我们这里 为了简单, 是直接使用的 nginx 镜像, 没有业务, 连接 app0 的服务
前端服务的 docker-compose 如下
version: "2"networks:fuzzy:external: trueservices:nginx:container_name: nginximage: nginx:latestports:- "80:80"volumes:- ./data:/etc/nginxnetworks:- fuzzy
nginx 配置大致如下
可以看到 /hello 开头的这部分请求, 我们把它 转发到了 app0 的服务上面, 使用 add_header backendIP $upstream_addr; 输出了一下 具体的处理业务的后端服务器的信息
server {listen 80;listen [::]:80;server_name localhost;location / {root /usr/share/nginx/html;index index.html index.htm;}location ~ /hello {proxy_pass http://app0:7901;add_header backendIP $upstream_addr;proxy_set_header SSL-Client-Cert $ssl_client_cert;proxy_set_header name jerry;}#error_page 404 /404.html;# redirect server error pages to the static page /50x.htmlerror_page 500 502 503 504 /50x.html;location = /50x.html {root /usr/share/nginx/html;}}
4. 正常情况 和 出现问题的情况
正常的情况
出现问题
问题细节
正常情况
首先我们看一下 app0, app1, nginx 的 ip 情况
从下面可以整理出 网路情况如下
app0 | 192.168.80.3 |
app1 | 192.168.80.2 |
nginx | 192.168.80.4 |
然后我们来看一下 正常的情况下 处理的后端服务的情况
可以看到的是 访问的是 ip 是 192.168.80.3 对应于上面的 app0
我们重启 app0, app1 直到复现问题
我们可以看到 此时处理服务的容器 的ip还是 192.168.80.3
但是 返回的数据, 却已经是 app1 应该返回的数据了
我们再来看一下 app0, app1, nginx 的 ip 情况
从下面可以整理出 网路情况如下
app0 | 192.168.80.2 |
app1 | 192.168.80.3 |
nginx | 192.168.80.4 |
可以看到的是 app0 和 app1 的 ip 变了, 两个容器的 ip 交换了一下, 但是 前端容器 还是将服务委托给了 192.168.80.3 的这个容器, 而不是 app0 这个服务
是前端容器的 dns 的缓存么?
为了 验证这个问题, 呵呵 可以使用 ping 或者 nslookup 之类的网络工具, 但是 在 nginx 容器里面这两个都没得
我今天 还想了一阵子, 怎么验证这个问题, 呵呵 curl 有一个 -v, verbose 展示出请求的更详细的信息
curl -v http://app0:7901/hello/context
从下面的日志信息可以看出, 从 前端服务的容器中访问 app0 访问的是 最新的app0[192.168.80.2], 因此可以排除 容器的 dns缓存的猜测
master:nginx jerry$ docker exec -it nginx /bin/sh
# curl -v http://app0:7901/hello/context
* Expire in 0 ms for 6 (transfer 0x55712a1dff50)
* Expire in 1 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 1 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 2 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 2 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 2 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 2 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Expire in 0 ms for 1 (transfer 0x55712a1dff50)
* Trying 192.168.80.2...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x55712a1dff50)
* Connected to app0 (192.168.80.2) port 7901 (#0)
> GET /hello/context HTTP/1.1
> Host: app0:7901
> User-Agent: curl/7.64.0
> Accept: */*
>
< HTTP/1.1 200
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 135
< Date: Sat, 14 Nov 2020 09:24:12 GMT
<
* Connection #0 to host app0 left intact
context info as follow!, APP_NAME : app0<br/> headers : {"host":"app0:7901","user-agent":"curl/7.64.0","accept":"*/*"}<br/> params : {}
nginx 的 dns 缓存
nginx -s reload 一下
# nginx -s reload
2020/11/14 09:27:13 [notice] 33#33: signal process started
看一下 /hello/context 的情况, 返回的数据也是 app0 处理之后返回的数据, backendIP 也更新成了 192.168.80.2[app0对应的ip]
所以之前的处理方式 : 重启前端服务, 实际上真正解决问题的是 nginx 的重新加载
完
参考
nginx查看请求被转发到哪台服务器
相关文章:

88 docker 环境下面 前端A连到后端B + 前端B连到后端A
前言 呵呵 最近出现了这样的一个问题, 我们有多个前端服务, 分别连接了对应的后端服务, 前端A -> 后端A, 前端B -> 后端B 但是 最近的时候 却会出现一种情况就是, 有些时候 前端A 连接到了 后端B, 前端B 连接到了 后端A 我们 前端服务使用 nginx 提供前端 html, js…...
k8s学习-Service Account和RBAC授权
1.1 ServiceAccount 介绍 首先Kubernetes中账户区分为:User Accounts(用户账户) 和 Service Accounts(服务账户) 两种,它们的设计及用途如下: UserAccount是给kubernetes集群外部用户使用的&am…...
SpringMVC-响应数据
一、引子 我们在上一篇文章SpringMVC-组件解析里介绍了SpringMVC框架执行一个请求的过程,并演示了快速使用Controller承接请求。本篇我们将深入介绍SpringMVC执行请求时,如何响应客户端。 二、响应类型 SpringMVC的数据响应方式主要分为两类ÿ…...

数学建模:数据相关性分析(Pearson和 Spearman相关系数)含python实现
相关性分析是一种用于衡量两个或多个变量之间关系密切程度的方法。相关性分析通常用于探索变量之间的关系,以及预测一个变量如何随着另一个变量的变化而变化。在数学建模中,这是常用的数据分析手段。 相关性分析的结果通常用相关系数来表示ÿ…...

使用pandas将excel转成json格式
1.Excel数据 2.我们想要的JSON格式 {"0": {"raw_data1": "Sam","raw_data2": "Wong","raw_data3": "Good","layer": "12v1"},"1": {"raw_data1": "Lucy…...

双向链表的插入、删除、按位置增删改查、栈和队列区别、什么是内存泄漏
2024年2月4日 1.请编程实现双向链表的头插,头删、尾插、尾删 头文件: #ifndef __HEAD_H__ #define __HEAD_H__ #include<stdio.h> #include<stdlib.h> #include<string.h> typedef int datatype; enum{FALSE-1,SUCCSE}; typedef str…...

Linux 驱动开发基础知识——总线设备驱动模型(七)
个人名片: 🦁作者简介:学生 🐯个人主页:妄北y 🐧个人QQ:2061314755 🐻个人邮箱:2061314755qq.com 🦉个人WeChat:Vir2021GKBS 🐼本文由…...
RTthread线程间通信(邮箱,消息队列,信号/软件中断)---03信号(软件中断)源码分析
信号 实际使用看这一个 #if defined(RT_USING_SIGNALS)rt_sigset_t sig_pending; /**< the pending signals 记录来了的信号 */rt_sigset_t sig_mask; /**< the mask bits of signal 记录屏蔽的信号 */rt_sigh…...

老版本labelme如何不保存imagedata
我的版本是3.16,默认英文且不带取消保存imagedata的选项。 最简单粗暴的方法就是在json文件保存时把传递过来的imagedata数据设定为None,方法如下: 找到labelme的源文件,例如:D:\conda\envs\deeplab\Lib\site-packages…...

vscode 如何修改c/c++格式化风格,大括号不换行
在Visual Studio Code(VSCode)中,若要修改C代码格式化的风格以实现大括号不换行,通常会借助于插件C/C扩展中的ClangFormat配置。以下是具体的步骤: 确保已安装了C/C扩展: 打开VSCode的扩展市场(…...

IP协议(2) 和 数据链路层协议基础
IP协议续 1.路由选择 在复杂的网络结构中,我们需要找到一个通往终点的路线,这就是路由选择 举个例子:我们在没有手机导航之前,想去一个地方得是到一个地方问一下路的方式最终找到目的地 路由的过程,其实就是样子问路的过程 1.当IP数据包到达路由器的时候,会查看目的IP 2.路由器…...
Flink-1.18.1环境搭建
下载 下载flink安装包 Index of /dist/flink/flink-1.18.1 下载flink-cdc安装包 Release Release 3.0.0 ververica/flink-cdc-connectors GitHub 安装 添加环境变量 vi ~/.bash_profile export FLINK_HOME=/home/postgres/flink/flink-1.18.1 export PATH=$PATH:$FL…...
deepin20.9安装及配置
安装deepin20.9很简单,刻录u盘 安装 一路next apt install nginx global vim-nox debian11 使用apt安装php, 使php多版本共存_debain11 php5-CSDN博客 vim LeaderF安装问题 - 知乎 debian10安装vue环境, 包括安装node.js-CSDN博客 debian安装vue3 nodejs20-CSD…...

2-2 动手学深度学习v2-损失函数-笔记
损失函数,用来衡量预测值和真实值之间的区别。是机器学习里面一个非常重要的概念。 三个常用的损失函数 L2 loss、L1 loss、Huber’s Robust loss 均方损失 L2 Loss l ( y , y ′ ) 1 2 ( y − y ′ ) 2 l(y,y^{\prime})\frac{1}{2}(y-y^{\prime})^{2} l(y,y′)21…...
非springboot 使用aop 切面
在非Spring Boot应用中使用AOP(Aspect Oriented Programming,面向切面编程)的代码实现需要依赖Spring AOP库。由于Spring AOP库并不直接支持非Spring应用,你需要将Spring AOP库作为依赖项添加到项目中,并使用Spring AO…...
MongoDB 字段中数据类型不一致序列化异常排查与处理
MongoDB 字段中数据类型不一致序列化异常排查与处理 背景如下,因为项目迁移愿意,一个使用Mongodb的业务拥有C#和Java两组Api。Java Api开发和测试都很顺利。上线一段时间后,客服反馈记录都不见了。查看数据库发现,时间字段拥有两…...
网络安全简介
网络安全: 网络安全攻击分为被动攻击和主动攻击。 1. 被动攻击:是指攻击者从网络上窃取了他人的通信内容,通常把这类的攻击称为截获,被动攻击只要有2种形式:消息内容泄漏攻击和流量分析攻击。由于攻击者没…...

【Docker】.NET Core 6.0 webapi 发布上传到Docker Desktop并启动运行访问,接口返回数据乱码解决方法
欢迎来到《小5讲堂》,大家好,我是全栈小5。 这是《Docker容器》系列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对…...

【Android Gradle 插件】自定义 Gradle 插件模块 ⑤ ( 完整总结 )
一、创建自定义插件类型模块 ( Java or Kotlin Library ) 选择 " 菜单栏 / New / New Module… " 选项 , 在 " Create New Module " 对话框中 , 选择 创建 " Java or Kotlin Library " 类型的依赖库 ; 二、手动导入相关依赖 ( Java | Groovy | …...

浅析现代计算机启动流程
文章目录 前言启动流程概述磁盘分区格式MBR磁盘GPT磁盘隐藏分区 传统BIOS引导传统BIOS启动流程 UEFI引导UEFI引导程序UEFI启动流程 引导加载程序启动操作系统相关参考 前言 现代计算机的启动是一个漫长的流程,这个流程中会涉及到各种硬件的配置与交互,包…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...