Eureka源码分析-环境构建篇
Posted 云水之路
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Eureka源码分析-环境构建篇相关的知识,希望对你有一定的参考价值。
承接上一篇文章《什么是微服务》,我们已经对微服务有一定了解,并且以一个实现了注册中心、服务提供者及消费者的例子作为文章的结尾,而本篇文章,主要介绍Eureka源代码的环境构建及示例调试。
- 环境构建
- 调试方式
- 运行原理
- 示例调试
一、环境构建
学习一门新技术的原理和根本,最好的方式就是研究它的源代码,搞懂它是如何诞生的,同时,也考虑下为什么这样去设计?我们要相信,从每段代码中,都能看出设计者当时的设计思路,通过源代码,就能与设计者进行心灵上的沟通。
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
精尽 Netty 原理与源码专栏( 已经完成 61+ 篇,预计总共 70+ 篇 )
精尽 Dubbo 原理与源码专栏( 已经完成 69+ 篇,预计总共 75+ 篇 )