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

版权声明:欢迎转载,请注明出处,谢谢。 https://blog.csdn.net/boling_cavalry/article/details/82918227

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

源码分析系列文章

以下是整理的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环境,本次实战用了三台电脑,部署情况如下图:
在这里插入图片描述

三台电脑的详细情况如下表所示:

应用名称 身份 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 此应用先不启动,
等抓包后再启动,以便观察变化

应用源码下载

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) [email protected]:zq2599/blog_demos.git 该项目源码的仓库地址,ssh协议

这个git项目中有多个文件夹,本章源码分别在springclouddeepeureka、springclouddeepprovider、springclouddeepconsumer这三个文件夹下,如下图红框所示:
在这里插入图片描述

实战步骤

  1. 修改应用的配置文件;
  2. 编译构建三个应用,得到三个jar包;
  3. 在三台电脑上分别部署应用;
  4. 启动springclouddeepeureka;
  5. 在springclouddeepprovider所在电脑上启动Wireshark,并配置好过滤规则;
  6. 启动springclouddeepprovider;
  7. Wireshark抓包,分析注册、续约、下载服务列表等请求响应;
  8. 启动springclouddeepconsumer;
  9. Wireshark抓包,分析服务列表的变化;
  10. 停止应用springclouddeepconsumer;
  11. Wireshark抓包,分析服务列表的变化;

关于机器的小建议

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

接下来开始实战吧;

修改应用的配置文件

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

编译构建三个应用

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

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

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

扫描二维码关注公众号,回复: 3428175 查看本文章

启动springclouddeepeureka

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

启动和配置Wireshark

  1. 应用springclouddeepprovider所在的电脑是Windows10操作系统,上面安装了Wireshark2.6.3,现在请运行它;

  2. 首先在网卡列表中确定自己用的是哪一个,我这里用的是无线网卡,因此双击下图红框位置:
    在这里插入图片描述

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

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

启动springclouddeepprovider

执行以下命令启动应用springclouddeepprovider

java -Xms256m -Xmx256m -jar springclouddeepprovider-0.0.1-SNAPSHOT.jar

启动后,在Eureka server的管理页面http://192.168.31.147:8081/,可见springclouddeepprovider的注册信息,如下图红框所示:
在这里插入图片描述

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

此时再去看Wireshark的内容窗口,发现已有很多数据包,如下图:
在这里插入图片描述

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

获取服务列表的请求响应

  1. Eureka client启动后,最先向Eureka server发起的并不是注册请求,而是获取服务列表,先从代码层面分析,下图是DiscoveryClient类的构造方法:
    在这里插入图片描述
    上图中,红框中的方法是获取服务列表操作,比蓝框中的注册服务代码先执行,接下来看抓包的结果是否与代码一致;

  2. 下图就是Wireshark抓到的springclouddeepeureka和springclouddeepprovider之间的请求和响应:
    在这里插入图片描述

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

  1. 《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();
            }
        }
    }
  1. springclouddeepprovider注册成功后,增量更新的服务列表中就能取得自身的信息了,如下图:
    在这里插入图片描述

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

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

服务注册的请求响应

  1. 《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();
            }
        }
    }
  1. 以上请求在Wireshark上可以观察到,如下图:
    在这里插入图片描述

  2. 对于注册请求,Eureka server的响应如下所示:
    在这里插入图片描述

上图红框可见Status Code为204,在w3网站对204的解释如下,强调了无body返回:
在这里插入图片描述

续约的请求响应

  1. 《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();
            }
        }
    }
  1. 以上请求在Wireshark上可以观察到,如下图,注意绿框中的内容:
    在这里插入图片描述

  2. Eureka server的响应如下图,返回码200,无内容:
    在这里插入图片描述

启动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这个应用的信息,如下图:
在这里插入图片描述

停止应用springclouddeepconsumer

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

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

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

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

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

猜你喜欢

转载自blog.csdn.net/boling_cavalry/article/details/82918227