服务治理
服务治理是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册和发现。
在微服务架构体系中,每个服务都是相对独立的,包括其部署、扩展和升级,都不应和其他服务产生耦合。但是微服务之间是无法避免业务关系的,也就是说服务之间需要互相调用。对于Restful接口而言,服务A要调用服务B的接口,必须知道具体的url,这样服务A就必须与服务B的部署位置产生依赖关系。另一方面,为了实现服务B的高可用,不论采用服务端负载均衡还是客户端负载均衡,都需要手工维护服务B的实例列表。
为了解决微服务架构中的服务实例维护问题,产生了大量的服务治理框架和产品。服务治理的功能主要有一下几点:
- 对开发新服务和升级现有服务的计划管理服务的生命周期;
- 确保升级服务不会影响目前的服务消费者制定方针来限制服务行为;
- 制定所有服务都要遵从的规则,确保服务的一致性监控服务的性能;
- 由于服务组合,服务停机和性能低下的后果是严重的。通过监控服务的性能和可用性,当问题出现的时候能马上采取应对措施;
- 管理由谁来调用服务、怎样调用服务
服务注册
在服务治理框架中,通常需要一个注册中心。每个服务想注册中心登记自己提供的服务,将服务的位置、调用方式等告知注册中心。注册中心会按服务名分类组织分类清单。另外服务注册中心还需定时监控清单中的服务的健康状态,及时剔除不可用的实例。
服务发现
在服务治理框架下,服务之间的调用不在依赖于服务的具体位置(如ip:port),而是通过服务名调用,从而将服务的部署从微服务的调用中解决关联。通过服务名调用,还可以方便地实现负载均衡。由于服务注册,我们有一份清单可以找到某个服务的具体实例,若是服务不止一个实例,我们可以很方便地动态选择服务的实例进行调用,从而实现负载均衡。这也有利于服务的横向扩展,实现高可用。
Spring Cloud Eureka
Netflix Eureka是Netflix开发的一套基于jvm和restful的服务治理框架。其服务端是用java语言编写,主要适用于java实现的分布式系统。但是其通信协议为基于http的restful,所以客户端理论上用什么语言实现都可以。这也是微服务的一大特点,服务可以根据自身特点选用相应的语言或平台实现,不必局限于同一的平台。
搭建服务注册中心
Spring Cloud中的微服务就是一个个Spring Boot应用程序,服务注册中心也不例外。按上篇文章的步骤,搭建一个spring boot模块。
修改build.gradle
,引入spring-cloud-starter-eureka-server
group 'com.zhuangqf.demo'
version '1.0-SNAPSHOT'
dependencies {
compile "org.springframework.cloud:spring-cloud-starter-eureka-server"
compile "org.springframework.boot:spring-boot-starter-web"
}
添加Application启动类,通过EnableEurekaServer注解启动一个注册服务中心。
@EnableEurekaServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
添加application.yml:
spring:
application:
name: eureka-server
server:
port: 9000
eureka:
instance:
instance-id: ${spring.cloud.client.ipAddress}:${server.port}
hostname: ${spring.cloud.client.ipAddress}
client:
fetch-registry: false
register-with-eureka: false
serviceUrl.defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
先重点关注eureka.client配置:
- eureka.client.fetch-registry 默认为true,是否拉取注册的实例信息,注册中心不需要远程调用实例,所以不需要检索服务,设为false。
- eureka.client.register-with-eureka 对于单注册中心,不需要向自己注册
- eureka.client.serviceUrl.defaultZone 注册中心地址
接入客户端
注册中心已经跑起来了,那么怎么让我们的服务注册到注册中心呢?让我们对之前写过的example模块做一些改造。
在example模块的build.gradle
中添加依赖
compile "org.springframework.cloud:spring-cloud-starter-eureka"
相应的,在Application类加一个注解:
@SpringBootApplication
@EnableDiscoveryClient
public class Application {
public static void main(String[] arg) {
SpringApplication.run(Application.class,arg);
}
}
接着,在application.yml
中指定注册地址:
eureka:
instance:
instance-id: ${spring.cloud.client.ipAddress}:${server.port}
hostname: ${spring.cloud.client.ipAddress}
client:
serviceUrl.defaultZone: http://localhost:9000/eureka/
高可用注册中心
高可用集群是指以减少服务中断时间为目的的服务器集群技术。它通过保护用户的业务程序对外不间断提供的服务,把因软件/硬件/人为造成的故障对业务的影响降低到最小程度。
在微服务架构系统中,故障是不可能避免的。Eureka Server的设计一开始就考虑了高可用的问题,在Eureka的服务治理设计中,所有节点既是服务提供方,又是服务消费方,服务注册中心也不例外。
Eureka Server的高可用实际上是将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组互相注册的服务注册中心。注册中心之间会共享彼此的服务清单,注册中心可以在一个zone中,也可以按业务或服务的部署位置分为多个zone。
在这里,我们先简单实现同一个zone的两个注册中心,让它们彼此注册,实现高可用。
首先,在eureka-server的application.yml中增加以下配置
-- peer1
server.port: 9001
eureka:
client:
fetch-registry: true
register-with-eureka: true
serviceUrl.defaultZone: http://${eureka.instance.hostname}:9002/eureka
-- peer2
server.port: 9002
eureka:
client:
fetch-registry: true
register-with-eureka: true
serviceUrl.defaultZone: http://${eureka.instance.hostname}:9001/eureka
peer1和peer2是可选的两组配置,在配置中,我们从彼此注册到对方。
分别启动peer1和peer2
启动example
修改example的注册服务器地址:
此时,peer1或者peer2有一个出现故障在短时间内不会对系统的业务有太大的影响,因为另一个注册中心可以临时性承接所有的流量。