这个注册的 IP 网络都不通了,Eureka 注册中心竟然无法踢掉它!
本文导读:
- 微服务技术架构选型介绍
- k8s 容器化部署架构方案
- Eureka 注册中心问题场景
- 问题解决手段及原理剖析
阅读本文建议先了解:
- 注册中心基本原理
- K8s(Kuberneters)基本概念
我们的微服务目前都是在服务器上部署的,也是基于 Docker 来部署的。
运维部门基于 K8s 自研了一套容器云管理平台,平台名称叫做 Ares,我们也开始准备将微服务迁移到这平台上,降低虚拟机或实体机服务器运维成本,提高服务器资源利用效率。
Ares:阿瑞斯(战神)
希腊神话中为战争而生的神,奥林匹斯十二神之一,被视为尚武精神的化身。看起来很牛逼的样子!

1、微服务技术架构选型介绍
微服务框架使用了流行的 Spring Cloud 框架。
框架技术组件如下:
- 注册中心选择的是 Eureka
- 网关使用的 Zuul
- 配置中心使用的 Apollo
- 熔断限流使用了 Sentienl + Hystrix
网关 Zuul 层使用了 Ribbon 做负载均衡、Hystrix 做限流熔断。
后端微服务使用了阿里巴巴开源的 Sentinel 做限流熔断。
由于当时服务器的配置不同,比如有低配置的虚拟机,还有高配置的物理机服务器。
所以呢,我们基于当时的服务器配置现状,基于 Ribbon 自行扩展了按照权重的负载均衡策略,对 Eureka 注册中心管理界面做了一点改造,能够支持动态对每台服务器变更权重。
因为本文的问题跟 Eureka 注册中心有关,对 Eureka 架构做个介绍下。
Eureka 注册中心简易架构图:

上图简要描述了 Eureka 的基本架构,由3个角色组成:
1)Eureka Server
提供服务注册、发现、健康检查。
2)Service Provider
服务提供方,
将自身服务注册到 Eureka,从而使服务消费方能够找到,
我们将容器可以作为服务提供者,会注册到 Eureka。
3)Service Consumer
服务消费方,
从Eureka获取注册服务列表,从而能够消费服务
我们可以将 Zuul 网关作为服务消费者。
2、K8s 容器化部署架构方案
考虑到使用的 Spring Cloud 框架,结合运维提供的容器平台。
制定容器化部署架构如下:

从容器创建到可访问流程:
1)创建容器
选择镜像及版本、CPU、内存配置、配置健康检查、日志收集、Pod 副本数量。提交创建容器。
2)服务注册
容器启动时,申请 SLB VIP,作为服务注册 IP,向 Eureka 上发起注册。
3)网关发起请求
域名请求,DNS 解析经过 GSLB(全局软负载均衡)负载到 Zuul 网关,Zuul 网关从 Eureka 注册中心拉取服务注册表,通过 Ribbon 负载均衡,从本地服务注册列表中,选择其中一台 Server,发起 Http 调用。
4)容器提供服务
容器内注册的是 SLB VIP(软负载均衡),这个 SLB 通过内部的 Nginx 负载均衡机制,轮询到后端的容器的多个 Pod IP 上,Pod IP 正是我们部署的微服务业务。
为什么要使用SLB VIP呢?
当时我们对接口压测时,发现使用 K8s 内部的 Service IP 存在性能瓶颈,该问题还在研究中。后来运维内部商榷,使用 SLB 来达到负载均衡的效果。
另外说明一点:
运维基于 K8s 自研的这套容器平台,网络层面做了重新架设和优化,打通了各个机房的网络。
这样做给我们的架构部署带来了好处:
前期目标仅为了迁移微服务业务,考虑到稳定性等因素,正式上线的Zuul网关和Eureka 注册中心部署在 K8s 集群外,微服务业务部署在容器内,因网络可通,容器启动后申请的 VIP,可以直接注册到 Eureka 上。
仿真环境(预上线环境)是直接将Eureka注册中心,也部署在了容器平台中,接下来会说下,因此导致的一些问题,以及解决该问题的方式。
3、Eureka 注册中心问题场景
容器测试阶段结束,由于运维调整为了 SLB VIP,将以前的应用(一个应用下包含多个 Pod 容器)都删除掉,我们重新搭建一套仿真环境用于,上线前的性能测试环境。
但是当我们部署完 Eureka 后,发现以前删除掉的应用VIP 也注册上来了,而且这个 VIP 网络是不通的,无法访问的。
Eureka 管理控制台示意图:

telnet 命令测试:
telnet 10.11.195.197 80
Trying 10.11.195.197...
telnet: connect to address 10.11.195.197: Network is unreachable
telnet: Unable to connect to remote host
结果提示 10.11.195.197 这个 VIP,网络是不可达的。
那为什么这个服务能注册上来呢?
起初,跟运维老哥请教,经过容器内排查后,也暂时没有太多眉目,确定是这个 VIP,已经下线了,网络也不通。
按照这个推测,是不太可能注册到 Eureka 上来的。
开始考虑到以为是 Eureka 机制是不是有问题,但仔细用「屁股」猜想论思考一下,结合 Eureka 框架底层原理来看,是不应该出现这个情况。
根据 Eureka 续约机制,一定是有哪个「哥们」在默默给这个服务 IP 发续约(向注册中心发送心跳)。
我们在 Eureka Server 服务端,也有监听各个动作的机制,如注册服务、续约服务、下线服务,根据日志看,也的确是有这个服务 IP 一直在发送续约动作。
续约监听代码:
@EventListener
public void listen(EurekaInstanceRenewedEvent event) {
InstanceInfo instanceInfo = event.getInstanceInfo();
if (instanceInfo != null) {
logger.info("renew ...." + instanceInfo.getInstanceId());
} else {
logger.info("renew ....instanceInfo is null");
}
}
4、问题解决手段及原理剖析
既然引出了上述问题,当然不能放任不管,一定要一探究竟。
这种问题你若不理他,早晚会搞出点别的事情来的。
Eureka 服务端已经收到了注册和一直续约的请求,说明一定是有哪个服务一直在偷偷发送心跳。
到底是谁干的啊?

到底如何找到这个上报的服务呢?
运维老哥暂时比较忙,看来只能先查找网络链路,抓取网络数据包看看到底是怎么回事了。
网络工具一般常用的就是 tcpdump、Wireshark。
Wireshark 小故事:
大概发生在 10 几年前,主导 Ethereal(应该听说过吧)的大佬跳槽了,然后这个商标就不能继续使用了,但是这个工具在当时来说人气很旺,后来大佬就将项目更名为 Wireshark 了。
服务器上命令行的抓包程序 tethereal 更名为了 tshark。
容器镜像中默认是不会自带这些工具的。镜像中 Linux 操作系统使用的是 CentOS,通过自带的 yum 源安装网络工具包,比较方便。
安装 wireshark:
yum install -y wireshark
安装 tcpdump:
yum install -y tcpdump
这里我们使用的是 Wireshark 工具,简单介绍下这个工具:
如果你要看到全部网络数据包,直接执行tshark命令即可。
1)获得 tshark 命令帮助
tshark --help
2)tshark 抓包模式参数一览

3)tshark 命令实战使用
打印源目标 Host 及 Http 协议信息:
tshark -s 512 -i eth0 -n -f 'tcp dst port 80' -t ad -R 'http.host and http.request.uri' -T fields -e "frame.time" -e "ip.src" -e "http.host" -e "http.request.method" -e "http.request.uri" | tr -d ' '
参数解释:
-i 捕获 eth0 网卡;
-n 禁止所有地址名字解析(默认为允许所有)
-t 设置解码结果的时间格式。
"ad"表示带日期的绝对时间,"a"表示不带日期的绝对时间,"r"表示从第一个包到现在的相对时间,“d”表示两个相邻包之间的增量时间(delta)-R 设置读取(显示)过滤表达式(read filter expression)
-T -e 输出指定的字段
执行结果:

来段文本:
[root@mas-manager-eureka-es1-66cb79bfb7-snmxm manager]# tshark -n -t a -R http.request -T fields -e "frame.time" -e "ip.src" -e "http.host" -e "http.request.method" -e "http.request.uri" | grep 10.11
Running as user "root" and group "root". This could be dangerous.
Capturing on eth0
Sep 27, 2019 00:22:05.174770971 10.124.12.169 10.124.14.4 PUT /eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569490783397
Sep 27, 2019 00:22:13.814821143 10.124.11.125 10.124.14.4 PUT /eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569407741389
Sep 27, 2019 00:22:15.180243816 10.124.11.123 10.124.14.4 PUT /eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569490783397
通过抓包,根据问题 IP 过滤得到的结果,我们看到了
/eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569490783397
说明是有 IP 在上报,上报来源 IP 就是第二列的 IP。
将这个信息提供给运维同学,根据来源 IP 去继续查找线索。
但是,发现第二列 IP 并不是实际的服务器节点 IP,查不到。因为这些 IP 都是主机上的虚拟 IP,每次上报来源 IP 不同,所以还要反向查找实际归属的主机节点。
为什么要有虚拟 IP?
实际是 SLB 节点上虚拟 IP,因为会负载到它所属主机节点,这台主机上默认只能支撑最大 65535 个 TCP 连接,所以为了单机能支撑更高的 TCP 连接数,会虚拟出来很多个 IP。假设有 10 个虚拟 IP,每个虚拟 IP 支撑 65535 个 TCP 连接,这台主机总共可以支撑 10 * 65535 = 60万以上的连接数了。
K8s 有多套集群,每个集群中有很多台主机节点,茫茫主机池中怎么去查找这些虚拟 IP 呢,
其实我们的目的是为了找到,谁往注册中心发送请求了,还是可以继续通过抓取网络数据包来定位这个问题。
这些网络数据包一定会经过 K8s 集群里的某一台节点,一台一台去找,很麻烦,编写简单脚本抓包查找:
#!/bin/bash
tcpdump -i any host 10.124.14.4 -n -s 0 -X -l | grep 10.11.195>/tmp/1.txt &
sleep 20s
kill -2 %1
cat /tmp/1.txt
网络抓包结果:

截取了关键的抓包信息:
11:41:56.598204 IP 10.110.157.81.54078 > 10.124.14.4.http: Flags [P.], seq 273:622, ack 218, win 245, options [nop,nop,TS val 3348483954 ecr 1420800289], length 349: HTTP: PUT /eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569394834392 HTTP/1.1
这里的 10.110.157.81.54078 就是主机节点 IP,目标地址 10.124.14.4 就是容器内的 Eureka 注册中心地址。
发送的请求是 /eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569394834392
这个请求地址上就带了 10.11.195.197 这个网络不可达的 IP 地址。
到这里,其实我们已经基本定位到了,一定是从 K8s 集群容器内发出来了。
根据这个有价值的节点信息,连接到 K8s 集群内,查找该节点上部署的容器。
查找 K8s 集群内 Pod 命令行:
kubectl get pod --all-namespaces -o wide |grep 10.110.157.81
部署在改节点上的容器:

运维根据 Eureka 上名称大概猜测一下,终于找到这个「罪魁祸首」的容器了。
进入容器内,查看配置 SVIP (Eureka上的注册IP)就是 10.11.195.197 这个IP。
将这个问题容器彻底关闭后,没有再继续发送续约请求,Eureka 注册中心上过了一段时间摘掉了 IP。
大家可能有疑问,这么繁琐,为啥不直接到 K8s 集群内去找,因为 K8s 集群内目前已有业务在运行着,集群内有几百个容器在跑着。当时运维一起测试时,容器名称都是自定义的,所以不是很好查找。
咱们经过这个过程的排查,确认了这个 Eureka 注册中心上的地址虽然不通,但是一直是有容器在上报,而上报的「ServerId」指向的 10.11.195.197:80 地址。
我们也可以结合底层源码了解下。
Eureka 续约时序图:

接口实现方式跟注册服务类似,更新自身状态后,会同步到其他集群节点。
PeerAwareInstanceRegistryImpl 类的 renew 方法会调用到 AbstractInstaceRegistry 抽象实例注册类的 renew 方法。
AbstractInstaceRegistry#renew 方法源码:

会根据服务 id 从注册表中获取 Lease 对象,如果不为空,则完成续约,更新 lastUpdateTimestamp 字段。

Eureka 注册表的数据结构:
private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry
= new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>();
是一个 ConcurrentHashMap 结构,Key 就是应用名称,Value 也是一个 Map 结构。
Map 结构中的 Key 是注册ID(IP + 端口),Value 是 Lease 服务续约对象,里面包含了动作类型,最后上报(心跳)更新时间戳等等信息。
容器服务作为 Eureka Client,每隔一定时间间隔(默认60秒)向注册中心发起一次续约。
Eureka Server 会定时检测服务实例心跳是否正常,如果间隔一定时间(90秒),还没有来续约,就会将这个服务从注册中心摘除掉。
最后总结:
总结上述分析过程,一图胜千言:

重要的不是结果,而是这个过程,希望你也能享受这个过程。
参考资料:
Wireshark 使用文档:
https://www.wireshark.org/docs/man-pages/tshark.html
Netflix Eureka 源代码:
https://github.com/netflix/eureka
欢迎关注我的公众号,更多精彩文章,与你一同成长,扫二维码关注~

这个注册的 IP 网络都不通了,Eureka 注册中心竟然无法踢掉它!的更多相关文章
- 搭建高可用的Eureka注册中心
搭建高可用的Eureka注册中心 一.搭建高可用的Eureka的作用 当服务器因种种原因导致Eureka注册中心(后面简称Eureka)服务当机(服务器跪了,异常关闭停止服务).这样就会影响到整个业务 ...
- SpringCloud系列(一):Eureka 注册中心
在演示spring cloud之前得要知道我们为什么需要微服务框架. 先讲讲我的经历,以前我们做项目时所有功能都写在一起,只是做了分层(模型,数据,业务),所有业务逻辑都写在业务层,刚开始还好,等时间 ...
- ubuntn 虚拟机NAT 静态IP 网络配置
在虚拟机安装ubuntu12.04自动获取IP 一切都没有问题 ssh连接也正常.关机重启后郁闷的发现网络已经不通了,于是开始了以下的摸索. 1.配置静态IP 网关: ip段: 命令: Vim /et ...
- tcp/ip网络里的客户端和服务器端 信息交流 与 安全
ISP(Internet Service Provider) 互联网服务提供商, 即向广大用户综合提供互联网接入业务.信息业务.和增值业务的电信运营商. 通过wireshark学习tcp/ip. 用w ...
- IP网络设计
一.总体规划 网络设计的分层思想 按照网络设计的分层思想,通常将网络分为:核心层.汇聚层和接入层三个部分.这三部分在功能上有明显差别 ,因此在IP设计上,有必要对这三个部分区别对待. 二.核心层 核心 ...
- Linux学习(1)- TCP/IP网络协议基础
Linux学习(1)- TCP/IP网络协议基础 一.TCP/IP 简介 学习内容 TCP/IP(Transmission Control Protocol/Internet Protocol)是传输 ...
- TCP/IP网络知识点总结
学完了计算机网络是时候整理一篇总结了,温故知新.注意:这篇博客很长长长(2.5万字+50图). TCP/IP网络知识点总结 一.总述 1.定义:计算机网络是一些互相连接的.自治的计算机的集合.因特网是 ...
- TCP/IP网络编程之优于select的epoll(一)
epoll的理解及应用 select复用方法由来已久,因此,利用该技术后,无论如何优化程序性能也无法同时接入上百个客户端.这种select方式并不适合以web服务端开发为主流的现代开发环境,所以要学习 ...
- TCP/IP网络编程之优于select的epoll(二)
基于epoll的回声服务端 在TCP/IP网络编程之优于select的epoll(一)这一章中,我们介绍了epoll的相关函数,接下来给出基于epoll的回声服务端示例. echo_epollserv ...
随机推荐
- Docker系列之镜像瘦身(五)
前言 本节我们来讲讲在我们在构建镜像过程中不出问题,同时使得最后所构建的镜像文件大小尽可能最小,温馨提示:文中大图均可点击放大查看详细信息. 缓存(cache) Docker的优势之一在于提供了缓存, ...
- 《Tomcat和JVM的性能调优你真的学会了吗?》总结篇
Tomcat性能调优: 找到Tomcat根目录下的conf目录,修改server.xml文件的内容.对于这部分的调优,我所了解到的就是无非设置一下Tomcat服务器的最大并发数和Tomcat初始化时创 ...
- ubuntu安装后的基本配置及常用软件的安装
文章作者:foochane 原文链接:https://foochane.cn/article/2019061501.html 内容简介 当前Ubuntu版本:ubuntu 18.04,具体操作如下: ...
- 我常用的一些linux命令
之前做过两年的运维,用过很多命令,深切体会到某些linux命令熟练掌握后对效率提升有多大.举个简单的例子,在做了研发后经常会有跑一些数据,对于结果数据的处理,我们的产品同学一般都习惯于用excel做统 ...
- 玩转 SpringBoot 2 快速搭建 | RESTful Api 篇
概述 RESTful 是一种架构风格,任何符合 RESTful 风格的架构,我们都可以称之为 RESTful 架构.我们常说的 RESTful Api 是符合 RESTful 原则和约束的 HTTP ...
- 04_枚举类型iota
iota是枚举类型的关键字,使用iota可以方便快捷的给常量赋值,主要体现在以下几个方面:1.iota常量自动生成器,每个一行加12.iota给常量赋值使用3.iota遇到const重置为04.可以写 ...
- mysql where、group by、having
今天重新温习一遍mysql的知识 先来讲讲where.group by.having group by :是将记录中的数据,按照条件进行分组: having:是将分组后的数据加上条件筛选,区别于whe ...
- spring boot application 配置详情
# =================================================================== # COMMON SPRING BOOT PROPERTIE ...
- TensorFlow Distribution(分布式中的数据读取和训练)
本文目的 在介绍estimator分布式的时候,官方文档由于版本更新导致与接口不一致.具体是:在estimator分布式当中,使用dataset作为数据输入,在1.12版本中,数据训练只是datase ...
- Salesforce LWC学习(六) @salesforce & lightning/ui*Api Reference
上一篇中我们在demo中使用了很多的 @salesforce 以及 lightning/ui*Api的方法,但是很多没有细节的展开.其实LWC中针对这些module提供了很多好用的方法,下面对这两种进 ...