Eureka服务治理
服务治理
服务治理的概念
- 服务治理可以说是微服务架构中最为核心和基础的模块,它 主要用来实现各个微服务实例的自动化注册与服务发现。
- 在传统的系统部署中,服务运行在一个固定的已知的IP和端口上,如果一个服务需要调用另一个服务,那么可以通过地 址直接调用。但是,在虚拟化或者容器化的环境中,服务实 例的启动和销毁是很频繁的,那么服务地址也是在动态变化的。因此,就产生了服务治理的概念。
- 如果需要将请求发送到动态变化的服务实例上,至少需要两个步骤:服务注册&服务发现。
服务发现的两种方式
客户端服务发现
优点: 客户端知道所有可用服务的实际网络地址,所以非常方便的实现负载均衡。(比如一致性哈希)
缺点:耦合性很强。针对不同的语言,每个服务的客户端都得实现一套服务发现的功能。
服务端服务发现
优点:服务的发现逻辑对客户端是透明的。客户端只需要向load balancer发送请求就可以了。
缺点:必须要关心该负载均衡组件的高可用性。
什么是CAP?
CAP理论指的是一个分布式系统最多只能同时满足一致性(Consistency)、可用性 (Availability)和分区容错性(Partition tolerance)这三项中的两项。
- 一致性指的是数据一致性,一致性指的是所有节点在同一时间的数据完全一致。
- 可用性指的是服务可用性,可用性指服务一直可用,而且是正常响应时间。,不管什么时候访问,都可以正常的获取数据值。而不会出现问题。好的可用性主要是指系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况。
- 分区容错性指的是在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。
Eureka实战
搭建单机服务注册中心
pom引入相应的包。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
主启动类添加注解@EnableEurekaServer。
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
修改application.yml 文件。
eureka:
client:
service-url:
defaultZone: http://localhost:8800/eureka/
register-with-eureka: false
fetch-registry: false
搭建集群服务注册中心
cluster1的配置文件。
# 同一个集群,应用名称保持一致
spring:
application:
name: eureka-cluster
server:
port: 8001
# http://cluster1:8001
eureka:
instance:
hostname: cluster1
# 注册到cluster2:8002里
client:
service-url:
defaultZone: http://cluster2:8002/eureka/
cluster2的配置文件。
# 同一个集群,应用名称保持一致
spring:
application:
name: eureka-cluster
server:
port: 8002
# http://cluster2:8002
eureka:
instance:
hostname: cluster2
# 注册到cluster1:8001里
client:
service-url:
defaultZone: http://cluster1:8001/eureka/
Eureka集群架构
服务提供者
-
服务注册
“服务提供者” 在启动的时候会通过发送REST请求的方式将自己注册到Eureka Server 上,同时带上了自身服务的一些元数据信息。Eureka Server 接收到这个REST请求后,将元数据信息存储在一个双层结构Map中,其中第一层的key是服务名,第二层的key 是具体服务的实例名。
在服务注册时,需要确认eureka.client.register-with-eureka=true参数是否正确,若为false,将不会启动注册操作。 -
服务同步
由于服务注册中心之间为互相注册,当服务提供者发送注册请求到一个服务注册中心时,它会将请求转发给集群中相连的其他注册中心,从而实现注册中心之间的服务同步。通过服务同步,两个服务提供者的服务信息就可以通过这两个服务注册中心中的任意一台获取到。 -
服务续约
在注册完服务之后,服务提供者会维护一个心跳用来持续告诉 Eureka Server :“我还活着”,以防止 Eureka Server 的 “剔除任务” 将该服务实例从服务列表中排除出去,我们称该操作为服务续约。
服务消费者
- 获取服务列表
假如到这里,在服务注册中心已经注册了一个服务,并且该服务有两个实例。当我们启动服务消费者时,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑,Eureka Server 会维护一份只读的服务清单来返回给客户端,同时该缓存清单会每隔30秒更新一次。
获取服务列表是服务消费者的基础,所以要确保 eureka-client-fetch-registery=true 参数没有被修改成false,该值默认为 true。若想修改缓存清单的更新时间,可以通过 eureka-client.registry-fetch-interval-seconds=30 参数来进行修改,该值默认为30,单位为秒。 - 服务调用
服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息。因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体需要调用的实例,在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。 - 服务下线
在系统运行过程中必然会面临关闭或重启服务的某个实例的情况,在服务关闭期间,我们自然不希望客户端会继续调用关闭了的实例。所以在客户端程序中,当服务实例进行正常的关闭操作时,它会触发一个服务下线的REST请求给 Eureka Server,告诉服务注册中心:“我要下线了”。服务端在接收到请求之后,将该服务状态设置为下线(DOWN),并把该下线事件传播出去。
服务注册中心
- 失效剔除
当一些外部原因如内存溢出、网络故障等导致服务实例非正常下线,而服务注册中心并未收到“服务下线”的请求。为了从服务列表中将这些无法提供服务的实例剔除,Eureka Server 在启动的时候会创建一个定时任务,默认每隔一段时间(默认60秒)将当前清单中超时(默认90秒)没有续约的服务剔除出去。 - 自我保护
我们在本地调试基于 Eureka 的程序时,基本上都会在服务注册中心的信息面板上出现红色警告信息。
实际上,该警告就是触发了Eureka Server的自我保护机制。之前介绍过,服务注册到Eureka Server之后,会维护一个心跳连接,告诉Eureka Server 自己还活着。Eureka Server 在运行期间,会统计心跳失败的比例在15分钟之内低于85%,如果出现低于的情况,Eureka Server 会将当前的实例信息保护起来,让这些实例不会过期,尽可能保护这些注册信息。但是,在保护期间内实例若出现问题,那么客户端很容易拿到实际已经不存在的服务实例,会出现调用失败的情况,所以客户端必须要有容错机制,比如可以使用请求重试、断路器等机制。
由于在本地调试很容易触发注册中心的保护机制,使得注册中心维护的服务实例不那么准确。可以在本地进行开发时,使用 eureka-server.enable-self-preservation=false 参数来关闭保护机制,确保注册中心将不可用的实例正确剔除。
常用的HttpRest接口
- 查看所有服务的注册列表
GET http://localhost:8800/eureka/apps
- 查看某一个服务的注册列表
GET http://localhost:8800/eureka/apps/SERVICE-NAME
- 服务下线
PUT http://localhost:8800/eureka/apps/SERVICE-NAME/INSTANCE-NAME/status?value=DOWN
- 服务恢复
PUT http://localhost:8800/eureka/apps/SERVICE-NAME/INSTANCE-NAME/status?value=UP
- 服务剔除
DELETE http://localhost:8800/eureka/apps/SERVICE-NAME/INSTANCE-NAME