Spring Cloud (4) Eureka – 进阶

在上一章中,我们学习了Eureka的原理以及基本使用。在本章,我们将探索Eureka的进阶知识。

  • 使用Ribbon负载均衡器
  • Eureka Server高可用集群搭建
  • Eureka自我保护机制

一、负载均衡

1、什么是负载均衡

负载均衡是指通过网关或在客户端本地根据一定算法选择服务进行调用,以减少单台服务器的压力,提高请求的并发度,提供更稳定的服务。

负载均衡分为软负载和硬负载(F5),即使用软件还是硬件进行负载均衡。我们接下来学习的都属于软负载。

Spring Cloud默认提供了Ribbon负载均衡器,支持本地客户端的负载均衡。

在此之前,你可能听说过使用Nginx反向代理服务器做负载均衡,但二者有一些区别。

Nginx负载均衡流程:

Nginx负载均衡使用反向代理技术,即Nginx反向代理服务器代替服务端接受请求,再将请求转发给其中一台服务器(按某种算法)。

通常Nginx作为网关来拦截请求,适用于服务器端负载均衡。

而Ribbon负载均衡适用于服务间负载均衡(rpc远程调用),更多细节我们将在之后的章节去详解。

2、Ribbon负载均衡器使用

Ribbon是Netflix提供的Spring Cloud中的负载均衡器,能和各种注册中心完美整合。Eureka依赖包中自动引入了Ribbon,使用负载均衡器十分容易!

在上一章中,我们配置RestTemplate的Bean时使用了@LoadBalanced注解,这就开启了Ribbon负载均衡。

@Bean
@LoadBalanced
RestTemplate getRestTemplate(RestTemplateBuilder builder) {
    return builder.build();
}

接下来我们可以使用该Bean去调用服务:

@Service
public class OrderService {

    @Resource
    private RestTemplate restTemplate;

    public String getOrder() {
        return restTemplate.getForObject("http://eureka-provider/member", String.class) + "order";
    }
}

此处我们必须指定服务的调用地址,但可以不使用域名+端口作为地址,而是使用服务提供者的spring application name。当我们有多个同名的服务提供者时,restTemplate对象将自动选择其中一个服务提供者的服务进行调用。

如果不用@LoadBalanced注解,调用服务时必须指定域名和端口,如localhost:8888。

为了测试负载均衡的效果,我们再新建一个服务提供者模块,创建方法不再赘述(见上一章),将上一章的服务提供者模块的controller、service包直接复制到和入口类同一目录即可。

开发:

修改MemberService的getMember方法的返回值:

MemberService.java

@Service
public class MemberSerivce {

    public String getMember() {
        return "member2";
    }
}

为入口类添加@EnableEurekaClient注解:

EurekaProvider2Application.java

@SpringBootApplication
@EnableEurekaClient
public class EurekaProvider2Application {

    public static void main(String[] args) {
        SpringApplication.run(EurekaProvider2Application.class, args);
    }
}

修改配置文件application.yml:

spring:
  application:
    name: eureka-provider # 应用名
server:
  port: 8183 # 端口
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8180/eureka # 指定Eureka Server地址

可直接copy之前的配置,修改server.port即可。

测试:

利用Run Dashboard一键启动所有项目:

浏览器访问几次order服务:

我们将看到member和member2的交替输出(采用轮询算法),证明负载均衡器生效,调用了不同模块提供的服务!

Ribbon本地负载均衡器不仅使用简单,其实现也并不复杂,在之后的章节中,我们会手写一个负载均衡器。

二、Eureka高可用集群搭建

Eureka的集群搭建非常简单,还记得之前在Eureka Server被我们设置为false的两条属性么?

fetch-registry: false # 是否开启搜索服务,Server不提供服务,故应关闭
register-with-eureka: false # 注册自己,Server不需注册自己,故应关闭

由于Eureka Server本身只是注册中心,并不需要提供服务,且不需要自己注册自己。

如果我们想让Eureka Server高可用,可以让两台或多台Eureka Server相互注册。

1、代码

新建一个Eureka Server项目,作为模块放在我们之前的父项目下。

现在的目录结构如下:

修改eureka-server的配置文件:

spring:
  application:
    name: eureka-server1 # 应用名
server:
  port: 8180 # 端口
eureka:
  instance:
    hostname: localhost # 域名
  client:
    service-url:
      defaultZone: http://localhost:8184/eureka # 其他注册中心的地址
#    fetch-registry: false # 是否开启搜索服务,Server不提供服务,故应关闭
#    register-with-eureka: false # 注册自己,Server不需注册自己,故应关闭

相对于之前的配置,我们修改了应用名,添加了eureka.client.service-url.defaultZone属性,并将值指定为其他注册中心的地址,即将自己注册到其他注册中心上。

修改eureka-server2的配置文件:

spring:
  application:
    name: eureka-server2
eureka:
  instance:
    hostname: localhost
  client:
    service-url:
      defaultZone: http://localhost:8180/eureka # 其他注册中心的地址
server:
  port: 8184

这样,两台注册中心相互注册,组成了集群。Eureka集群有如下特点:

  • 当其中一台注册中心挂掉后,将自动将其上已注册的服务注册到到其他正常运行的Eureka Server上。
  • 每隔一定时间,每个注册中心将从其他注册中心获取服务。

我们也可以在服务提供者的配置文件中指定多个注册中心的地址,即在一开始就在多个注册中心上注册该服务。

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8180/eureka,http://localhost:8184/eureka # 指定Eureka Server地址,多个注册中心用逗号隔开

2、测试

Run Dashboard一键启动所有项目:

启动项目后,分别查看两个注册中心上的已注册服务:

之后停掉其中一台注册中心,查看剩余正常运行的注册中心的服务,我们可以发现所有注册在停掉的注册中心上的服务都已经在正常运行的注册中心上注册了。

三、Eureka自我保护机制

通过前面的学习,我们知道,Eureka有Client(客户端)、Server(服务端)两种角色。

Eureka自我保护机制解决了什么问题?

Client即服务提供者/消费者,会定时向Server发送心跳包,若Server一定时间内
(默认90s) 未收到该心跳包,则剔除该Client提供的所有服务。

而若短时间内(30s)丢失了大量的服务实例的心跳包,Eureka Server会开启自我保护,而不会剔除该服务。能够有效防止服务误剔除(Client可能可用,但由于网络原因暂时无法与Server通讯)。

即开启自我保护机制,服务会在更长时间后剔除。

适用场景

通常一个项目会经历dev(本地环境)、sit(测试环境)、uat(验收环境)、pre(预发布)、prod(生产环境)。

那么显然,自我保护机制防止网络暂时不通导致的服务误剔除,适用于生产环境。

但是不适用于本地开发环境,因为开发时我们经常要重启项目进行调试,如果开启了自我保护,可能重启前的服务还处于缓存状态,即未被剔除(如有三个provider提供同一服务,结果其中一台provider关闭了,但其地址未被即时剔除,在负载均衡轮询调用provider服务时,将会报错)。

建议dev环境下,关闭Eureka自我保护。

配置

支持服务端和客户端两种配置方式。

Eureka Server配置:

spring:
  application:
    name: eureka-server2
eureka:
  instance:
    hostname: localhost
  client:
    service-url:
      defaultZone: http://localhost:8180/eureka # 其他注册中心的地址
  server:
    enable-self-preservation: false # 关闭自我保护
    eviction-interval-timer-in-ms: 10000 # 多久剔除服务
server:
  port: 8184

新增倒数第3、4行的两条配置即可。

Eureka Client配置:

spring:
  application:
    name: eureka-provider # 应用名
server:
  port: 8183 # 端口
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8180/eureka,http://localhost:8184/eureka # 指定Eureka Server地址
  instance:
    lease-renewal-interval-in-seconds: 30 # 发送心跳的间隔时间
    lease-expiration-duration-in-seconds: 30 # 超过多少秒剔除服务

新增最后两条配置即可。

发表评论

电子邮件地址不会被公开。