前言
在Spring Cloud微服务全家桶之服务注册、服务发现(Eureka、Consul作为服务注册中心)文中,使用的是单点eureka注册中心。在开发测试环境是可以的,但生产环境强烈不建议用单点eureka注册中心。
双eureka高可用

思路就是每个eureka server通过eureka.client.serviceUrl.defaultZone配置,将自己注册到对方的注册中心。
新建一个module项目,建的过程这里省略,名为registry-ha-ms,建完后pom.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
使用@EnableEurekaServer注解启用Eureka注册中心
1 |
|
建两个properties配置文件,分别为application-peer1.properties,application-peer2.properties
- application-peer1.properties
1 | server.port=1011 |
- application-peer2.properties
1 | server.port=1012 |
配置本地Hosts域名解析
1 | 127.0.0.1 eureka-peer1 |
在项目目录下使用maven clean package -DskipTests打包,进入target目录,开启两个命令行窗口分别执行
1 | java -jar registry-ha-ms-0.0.1-SNAPSHOT --spring.profiles.active=peer1 |
或者在idea里建两个执行配置


这样就开启了两个eureka server。
我们在上一篇文章的基础上,将provider-ms的application.properties修改下
1 | server.port=2103 |
然后再启动ProviderApplication,可以看到PROVIDER-MS 已经注册到eureka-peer1与eureka-peer2上了。且eureka-peer1的replicas节点列表里有eureka-peer2,eureka-peer2的replicas节点列表里有eureka-peer1


新建一个服务消费项目,名为consumer-ms建完后pom.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
修改properties资源文件
1 | server.port=2104 |
@EnableDiscoveryClient启用服务发现客户端
1 |
|
写一个Controller消费provider-ms提供的服务
1 |
|
这里引入了LoadBalancerClient,通过choose方法负载均衡选择一个“provider-ms”的服务实例,再通过restTemplate调用,服务实例的信息存储在ServiceInstance对象中,可以获取到主机名,端口号等信
启动ConsumerMsApplication,观察eureka-peer1,eureka-peer2,consumer-ms已经注册了

此时调用刚才写的consume接口,发现已经能够将注册中心的两个服务实例展示出来了,说明服务间调用成功了

三eureka高可用

虽然上面我们以双节点作为例子,但是实际上因负载等原因,我们往往可能需要在生产环境构建多于两个的Eureka Server节点。那么对于如何配置serviceUrl来让集群中的服务进行同步,需要我们更深入的理解节点间的同步机制来做出决策。Eureka Server的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。什么意思呢?不妨我们通过下面的实验来看看会发生什么。场景一:假设我们有3个注册中心,我们将eureka-peer1、eureka-peer2、eureka-peer3各自都将eureka.client.serviceUrl.defaultZone指向另外两个节点。换言之,peer1、peer2、peer3是两两互相注册的。启动三个服务注册中心,并将provider-ms的serviceUrl指向eureka-peer1并启动,可以获得如下图所示的集群效果。

我们在上述双eureka节点高可用的基础上,增加一个application-peer3.properties,并修改3个properties配置文件,内容如下:
1 | application-peer1.properties |
application-peer2.properties
1 | server.port=1012spring.application.name=registry-ha-ms |
application-peer3.properties
1 | server.port=1013spring.application.name=registry-ha-ms |
复制一个,改名RegistryHaApplication-peer3 ,其中Program arguments: –spring.profiles.active=peer3

配置本地Hosts域名解析
1 | 127.0.0.1 eureka-peer1127.0.0.1 eureka-peer2127.0.0.1 eureka-peer3 |
分别启动RegistryHaApplication-peer1,RegistryHaApplication-peer2,RegistryHaApplication-peer3

观察eureka-peer1,eureka-peer2,eureka-peer3,每个eureka都已经两两互相注册,且目前没有服务实例注册在注册中心(Instances currently registered with Eureka,No instance available)


试验下单边注册一个服务实例,即provider-ms的serviceUrl指向eureka-peer1修改provider-ms项目的application.properties配置,仅仅配置将provider-ms注册到eureka-peer1,然后启动ProviderApplication
server.port=2103spring.application.name=provider-ms#eureka.client.serviceUrl.defaultZone=http://registry-ms.pay-inner.com:1001/eurekaeureka.client.serviceUrl.defaultZone=http://eureka-peer1:1011/eureka
观察eureka-peer1,eureka-peer2,eureka-peer3发现provider-ms服务,已经通过eureka-peer1将服务实例信息同步给了eureka-peer2,eureka-peer3



进一步,我们再将consumer-ms进行eureka-peer2单边注册

观察eureka-peer1,eureka-peer2,eureka-peer3,此时eureka-peer2同步consumer-ms的服务实例信息到eureka-perr1,eureka-peer3


然后我们调用下consumer-ms的consume接口,没有问题

将eureka-peer1 shutdownprovider-ms开始报错,访问不到eureka-peer1

但这并不影响,consumer-ms调用provider-ms

将eureka-peer2 shutdownconsumer-ms开始报错,访问不到eureka-peer2

但丝毫不影响,consumer-ms调用provider-ms,做到了服务注册中心的高可用!(这里有点不严谨,因为即使把所有eureka节点都shutdown,还是可以调用的,服务消费方都会本地缓存服务提供方的地址的,但是如果eureka节点全部shutdown,那么新加入的服务实例就无法感知了)

不过,不建议每个服务配置单边注册到某个eureka节点,强烈建议,每个服务配置所有eureka节点即provider-ms,consumer-ms的application.properties中的eureka.client.serviceUrl.defaultZone配成所有eureka节点
1 | eureka.client.serviceUrl.defaultZone=http://eureka-peer1:1011/eureka,http://eureka-peer2:1012/eureka,http://eureka-peer3:1013/eureka |
这个配置的试验就不再赘述,可以自行尝试