鸿 网 互 联 www.68idc.cn

当前位置 : 服务器租用 > 编程语言开发 > java > >

Wireshark抓包分析Eureka注册发现协议

来源:互联网 作者:佚名 时间:2022-07-19 11:02
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 前面的系列文章中,我们分析源码对Eureka有了深入了解,其中获取服务列表、注册、续约

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

  • 前面的系列文章中,我们分析源码对Eureka有了深入了解,其中获取服务列表、注册、续约等操作都涉及到client和server端的交互,今天我们通过Wireshark抓包来分析这些交互的内容,以印证之前的代码分析,加深印象

源码分析系列文章

  • 以下是整理的Eureka源码分析系列,用于参考:
  • 《Spring Cloud源码分析之Eureka篇第一章:准备工作》
  • 《Spring Cloud源码分析之Eureka篇第二章:注册中心启动类上的注解EnableEurekaServer》
  • 《Spring Cloud源码分析之Eureka篇第三章:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)》
  • 《Spring Cloud源码分析之Eureka篇第四章:服务注册是如何发起的》
  • 《Spring Cloud源码分析之Eureka篇第五章:更新服务列表》
  • 《Spring Cloud源码分析之Eureka篇第六章:服务注册》
  • 《Spring Cloud源码分析之Eureka篇第七章:续约》
  • 《Spring Cloud源码分析之Eureka篇第八章:服务注册名称的来历》
  • 实战环境简介

    • 为了组建Spring cloud环境,本次实战用了三台电脑,部署情况如下图:

    image.png

    • 三台电脑的详细情况如下表所示:
    应用名称 身份 IP地址 端口 启动顺序 操作系统 备注 springclouddeepeureka Eureka server 192.168.31.147 8081 第一 Linux springclouddeepprovider Eureka client 192.168.31.104 8082 第二 Windows10 这台电脑上安装了Wireshark2.6.3 springclouddeepconsumer Eureka client 192.168.31.88 8083 第三 Linux 此应用先不启动,<br>等抓包后再启动,以便观察变化

    应用源码下载

    • springclouddeepeureka、springclouddeepprovider、springclouddeepconsumer这三个应用,在文章《Spring Cloud源码分析之Eureka篇第一章:准备工作》中已有详细介绍,本文不多说了,您可以参考文章,也可以在github下载这三个应用的源码,地址和链接信息如下表所示:
    名称 链接 备注 项目主页 https://github.com/zq2599/blog_demos 该项目在GitHub上的主页 git仓库地址(https) https://github.com/zq2599/blog_demos.git 该项目源码的仓库地址,https协议 git仓库地址(ssh) git@github.com:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议
    • 这个git项目中有多个文件夹,本章源码分别在springclouddeepeureka、springclouddeepprovider、springclouddeepconsumer这三个文件夹下,如下图红框所示:

    image.png

    实战步骤

  • 修改应用的配置文件;
  • 编译构建三个应用,得到三个jar包;
  • 在三台电脑上分别部署应用;
  • 启动springclouddeepeureka;
  • 在springclouddeepprovider所在电脑上启动Wireshark,并配置好过滤规则;
  • 启动springclouddeepprovider;
  • Wireshark抓包,分析注册、续约、下载服务列表等请求响应;
  • 启动springclouddeepconsumer;
  • Wireshark抓包,分析服务列表的变化;
  • 停止应用springclouddeepconsumer;
  • Wireshark抓包,分析服务列表的变化;
  • 关于机器的小建议

    • 三台电脑的成本不低,除了用老旧电脑东拼西凑,也可以考虑租用云服务器,我这里的Linux电脑是树莓派,装64位Linux,再装上JDK8就能部署和运行springboot应用了,树莓派安装64位系统请参考《树莓派3B安装64位操作系统(树莓派无需连接显示器键盘鼠标) 》

    • 接下来开始实战吧;

    修改应用的配置文件

    • 根据前面提供的Github地址下载三个应用源码;
    • springclouddeepprovider和springclouddeepconsumer这两个应用的application.yml文件都要修改,配置项eureka.client.serviceUrl.defaultZone的值都改成http://192.168.31.147:8081/eureka/,如下图红框所示:

    image.png

    编译构建三个应用

    • 在每个应用的目录下分别执行命令mvn clean package -Dmaven.test.skip=true docker:build,即可在target目录得到应用对应的jar文件,例如springclouddeepeureka工程的jar文件是springclouddeepeureka-0.0.1-SNAPSHOT.jar,如下图所示:

    image.png

    在三台电脑上分别部署应用

    • 将三个jar文件分别部署到对应的三台电脑上,并保证这三台电脑上都已装有JDK1.8版本;

    启动springclouddeepeureka

    • 登录springclouddeepeureka所在的电脑,在springclouddeepeureka-0.0.1-SNAPSHOT.jar文件所在目录下执行命令java -Xms256m -Xmx256m -jar springclouddeepeureka-0.0.1-SNAPSHOT.jar,这样Eureka server就启动了;

    启动和配置Wireshark

  • 应用springclouddeepprovider所在的电脑是Windows10操作系统,上面安装了Wireshark2.6.3,现在请运行它;
  • 首先在网卡列表中确定自己用的是哪一个,我这里用的是无线网卡,因此双击下图红框位置:
  • image.png

  • 配置过滤规则,本次抓的包是HTTP的,并且只关注和Eureka server之间的请求响应,因此过滤规则是ip.addr == 192.168.31.147 && http,将此规则填入下图红框中的位置,再按下回车键:
  • image.png

    • 如上图,之前的数据都没有了,内容窗口空空如也,这是因为应用springclouddeepprovider还未启动,和Eureka server之间并没有什么请求响应;

    启动springclouddeepprovider

    • 执行以下命令启动应用springclouddeepprovider
    java -Xms256m -Xmx256m -jar springclouddeepprovider-0.0.1-SNAPSHOT.jar
    • 启动后,在Eureka server的管理页面http://192.168.31.147:8081/,可见springclouddeepprovider的注册信息,如下图红框所示:

    image.png

    Wireshark抓包,分析注册、续约、下载服务列表等请求响应

    • 此时再去看Wireshark的内容窗口,发现已有很多数据包,如下图:

    image.png

    • 接下来依次分析获取服务列表、注册、续约等请求响应;

    获取服务列表的请求响应

    • Eureka client启动后,最先向Eureka server发起的并不是注册请求,而是获取服务列表,先从代码层面分析,下图是DiscoveryClient类的构造方法:

    image.png

    • 上图中,红框中的方法是获取服务列表操作,比蓝框中的注册服务代码先执行,接下来看抓包的结果是否与代码一致;

    • 下图就是Wireshark抓到的springclouddeepeureka和springclouddeepprovider之间的请求和响应:

    image.png

    • 从上图我们能看出以下几个信息:
    • 第一:461号数据包就是获取服务列表的请求,472号是注册到Eureka server的请求,目前看来的确是获取服务列表在前,注册在后;
    • 第二:467号数据包是Eureka server返回的服务列表,此时由于还没有应用注册,因此获取服务列表返回的数据中,服务列表为空、一致性哈希码也为空(更多关于一致性哈希码的信息请参考《Spring Cloud源码分析之Eureka篇第五章:更新服务列表》);

    • 在《Spring Cloud源码分析之Eureka篇第五章:更新服务列表》一文中已看过更新服务列表的源码,分为全量更新和增量更新两部分,调用的都是AbstractJerseyEurekaHttpClient类的getApplicationsInternal方法,只是urlPath参数不同而已:

      private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath, String[] regions) { ClientResponse response = null; String regionsParamValue = null; try { WebResource webResource = jerseyClient.resource(serviceUrl).path(urlPath); if (regions != null && regions.length > 0) { regionsParamValue = StringUtil.join(regions); webResource = webResource.queryParam("regions", regionsParamValue); } Builder requestBuilder = webResource.getRequestBuilder(); addExtraHeaders(requestBuilder); response = requestBuilder.accept(MediaType.APPLICATION_JSON_TYPE).get(ClientResponse.class); Applications applications = null; if (response.getStatus() == Status.OK.getStatusCode() && response.hasEntity()) { applications = response.getEntity(Applications.class); } return anEurekaHttpResponse(response.getStatus(), Applications.class) .headers(headersOf(response)) .entity(applications) .build(); } finally { if (logger.isDebugEnabled()) { logger.debug("Jersey HTTP GET {}/{}?{}; statusCode={}", serviceUrl, urlPath, regionsParamValue == null ? "" : "regions=" + regionsParamValue, response == null ? "N/A" : response.getStatus() ); } if (response != null) { response.close(); } } }
    • springclouddeepprovider注册成功后,增量更新的服务列表中就能取得自身的信息了,如下图:

    image.png

    • 上图中的1036就是增量更新的请求,红框中是path,1039是Eureka server的响应,有两处需要注意:
    • 第一:蓝框中的actionType为ADDED,这样springclouddeepprovider就会将当前记录添加到本地缓存中,对应的代码在DiscoveryClient类的updateDelta方法中,如下图,红框中就是对不同actionType的处理逻辑:

    image.png

    • 第二:绿框中是Eureka server计算出的一致性哈希码,Eureka client更新了服务列表的本地缓存后,也会计算出一致性哈希码,然后与Eureka server返回的进行对比,正常情况下应该是一致的,如果Eureka client的增量更新出了问题,就会导致双方的一致性哈希码不同,这时Eureka client就会发起一次全量更新,对应的代码在DiscoveryClient类的getAndUpdateDelta方法中,如下图所示,红框中就是比较逻辑,而蓝框中的注释是很重要的提醒--reconcileAndLogDifference方法中有远程请求:

    image.png

    服务注册的请求响应

    • 在《Spring Cloud源码分析之Eureka篇第六章:服务注册》一文中已看过服务注册的源码,是AbstractJerseyEurekaHttpClient类的register方法,源码如下,可见是个POST请求,请求参数是个InstanceInfo类型的对象:
    @Override public EurekaHttpResponse<Void> register(InstanceInfo info) { String urlPath = "apps/" + info.getAppName(); ClientResponse response = null; try { Builder resourceBuilder = jerseyClient.resource(serviceUrl).path(urlPath).getRequestBuilder(); addExtraHeaders(resourceBuilder); response = resourceBuilder .header("Accept-Encoding", "gzip") .type(MediaType.APPLICATION_JSON_TYPE) .accept(MediaType.APPLICATION_JSON) .post(ClientResponse.class, info);//info就是POST到服务端的数据 return anEurekaHttpResponse(response.getStatus()).headers(headersOf(response)).build(); } finally { if (logger.isDebugEnabled()) { logger.debug("Jersey HTTP POST {}/{} with instance {}; statusCode={}", serviceUrl, urlPath, info.getId(), response == null ? "N/A" : response.getStatus()); } if (response != null) { response.close(); } } }
    • 以上请求在Wireshark上可以观察到,如下图:

    image.png

    • 对于注册请求,Eureka server的响应如下所示:

    image.png

    • 上图红框可见Status Code为204,在w3网站对204的解释如下,强调了无body返回:

    image.png

    续约的请求响应

    • 在《Spring Cloud源码分析之Eureka篇第七章:续约》一文中已看过续约的源码,是AbstractJerseyEurekaHttpClient类的sendHeartBeat方法,源码如下,可见是个PUT请求: @Override public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id, InstanceInfo info, InstanceStatus overriddenStatus) { String urlPath = "apps/" + appName + '/' + id; ClientResponse response = null; try { WebResource webResource = jerseyClient.resource(serviceUrl) .path(urlPath) .queryParam("status", info.getStatus().toString()) .queryParam("lastDirtyTimestamp", info.getLastDirtyTimestamp().toString()); if (overriddenStatus != null) { webResource = webResource.queryParam("overriddenstatus", overriddenStatus.name()); } Builder requestBuilder = webResource.getRequestBuilder(); addExtraHeaders(requestBuilder); response = requestBuilder.put(ClientResponse.class); EurekaHttpResponseBuilder<InstanceInfo> eurekaResponseBuilder = anEurekaHttpResponse(response.getStatus(), InstanceInfo.class).headers(headersOf(response)); if (response.hasEntity()) { eurekaResponseBuilder.entity(response.getEntity(InstanceInfo.class)); } return eurekaResponseBuilder.build(); } finally { if (logger.isDebugEnabled()) { logger.debug("Jersey HTTP PUT {}/{}; statusCode={}", serviceUrl, urlPath, response == null ? "N/A" : response.getStatus()); } if (response != null) { response.close(); } } }
    • 以上请求在Wireshark上可以观察到,如下图,注意绿框中的内容:

    image.png

    • Eureka server的响应如下图,返回码200,无内容:

    image.png

    启动springclouddeepconsumer

    • 登录springclouddeepconsumer应用所在机器,在springclouddeepconsumer-0.0.1-SNAPSHOT.jar文件所在目录执行如下命令,启动应用:
    java -Xms256m -Xmx256m -jar springclouddeepconsumer-0.0.1-SNAPSHOT.jar

    Wireshark抓包,分析服务列表的变化

    • 现在springclouddeepprovider和springclouddeepconsumer这两个应用都已启动,并且注册到Eureka server,此时再去看Wireshark抓的增量更新接口的响应包,应该会有springclouddeepconsumer这个应用的信息,如下图:

    image.png

    停止应用springclouddeepconsumer

    • 在启动springclouddeepconsumer的控制台上,Ctrl+c键同时按下,结束springclouddeepconsumer应用;

    Wireshark抓包,分析服务列表的变化

    • springclouddeepconsumer应用停止后,该变化在springclouddeepprovider的增量更新数据中应该能体现出来,去Wireshar上抓包,果然发现了对应的变更信息,如下图:

    image.png

    • 如上图所示,本次增量更新收到了一条类型为DELETED的记录,于是Eureka client就会在本地缓存中寻找此服务信息,如果找到就删除掉;

    • 至此,本次Wireshar抓包分析实战就完成了,在学习Eureka源码时,我们可以通过这种方式来验证和分析代码,对学习起到了很好的辅助作用;

    欢迎关注51CTO博客:程序员欣宸

    学习路上,你不孤单,欣宸原创一路相伴...

    【本文转自:韩国服务器 https://www.68idc.cn 复制请保留原URL】
    网友评论
    <