服务治理

什么是服务治理?

服务治理可以说是微服务架构中最为核心和基础的模块,它主要是对微服务的实例进行管理,有如下几个功能:

  1. 服务注册:在服务治理框架中,会构建一个注册中心,服务提供者会向注册中心登记自己提供的服务,将服务名、主机与端口号等信息告知注册中心,注册中心会按照服务名进行分类,整理出一个服务清单。服务注册中心还需要以心跳的方式去监测清单中的服务是否可用,若不可用则需要从服务清单中剔除,达到排除故障服务的效果。
  2. 服务发现:服务调用者需要向服务注册中心咨询服务,获取所有的服务实例清单,在清单中通过客户端负载均衡的方式选取一个服务实例进行调用。

服务治理之Eureka

Eureka是Spring Cloud Netfilx 组件中的一部分,它基于Netfilx Eureka进行了二次封装,增加了Spring Boot风格的自动化配置,只需要通过简单的注解配置就能轻松的与微服务应用进行整合。

​ Eureka服务端:也称为服务注册中心,支持高可用配置,当Eureka服务端以集群的方式部署时,其他节点出现故障不会影响正常节点的工作,正常的节点仍然可以提供注册和发现,当故障节点恢复正常时,集群中的其他节点会把他们的状态再次同步回来。不过服务注册中心是通过异步模式相互复制各自的状态,这意味着每个实例之间状态是有细微差别的。

​ Eureka客户端:主要处理服务的注册与发现。客户端通过注解和参数配置的方式,嵌入在客户端应用程序的代码中,在运行时,Eureka客户端会向注册中心注册自身提供的服务并周期性的发送心跳来维持服务租约。同时,它也能从服务端查询到当前注册的服务信息并把他们缓存到本地并周期性地刷新服务状态。

搭建服务注册中心

  1. 使用IDEA的脚手架创建一个SpringBoot工程,选择Eureka Server依赖
    在这里插入图片描述
  2. 在启动类中通过添加**@EnableEurekaServer**注解启动一个服务注册中心
  3. 默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,可以通过配置进行修改,相关配置如下
# 服务命名
spring.application.name=spring-cloud-eureka-server
# 设置当前的端口
server.port=8761
# 指定服务注册中心的地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
# 主机名
eureka.instance.hostname=eureka1

# 是否向服务注册中心进行注册
eureka.client.register-with-eureka=false
# 是否向服务注册中心检索服务
eureka.client.fetch-registry=false

注册服务提供者

  1. 使用IDEA脚手架创建一个Spring Boot 工程
    在这里插入图片描述
  2. 创建一个控制器HelloController作为一个服务
package com.wxw.example.springcloudeurekahello;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    public String hello(){
        System.out.println("欢迎使用Hello服务组件!!!");
        return "Hello World!!!";
    }

}

  1. 修改配置信息
#设置应用名称
spring.application.name=hello-server
#设置端口号
server.port=8081

#指定服务注册中心
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/

高可用的注册中心

Eureka Server的高可用实际上就是将自己作为服务向其他服务注册中心注册自己,这样就形成了一组互相注册的服务注册中心,以实现服务清单的互相同步。

​ 例如:

​ 服务注册中心1配置:

spring.application.name=eureka-server
server.port=1111

eureka.instance.hostname=peer1
eureka.client.service-url.defaultZone=http://peer2:1112/eureka/
服务注册中心2配置:
spring.application.name=eureka-server
server.port=1112

eureka.instance.hostname=peer2
eureka.client.service-url.defaultZone=http://peer1:1111/eureka/
修改服务提供者配置:
#指定服务注册中心
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/,http://localhost:2222/eureka/

服务发现与消费

  1. 使用IDEA脚手架创建一个Spring Boot 工程
    在这里插入图片描述
  2. 创建一个控制器UserController作为一个服务
package com.wxw.example.springcloudeurekauser;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class UserController {

    @Bean
    @LoadBalanced
    RestTemplate restTemplate(){
        return new RestTemplate();
    }

    @Autowired
    RestTemplate restTemplate;

    @RequestMapping(value = "helloUser",method = RequestMethod.GET)
    public String helloUser(){
        return restTemplate.getForEntity("http://hello-server/hello",String.class).getBody();
    }

}

  1. 修改配置信息
#设置应用名称
spring.application.name=user-server
#设置端口号
server.port=8082

#指定服务注册中心
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/,http://localhost:2222/eureka/

服务治理机制

服务提供者

服务注册

服务提供者在启动的时候会通过发送REST请求的方式将自己注册到服务注册中心,服务注册中心收到请求之后,会将元数据信息存储在一个双层结构的Map中,其中第一层的key是服务命,第二层的key是具体服务的实例名。

服务同步

如果服务注册中心互相注册为服务,当服务提供者发送请求到一个服务注册中心时,也会将该请求转发给集群中的其他注册中心,从而实现服务注册中心之间的服务同步。

服务续约

在完成服务注册之后,服务提供者会维护一个心跳用来持续告诉服务注册中心,以防止服务注册中心剔除该服务实例。

​重要配置:

# 服务续约任务的调用间隔时间,默认30秒
eureka.instance.lease-renewal-interval-in-seconds=30
# 服务失效的时间,默认90秒
eureka.instance.lease-expiration-duration-in-seconds=90

服务消费者

获取服务

在启动服务消费者的时候,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。为了考虑性能,服务注册中心会返回一份只读的服务清单给客户端,该缓存清单会每隔30秒更新一次。

​重要配置:

# 缓存清单的更新时间,默认为30秒
eureka.client.registry-fetch-interval-seconds=30
服务调用

服务消费者在获取服务清单后,通过服务命可以获得具体服务的实例信息,客户端会根据负载均衡的方式进行调用。在Ribbon中会默认采用轮询的方式进行调用。

服务下线

当服务实例进行正常的关闭操作时,它会触发一个服务下线的REST请求给服务注册中心。服务注册中心在接收到请求之后,会将该服务状态设置为下线,并把该下线事件传播出去。

服务注册中心

失效剔除

如果服务实例因为故障不能正常工作,而且服务注册中心并未收到服务下线的请求。为了从服务清单中将这些故障服务实例剔除,服务注册中心会创建一个定时任务,默认每60秒将当前清单中剔除超过90秒没有续约的服务。

自我保护

服务注册中心在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现,服务注册中心会将当前的服务实例信息保护起来。但是,在这段保护期间内实例若出现问题,那么客户端可能会出现调用失败的情况。

​重要配置:

# 是否使用保护机制
eureka.server.enable-self-preservation=false

健康检测

默认的心跳检测方式可以有效检查客户端进程是否正常运作,但却无法保证客户端应用能够正常提供服务。

​在Spring Cloud Eureka中,可以通过简单的配置,把Eureka客户端的健康检测交给Spring-boot-actuator模块的/health端点,以实现更加全面的健康状态检测,步骤如下:

  1. 在pom.xml中引入spring-boot-starter-actuator模块的依赖。
  2. 在application.properties中增加参数配置eureka.client.healthcheck.enabled=true

CAP理论

一个分布式系统不可能同时满足C(一致性)、A(可用性)、p(分区容错性)。

由于分区容错性P在分布式系统中是必须要保证的,因此我们只能从A和C中进行权衡。

Eureka遵循AP

  • Eureka各个节点都是平等的,异常的节点挂掉不能影响正常节点的工作,正常节点仍然可以提供注册和发现服务
  • 如果Eureka客户端向某个Eureka注册中心注册或发现服务时出现连接失败,则会自动切换到其他节点,只要有一台节点正常,就可以保证服务的可用性,只不过查到的信息不一定是最新的。
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐