Spring Cloud Eureka—服务治理

搭建服务注册中心

在eureka-server工程中:

  1. 添加依赖:
    compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-server')
  2. 启动类上添加@EnableEurekaServer注解,声明这是一个Eureka Server。
  3. 编写配置文件application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    server:
    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交互的地址,查询服务和注册服务都需要依赖这个地址。
  4. 测试
    启动eureka-server项目,访问:http://localhost:8761/ ,如下图,则正常。

    此时还没有任何微服务实例被注册到Eureka Server上,所以Instances currently registered with Eureka
    拦是空的。

    注册服务提供者

    在tw_mall_orderserver工程中:

  5. 添加依赖:
    compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client')
  6. 在配置文件application.yml中添加配置

    1
    2
    3
    4
    5
    6
    7
    spring:      
    application:
    name: hello-service # 指定注册到Eureka Server上的应用名称
    eureka:
    client:
    serviceUrl:
    defaultZone: http://localhost:8761/eureka/
  7. 修改启动类
    在启动类上添加@EnableEurekaClient注解,表明是Eureka的Client

  8. 测试
    先启动eureka-server服务,再启动tw_mall_orderserver服务,访问:http://localhost:8761/ ,如下图,
    则正常。 此时已经有一个微服务实例被注册到Eureka Server上,可以看到Instances currently registered with
    Eureka拦有一条信息了,正式发现的名为order-server的服务。

    高可用注册中心集群

    在Eureka的服务治理设计中,所有节点即是服务提供方,也是消费方,包括服务注册中心。
    在服务注册中心,我们设置过下面这两个参数,让服务注册中心不注册自己:
    1
    2
    3
    4
    5
    6
    eureka:
    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
    5
    spring:
    application:
    name: eureka-server
    profiles:
    active: peer1
  • 创建application-peer1.yml,作为peer1服务中心的配置,并将serviceUrl指向peer2

    1
    2
    3
    4
    5
    6
    7
    8
    server:
    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
    8
    server:
    port: 8762
    eureka:
    instance:
    hostname: peer2
    client:
    serviceUrl:
    defaultZone: http://peer1:8761/eureka
  • 在/etc/hosts文件中添加对peer1和peer2的转换,让上面配置的host形式的serviceUrl能在本地正确访问到

    1
    2
    127.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
    4
    eureka:
    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
    2
    compile('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
    9
    spring:
    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”。