搭建服务注册中心
在eureka-server工程中:
- 添加依赖:
compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-server')
- 启动类上添加@EnableEurekaServer注解,声明这是一个Eureka Server。
编写配置文件application.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16server:
port: 8761
spring:
application:
name: register-server
eureka:
instance:
hostname: localhost
client:
registerWithEureka: false # 是否将自己注册到Eureka Server,默认为true。由于当前应用就是
Eureka Server,故而设为false
fetchRegistry: false # 表示是否从Eureka Sever获取注册信息,默认为true。因为这是一个单节点的
Eureka Server,不需要同步其他的Eureka Server节点的数据,故而设为false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 设置与
Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。测试
启动eureka-server项目,访问:http://localhost:8761/ ,如下图,则正常。此时还没有任何微服务实例被注册到Eureka Server上,所以Instances currently registered with Eureka
拦是空的。注册服务提供者
在tw_mall_orderserver工程中:
- 添加依赖:
compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')
在配置文件application.yml中添加配置
1
2
3
4
5
6
7spring:
application:
name: hello-service # 指定注册到Eureka Server上的应用名称
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/修改启动类
在启动类上添加@EnableEurekaClient注解,表明是Eureka的Client- 测试
先启动eureka-server服务,再启动tw_mall_orderserver服务,访问:http://localhost:8761/ ,如下图,
则正常。 此时已经有一个微服务实例被注册到Eureka Server上,可以看到Instances currently registered with
Eureka拦有一条信息了,正式发现的名为order-server的服务。高可用注册中心集群
在Eureka的服务治理设计中,所有节点即是服务提供方,也是消费方,包括服务注册中心。
在服务注册中心,我们设置过下面这两个参数,让服务注册中心不注册自己:1
2
3
4
5
6eureka:
client:
registerWithEureka: false # 是否将自己注册到Eureka Server,默认为true。由于当前应用就是
Eureka Server,故而设为false
fetchRegistry: false # 表示是否从Eureka Sever获取注册信息,默认为true。因为这是一个单节点的
Eureka Server,不需要同步其他的Eureka Server节点的数据,故而设为false
Eureka Server的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,形成一组相互注册的服务注册中
心,以实现服务清单的相互同步,达到高可用效果。
以下是在同一个项目中启动两个服务,占用不同的端口,来模拟Eureka服务集群。
application.yml配置
1
2
3
4
5spring:
application:
name: eureka-server
profiles:
active: peer1创建application-peer1.yml,作为peer1服务中心的配置,并将serviceUrl指向peer2
1
2
3
4
5
6
7
8server:
port: 8761
eureka:
instance:
hostname: peer1
client:
serviceUrl:
defaultZone: http://peer2:8762/eureka创建application-peer2.yml,作为peer2服务中心的配置,并将serviceUrl指向peer1
1
2
3
4
5
6
7
8server:
port: 8762
eureka:
instance:
hostname: peer2
client:
serviceUrl:
defaultZone: http://peer1:8761/eureka在/etc/hosts文件中添加对peer1和peer2的转换,让上面配置的host形式的serviceUrl能在本地正确访问到
1
2127.0.0.1 peer1
127.0.0.1 peer2启动类上添加@EnableEurekaClient注解
下面分别用peer1和peer2两个配置启动两个server服务- 在idea右上角run,选择edit configrations
- 然后把两个启动项都run起来,分别访问各自的断口。结果如图:
服务提供者注册到集群
在上面的tw_mall_orderserver服务中修改application.yml,将注册中心指向前面搭建的peer1和peer2。1
2
3
4eureka:
client:
serviceUrl:
defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/启动该服务,分别访问http://localhost:8761/和http://localhost:8762/,可以观察到hello-service服
务同时被注册到peer1和peer2中。- 若此时断开peer1,由于hello-service同时也向peer2注册,因此在peer2上其他服务依然能访问到
hello-service,从而实现了高可用的服务注册中心。深入理解
Eureka Server的同步遵循的原则:只要有一条边将节点连接,就可以进行信息传播与同步。
实验场景
假设有3个注册中心peer1、peer2和peer3,它们各自都将serviceUrl指向另外两个节点。换言之,peer1、
peer2、peer3是两两互相注册的。启动三个服务注册中心,并将compute-service的serviceUrl指向peer1并启
动,可以获得如下图所示的集群效果。 访问http://localhost:8762/,可以看到3个注册中心组成了集群,compute-service服务通过peer1同步给了与
之互相注册的peer2和peer3。 通过上面的实验,可以得出下面的结论: - 两两注册的方式可以实现集群中节点完全对等的效果,实现最高可用性集群,任何一台注册中心故障都不会影响服务的注册与发现
服务发现与消费
前面已经有了服务注册中心和服务提供者,现在构建服务消费者ribbon-consumer。服务消费者主要有两个目标:服务
发现和服务消费。服务发现由Eureka客户端完成,服务消费由Ribbon完成。
Ribbon是一个基于HTTP和TCP的客户端负载均衡器,它可以在通过客户端中配置的ribbonServiceList服务端列表去
轮询访问以达到均衡负载的作用。Ribbon和Eureka联合使用时,可以从Eureka注册中心中获取服务端列表。
在前面的基础上,创建ribbon-consumer服务。
添加依赖
1
2compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')
compile('org.springframework.cloud:spring-cloud-starter-netflix-ribbon')在主类中添加@EnableDiscoveryClient注解或者@EnableEurekaClient注解,并创建RestTemplate的Spring Bean实例,并通过@LoadBalanced注解开启客户端负载均衡。
1
2
3
4
5
6
7
8
9
10
11
12
13@SpringBootApplication
@EnableEurekaClient
public class RibbonConsumerApplication {
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RibbonConsumerApplication.class, args);
}
}创建ConsumerController类并实现/ribbon-consumer接口。这里地址访问的是服务名,而不是一个具体的地址。符合服务治理框架特性。
1
2
3
4
5
6
7
8
9
10@RestController
public class ConsumerController {
@Autowired
RestTemplate restTemplate;
@RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET)
public String helloConsumer() {
return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class).getBody();
}
}application.yml配置文件
1
2
3
4
5
6
7
8
9spring:
application:
name: ribbon-consumer
server:
port: 9000
eureka:
client:
serviceUrl:
defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/
启动服务并向http://localhost:9000/ribbon-consumer发起GET请求,成功返回“Hello World”。