当前位置: 首页 > news >正文

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 情况 

从下面可以整理出 网路情况如下 

app0192.168.80.3
app1192.168.80.2
nginx192.168.80.4

然后我们来看一下 正常的情况下 处理的后端服务的情况 

可以看到的是 访问的是 ip 是 192.168.80.3 对应于上面的 app0 

我们重启 app0, app1 直到复现问题

我们可以看到 此时处理服务的容器 的ip还是 192.168.80.3 

但是 返回的数据, 却已经是 app1 应该返回的数据了 

我们再来看一下 app0, app1, nginx 的 ip 情况 

从下面可以整理出 网路情况如下 

app0192.168.80.2
app1192.168.80.3
nginx192.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中账户区分为&#xff1a;User Accounts&#xff08;用户账户&#xff09; 和 Service Accounts&#xff08;服务账户&#xff09; 两种&#xff0c;它们的设计及用途如下&#xff1a; UserAccount是给kubernetes集群外部用户使用的&am…...

SpringMVC-响应数据

一、引子 我们在上一篇文章SpringMVC-组件解析里介绍了SpringMVC框架执行一个请求的过程&#xff0c;并演示了快速使用Controller承接请求。本篇我们将深入介绍SpringMVC执行请求时&#xff0c;如何响应客户端。 二、响应类型 SpringMVC的数据响应方式主要分为两类&#xff…...

数学建模:数据相关性分析(Pearson和 Spearman相关系数)含python实现

相关性分析是一种用于衡量两个或多个变量之间关系密切程度的方法。相关性分析通常用于探索变量之间的关系&#xff0c;以及预测一个变量如何随着另一个变量的变化而变化。在数学建模中&#xff0c;这是常用的数据分析手段。   相关性分析的结果通常用相关系数来表示&#xff…...

使用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.请编程实现双向链表的头插&#xff0c;头删、尾插、尾删 头文件&#xff1a; #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 驱动开发基础知识——总线设备驱动模型(七)

个人名片&#xff1a; &#x1f981;作者简介&#xff1a;学生 &#x1f42f;个人主页&#xff1a;妄北y &#x1f427;个人QQ&#xff1a;2061314755 &#x1f43b;个人邮箱&#xff1a;2061314755qq.com &#x1f989;个人WeChat&#xff1a;Vir2021GKBS &#x1f43c;本文由…...

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&#xff0c;默认英文且不带取消保存imagedata的选项。 最简单粗暴的方法就是在json文件保存时把传递过来的imagedata数据设定为None&#xff0c;方法如下&#xff1a; 找到labelme的源文件&#xff0c;例如&#xff1a;D:\conda\envs\deeplab\Lib\site-packages…...

vscode 如何修改c/c++格式化风格,大括号不换行

在Visual Studio Code&#xff08;VSCode&#xff09;中&#xff0c;若要修改C代码格式化的风格以实现大括号不换行&#xff0c;通常会借助于插件C/C扩展中的ClangFormat配置。以下是具体的步骤&#xff1a; 确保已安装了C/C扩展&#xff1a; 打开VSCode的扩展市场&#xff08;…...

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很简单&#xff0c;刻录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-损失函数-笔记

损失函数&#xff0c;用来衡量预测值和真实值之间的区别。是机器学习里面一个非常重要的概念。 三个常用的损失函数 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&#xff08;Aspect Oriented Programming&#xff0c;面向切面编程&#xff09;的代码实现需要依赖Spring AOP库。由于Spring AOP库并不直接支持非Spring应用&#xff0c;你需要将Spring AOP库作为依赖项添加到项目中&#xff0c;并使用Spring AO…...

MongoDB 字段中数据类型不一致序列化异常排查与处理

MongoDB 字段中数据类型不一致序列化异常排查与处理 背景如下&#xff0c;因为项目迁移愿意&#xff0c;一个使用Mongodb的业务拥有C#和Java两组Api。Java Api开发和测试都很顺利。上线一段时间后&#xff0c;客服反馈记录都不见了。查看数据库发现&#xff0c;时间字段拥有两…...

网络安全简介

网络安全&#xff1a; ​ 网络安全攻击分为被动攻击和主动攻击。 1. 被动攻击&#xff1a;是指攻击者从网络上窃取了他人的通信内容&#xff0c;通常把这类的攻击称为截获&#xff0c;被动攻击只要有2种形式&#xff1a;消息内容泄漏攻击和流量分析攻击。由于攻击者没…...

【Docker】.NET Core 6.0 webapi 发布上传到Docker Desktop并启动运行访问,接口返回数据乱码解决方法

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Docker容器》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…...

【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启动流程 引导加载程序启动操作系统相关参考 前言 现代计算机的启动是一个漫长的流程&#xff0c;这个流程中会涉及到各种硬件的配置与交互&#xff0c;包…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...