Spring Cloud实战
上QQ阅读APP看书,第一时间看更新

3.3 实现高可用的Eureka集群

在上文里,我们演示了Eureka客户端调用服务的整个流程,这里我们将在架构上有所改进。大家可以想象一下,在上文的案例中,Eureka注册中心只部署在一台机器上,这样一旦它出现问题,就会导致整个服务调用系统的崩溃,如果这种情况发生在生产环境上,后果是不堪设想的。

大家别以为这是危言耸听,在高并发的场景下(比如双十一的并发环境),这种情况发生的可能性不低。针对这种场景,这里我们将部署两台Eureka注册中心,彼此相互注册,以此搭建一个可用性比较高的Eureka集群。

3.3.1 集群的示意图

在这个集群里,我们将配置2台相互注册的Eureka服务器,这样一来,每台服务器都包含着对方的服务注册信息,相当于双机热备,同时服务提供者只需向其中的一个注册服务,如图3.6所示。

图3.6 高可用Eureka集群示意图

这样,如果服务器A或B宕机,那么另一台服务器依然可以向外部提供服务列表,服务调用者依然可以据此调用服务。

在并发要求更高的环境里,我们甚至可以搭建2台以上的服务器,不过事实上,双机热备的集群能满足大多数的场景:一方面,不是每个系统的并发量都很高,所以双机热备足以满足大多数的并发需求;另一方面,毕竟两台服务器同时宕机的可能性也不大。

3.3.2 编写相互注册的服务器端代码

这里为了演示方便,我们在一台机器上模拟双服务器的场景,在真实项目里,我们一般是把两个相互注册的服务器安装在两台主机上,因为如果只安装在一台上,那么该服务器发生故障,两个服务器都会失效。具体的实现步骤如下。

步骤01 到C:\WINDOWS\system32\drivers\etc目录里,找到hosts文件,在其中加入两个机器名(其实都是指向本机),代码如下。修改后,需要重启机器。

步骤02 创建ek-cluster-server项目,其实是根据3.2.1小节里的EurekaBasicDemo-Server项目改写而来。和之前的项目相比,我们只改动了application.yml文件,代码如下:

这里的端口号没变,依然是8888,但我们在第5行把项目名修改成了ekServer1;在第8行里,把提供服务的主机名也修改成ekServer1;在第11行里,我们指定了本服务所在的url,这里请注意,我们把ekServer1所在的serverUrl指定到ekServer2的8889端口上,也就是说,这里我们指定ekServer1向ekServer2注册。

步骤03 在真实项目里,我们一般会在两台主机上启动两个Eureka服务,所以这里我们再创建一个Maven类型的项目ek-cluster-server-backup,和之前的ek-cluster-server相比,它们的差别还是在于application.yml,代码如下:

这里的配置信息其实和刚才的是对偶的,这里的application名和主机名都叫ekServer2,不过请注意第11行,这里的serviceUrl是注册到ekServer1的8888端口上,这里我们同样指定ekServer2向ekServer1注册。结合上文,至此我们实现了双服务器之间的相互注册。

3.3.3 服务提供者只需向其中一台服务器注册

虽然在集群里搭建了两台服务器,但是服务提供者只需向其中的一台注册即可,否则高可用的便利性就会以牺牲代码可维护性为代价了。

这里我们是在ek-cluster-ServiceProvider项目编写服务提供程序,它是根据上文3.2.2小节里的项目EurekaBasicDemo-ServerProvider改写而来的,其中只修改了application.yml部分的代码。

我们只改动了第9行的代码,这说明本服务是向ekServer1的8888号端口注册。

由于这里两个Eureka服务器是相互注册的,因此本服务提供者无须同时向两个服务器注册,一旦向ekServer1注册后,该服务器就会自动把服务提供者的信息复制到ekServer2上。

3.3.4 修改服务调用者的代码

我们把服务调用者的代码放入ek-cluster-ServiceCaller这个Maven项目里,这是根据之前3.2.3小节里的EurekaBasicDemo-ServerCaller项目改写而来的。其中,我们也只修改application.yml代码。

改动点还是在第9行上,这里是向ekServer1服务器的8888号端口注册。同理,这里也无须向另外一个机器(ekServer2)注册。

3.3.5 正常场景下的运行效果

按如下次序启动4个项目的Spring Boot服务。


第一,ek-cluster-server(第一个Eureka服务器)。

第二,ek-cluster-server-backup(第二个Eureka服务器)。

第三,ek-cluster-ServiceProvider(服务提供者)。

第四,ek-cluster-ServiceCaller(服务调用者)。


随后,大家能在http://ekserver1:8888/http://ekserver2:8889/两个浏览器上看到如图3.7所示的4个可用服务。由于是相互注册,因此它们的内容是一样的。

图3.7 集群运行后的效果图

虽然这里我们也可以通过http://localhost:8888/http://localhost:8889/看到相同的效果,但是不推荐。这是因为,在真实的项目里,Eureka的服务器应该是和开发机器分开的,也就是说它们应该被部署在其他机器上,只不过这里我们为了演示方便,把它们都放在了本机中。

当我们确认服务启动后,可以在浏览器里输入“http://ekserver1:8080/hello”来查看服务调用的效果,这里其实触发了ek-cluster-ServiceCaller中Controller里的hello方法。

和之前一样,这里的输出还是“In Caller, hello Eureka”,这说明双机热备的Eureka架构至少不会影响基本的功能。同样,这里不建议通过http://localhost:8080/hello来查看运行效果。

3.3.6 一台服务器宕机后的运行效果

这里我们可以故意关闭ek-cluster-server服务,以此来模拟一台服务器宕机的情况。

关闭后,我们在浏览器里输入“http://ekserver1:8080/hello”,虽然我们在服务提供者和服务调用者的application.yml里指定的serviceUrl.defaultZone都是http://ekServer1:8888/eureka/,但是在一台Eureka服务器失效的情况下,我们依然能看到正确的结果,如图3.8所示。

图3.8 一台Eureka服务器宕机后的效果图

如果在刚才关闭的是ek-cluster-server-backup,让ek-cluster-server运行,这里我们还是能看到同样的效果。也就是说,在这个Eureka双服务器的集群里,一台服务器宕机后,整个服务体系依然可用,这就大大提升了系统的可用性。