Eureka源码分析-环境构建篇

Posted 云水之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Eureka源码分析-环境构建篇相关的知识,希望对你有一定的参考价值。

 

     承接上一篇文章《什么是微服务》,我们已经对微服务有一定了解,并且以一个实现了注册中心、服务提供者及消费者的例子作为文章的结尾,而本篇文章,主要介绍Eureka源代码的环境构建及示例调试。 

 

  1. 环境构建
  2. 调试方式
  3. 运行原理
  4. 示例调试

 

 

 

一、环境构建

学习一门新技术的原理和根本,最好的方式就是研究它的源代码,搞懂它是如何诞生的,同时,也考虑下为什么这样去设计?我们要相信,从每段代码中,都能看出设计者当时的设计思路,通过源代码,就能与设计者进行心灵上的沟通。

 

 

1、相关说明

据作者了解,刚接触并选用Spring Cloud作为实现微服务架构技术栈的同学,经常认为是Spring Cloud提供了本章的主角-Eureka注册中心,其实不然。Eureka的开发维护公司是大名顶顶的Netflix,并且这家公司也提供了不少优秀的开源产品,比如:Eureka、Zuul、Ribbon、Hystrix、Sidecar等,而Spring Cloud则是我们强大的开源社区在维护开发,并且它的诞生是建立在不断集成及定制那些优秀的开源产品,比如:Netflix上面的那些开源产品,目前都已集成和发布使用,Spring Cloud构建在Spring boot之上,欲建立一套标准体系的微服务整体解决方案,这可是不少程序员的福音,也是很多中小企业的福音。说到这里,估计很多同学有些按耐不住了,别急,后续我会逐一介绍微服务架构体系的各种实现技术的原理及特点。

 

 

2、环境构建

第一步,我们先分析下Netflix的Eureka的源代码,地址如下:

https://github.com/Netflix/eureka.git,同时,我们可以使用eclipse或Idea等提供的版本工具,如:Git/Svn等下载源代码,这个地址下载得到的是主分支代码,也是稳定和较新的代码,当然,这里我使用Git命令下载也可以(需要点时间:笔者环境下载时大概10分钟),命令如下:

$git clone https://github.com/Netflix/eureka.git

 

第二步,源代码拿到后,我们可以使用IDE工具将其打开,比如:我使用Idea导入源代码,选择以Gradle方式导入编译(因为Eureka官方源码采用Gradle来管理)。另外,首次导入打开时,选择采用本地还是源码中提供的gradle昵?我建议使用源代码中的gradle版本,因为就作者写文时,最新的gradle版本已经4.10,而源码中默认提供的是2.10,两者版本相差较大,如果使用较新的版本,可能出现各种编译错误,所以建议采用源代码提供的gradle编译打包。接下来就是等待了,如果你已经安装了合适版本的gradle,那您只需等待gradle下载Eureka框架的依赖包,这个时间比较长,大家耐心等待,建议听首魔性的歌曲休息下哈。

 

第三步,相关依赖包下载完成后,我们试着启动调试下Eureka。这里我们先以生成war方式来调试,具体如下:

 

A、采用源代码自动gradlew工具编译打包或IDE环境gradle打包也可。 

$./gradlew  clean build

 

B、将编译得到的war,放入你的Web容器(改名为eureka.war),如:Tomcat

路径: eureka/eureka-server/build/libs

包名: eureka-server-1.9.6-SNAPSHOT.war

 

如下图所示:

 

 

C、当我们启动Tomcat后,需要等待许久,就笔者已足足等待20分钟,并且,运行解析过程中,可能会报如下错误(这些错不影响运行war后,访问控制台页面):

 

错误1:

TransportException: Cannot execute request on any known server

 

错误2:

java.net.ConnectException: Connection refused

 

 

D、将eureka-resources加入到build.gradle一起打包

经过上面的步骤,发现放入Tomcat的war不显示页面,因为打包编译时,并未把对应的jsp及css等文件一起打包,所以,我们需要将eureka-resources一起打包进去(若正常显示,可忽略),具体如下:

 

$cd  eureka-server

$vim  build.gradle

 

加入依赖编译eureka-resources包,截图如下:

 

E、经过上面所有的处理后,激动的一刻到了,期待已久的注册中心服务端控制台页面出现了,具体如下(比较简陋哦):

 

看到上面的页面结果,就说明eureka-server的war部署成功了。

 

 

二、调试方式

实际上,就Eureka源码仅提供了两种调试方式:一种是通过编译生成的war方式,另一种方式,则是模拟Mock的方式,而下面介绍的第三种方式,其实是通过修改war包方式得来的,好处是不需要每次修改后都需build的时间耗费,只需直接运行程序即可。

 

 

1、模拟Mock方式

这里介绍的是模拟方式,也就是采用与Eureka-Server实现逻辑相同的

MockRemoteEurekaServer作为服务端,来模拟的测试功能。因为是模拟,所以速度比较快,但又因为是模拟,某些功能不建议依赖这种方式来测试,而建议采用下面的方式。那么,先介绍下这种方式,它的优点很明显,速度快,缺点是模拟的Mock更新较慢时,某些功能无法测试。但随着Eureka2.x不再开发维护的消息到来,这种方式也是靠谱的。经过分析,所有测试单元,如果其父类为AbstractTester,那么,它使用的就是这种模拟Mock测试方式,具体是在运行setUp时,创建了MockRomoteEurekaServer,并初始化了Eureka相关的配置环境,

如eureka-core-resources中下面的测试单元都有采用Mock:

 

 

比如,我们选择ApplicationResoucesTest来运行测试,因为采用了Junit单元测试,所以,我们可以双击要测试的@Test,单独测试之即可,这里我测试下其中的testFullAppsGetJson获取所有注册的服务json信息,控制台运行结果可视性不好,笔者截取下来,格式化了下,具体如下:

 

 

那么,其它功能测试流程相同,各位同学自行试试吧!

 

 

2、编译war方式

这种方式,其实就是每次修改调试时,必须重新build一次,生成新的eureka-server-x.x.x-SNAPSHOT.war包,然后,在startServer时,在程序中指定该war的位置,以便读取里面的配置信息,并最终将Server启动,具体以下面截图中测试单元为例:

 

 

编译生成war后,我们选择上图中任意测试单元测试,比如:选择测试

@Test
public void testRegistration() throws Exception
    InstanceInfo instanceInfo = 
instanceInfoIt.next();
    
EurekaHttpResponse<Void> httpResponse = jerseyEurekaClient.register(instanceInfo);

    
System.out.println("status-code:" + httpResponse.getStatusCode());
    
assertThat(httpResponse.getStatusCode()is(equalTo(204)));

 

为了更清晰验证,笔者临时添加了System.out来打印结果,如果返回的结果码为204,就说明注册服务测试成功,结果如下:

 

 

3、直接启动方式

通过war包的调试方式比较费时间,且不灵活,接下来介绍的这种方式,是通过修改Eureka-Server默认的war调试方式,具体如下所示:

 

 

图中被注释掉部分,为源码提供的war包方式,高亮框起的部分,则为笔者修改后的调试方式,起意就是换种方式将一个web程序所需的resources配置文件及核心的web.xml通过api方式注入到WebAppContext上下文中,这样其它服务就可以通过HTTP访问了。经过测试,此种测试方式的结果与通过war包方式结果相同,但更节省时间,所以推荐使用它。那么,该如何使用昵?笔者会在本文第四部分的演示中,就使用这种方式来测试Eureka的运行过程,请继续往下俯瞰。

 

 

三、运行原理

在介绍这个例子之前,我们有必要简单地了解下Eureka的运行过程,并且官方已提供一个不错的运行架构图,具体结构如下:

 

Ps:

官方地址位置:https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance 

 

至于上图的运行原理,本篇仅简单介绍下运行过程,在后续文章中,会陆续深入的介绍各个环节的核心内容,之所以在这里谈到,只因为可以让大家从整体角度认识Eureka注册中心,也是为第四部分做铺垫 。从运行架构图了解到,基本包含了4个核心角色,具体如下所示:

 

1、Eureka Server

Eureka注册中心,负责服务的注册与服务发现等功能,其是整个Eureka体系的核心中转站,与下面提到的几个角色都有交集,所以,它的负担一般会比较大,生产环境下HA是必须的。

 

2、Application Service

该角色具体负责将各个服务注册到Eureka Server,并提供服务续约及注销等工作,可归属为Eureka Client的一员。

 

3、Application Client

该角色具体负责从Eureka Server中查找需要的服务信息,再请求具体的服务信息,也可归属为Eureka Client的一员。

 

4、Eureka Client

Eureka的客户端,其分为2和3两种角色,从架构图中可看出。

 

 

 

四、示例调试

在了解了第三部分内容后,再介绍本测试效果会更好,具体可分为注册中心服务端(Eureka Server)和第三部分所提到Application Service、Application Client及Eureka Client几个角色,具体如下操作:

 

1、Eureka Server(对应eureka-server项目的test部分)

 

第一步:在setUp后,添加Thread.sleep(Long.MAX_VALUE),其意是让Eureka-Server存活更长时间,这样才能方便测试,具体如下:

 

 

 

第二步:修改eureka-server.properties配置文件

根据官方建议,在调试测试(仅限测试环境)时,取消下面的注释:

eureka.waitTimeInMsWhenSyncEmpty=0

eureka.numberRegistrySyncRetries=0

 

Ps:

关闭掉Eureka Server的Replication的检测,以免下面测试服务注册时,频繁检测的工作。

 

第三步:选择第一步测试类中任意@Test运行,此时你会发现它被阻塞,并继续存活,这为测试其它功能提供了时间。这里,我们仍以testRegistration为例运行Server。

 

 

2、SampleEurekaService(Application Service,对应项目eureka-examples)

 

因为eureka-examples中的conf配置,只有在编译时才会读取conf下的配置文件:

sample-eureka-client.properties和sample-eureka-service.properties

 

首先,这里笔者直接将1中的injectEurekaConfiguration复制过来,并做了简单修改,具体如下(关注注释部分):

/**
 * This will be read by server internal discovery client. We need to salience it.
 */

private static void injectEurekaConfiguration() throws UnknownHostException
    String myHostName = InetAddress.getLocalHost().getHostName()
;
    
String myServiceUrl = "http://" + myHostName + ":8080/v2/";

    
System.setProperty("eureka.region""default");     // 区域必须与注册中心相同
    System.setProperty("eureka.name""sample-servide");    // 服务名修改
    System.setProperty("eureka.vipAddress""sample-service.mydomain.net");    // 虚拟VIP地址,供Application Client查找
    System.setProperty("eureka.port""8001");      // 独立端口号,如果已被占用,请换之
    System.setProperty("eureka.preferSameZone""false");       // 禁用Same Zone
    
System.setProperty("eureka.shouldUseDns""false");     // 禁用DNS
    
System.setProperty("eureka.shouldFetchRegistry""true");   // 需要注意,必须设置为true,否则无法注册
    System.setProperty("eureka.serviceUrl.defaultZone"myServiceUrl);     // 注册地址,必须与注册中心相同
    System.setProperty("eureka.serviceUrl.default.defaultZone"myServiceUrl);     // 注册地址,必须与注册中心相同

 

 

然后,我们在启动ExampleEurekaService中的main方法前,在其首行添加injectEurekaConfiguration的调用,直接启动即。此时,我们在控制台看到如下信息时,代表服务与Server通信及注册成功了,并且该服务在不断的检测是否有Client发来请求,只要检测到了一个成功请求,那么它的工作也就结束,并被停止,如下:

 

 

3、SampleEurekaClient(Application Client,对应项目eureka-examples)

 

首先,injectEurekaConfiguration复制过来,并做了简单修改,具体如下(关注注释部分):

/**
 * This will be read by server internal discovery client. We need to salience it.
 */

private static void injectEurekaConfiguration() throws UnknownHostException
    String myHostName = InetAddress.getLocalHost().getHostName()
;
    
String myServiceUrl = "http://" + myHostName + ":8080/v2/";

    
System.setProperty("eureka.region""default");     // 区域与注册中心保持一致
    System.setProperty("eureka.vipAddress""sample-service.mydomain.net");    // vip地址必须与服务定义相同,否则找不到服务
    System.setProperty("eureka.shouldFetchRegistry""true");           // 需要注意,必须设置为true,否则无法注册
    System.setProperty("eureka.serviceUrl.defaultZone"myServiceUrl);     // 注册地址,必须与注册中心相同
    System.setProperty("eureka.serviceUrl.default.defaultZone"myServiceUrl);     // 注册地址,必须与注册中心相同

 

然后,我们在启动ExampleEurekaClient中的main方法前,在其首行添加injectEurekaConfiguration的调用,运行结果如下:

 

我们也看到,在ExampleEurekaClient结束之后,ExampleEurekaService也结束了运行,正好验证了ExampleEurekaService只服务一次哦。

 

 

好了,本篇文章就介绍到这里,后面会继续介绍Eureka的源码分析相关的文章,敬请期待!由于原创文章梳理费时费力,觉得还不错的读者朋友,可以关注下面的个人公众号,以便及时查阅新的文章,谢谢。

 

以上是关于Eureka源码分析-环境构建篇的主要内容,如果未能解决你的问题,请参考以下文章

鸿蒙内核源码分析(构建工具篇) | 顺瓜摸藤调试鸿蒙构建过程 | 百篇博客分析HarmonyOS源码 | v59.01

Eureka 系列(02)客户端源码分析

精尽 Netty 原理与源码专栏( 已经完成 61+ 篇,预计总共 70+ 篇 )

精尽 Dubbo 原理与源码专栏( 已经完成 69+ 篇,预计总共 75+ 篇 )

鸿蒙内核源码分析(GN应用篇) | GN语法及在鸿蒙的使用 | 百篇博客分析HarmonyOS源码 | v60.01

微服务发现与注册之Eureka源码分析