了解 Spring Cloud Netflix
该项目是Spring Cloud的子项目之一,主要内容是对Netflix公司一系列开源产品的包装,它为Spring Boot应用提供了自配置的Netflix OSS整合。通过一些简单的注解,开发者就可以快速的在应用中配置一下常用模块并构建庞大的分布式系统。它主要提供的模块包括:服务发现(Eureka),断路器(Hystrix),智能路有(Zuul),客户端负载均衡(Ribbon)等
了解Spring Cloud Eureka
Spring Cloud Eureka 是 Spring Cloud Netflix 组件的一部分。它基于Netflix Eureka做了二次封装,来实现微服务架构中的服务治理功能,即服务注册和发现等功能。Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server,并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。Spring Cloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。
Eureka由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。Eureka客户端是一个java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。Netflix在其生产环境中使用的是另外的客户端,它提供基于流量、资源利用率以及出错状态的加权负载均衡。
为什么要使用服务治理
在一个微服务系统中,可能其中的小型服务几十个以上,服务之间互相依赖调用,如果没有服务治理的话,每一个小型服务都需要维护一个依赖的服务列表,包括ip、端口等,如果其中一个服务修改了, 可能所有依赖它的服务都需要重新修改,这个工程量是很大的,而且这么多服务还要考虑各种命名冲突等问题。如果有了服务治理功能,我们就可以通过它提供的服务注册和服务发现机制来实现对微服务应用实例的自动化管理。
服务注册
在服务治理框架中,通常都会构建一个注册中心,每个服务像注册中心登记自己提供的服务,将主机、端口号、版本号、通信协议等附加信息告知注册中心,注册中心按服务分类组织服务清单。当这些服务启动并向注册中心注册自己的服务后,注册中心就会维护一个服务清单,还以心跳的方式去监测清单中的服务是否可用,若不可用则从服务清单剔除,达到排除故障的效果。
服务发现
由于在服务治理框架下运行,服务间的调用不在通过指定具体的实例地址来实现,而是通过向服务名发起请求调用实现。所以服务调用方并不清楚服务提供方的实际位置。因此,服务调用方会向注册中心咨询服务,获取可以被调用的服务实例清单,以实现对具体实例服务的访问,而且这里默认采用了轮询的方式实现客户端负载均衡,以后在介绍。
用一张图来认识一下
上图简要描述了Eureka的基本架构,由3个角色组成:
1、Eureka Server
服务注册中心,提供服务注册和发现
2、Service Provider
服务提供者
将自身服务注册到Eureka,为服务消费者提供服务
3、Service Consumer
服务消费者
从Eureka获取注册服务列表,从而能够消费服务
搭建服务注册中心
创建Spring Boot项目起名eureka-server-vFinchley.RC2(我这么起名主要是想区分Spring Cloud版本),选择eureka-server依赖
点击finish。创建应用后的pom文件
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Finchley.RC2</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories>
此时直接启动应用会报错,我们配置一下注册中心。
在启动类中添加注解@EnableEurekaServer启动一个服务注册中心提供给其他应用进行对话。
@EnableEurekaServer @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
在默认设置下,该服务注册中心也会将自己作为客户端来尝试注册它自己,所以我们需要禁用它的客户端注册行为,只需要在application.yml中增加如下配置:
server: port: 1111 eureka: instance: hostname: localhost client: register-with-eureka: false #不像注册中心注册自己 fetch-registry: false #是否从Eureka Server获取注册信息,默认为true service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #map类型 设置与Eureka Server交互的地址,查询服务和注册服务都要依赖它
启动应用访问http://localhost:1111/,页面显示
此时是没有服务的,接下来我们创建服务的客户端——服务提供者
创建Spring Boot项目命名eureka-client-vFinchley.Rc2,并添加依赖eureka-discovery
在启动类中加上@EnableDiscoveryClient注解,该注解能激活Eureka中的DiscoveryClient实现。
@EnableDiscoveryClient @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
在添加一个RESTFul API提供服务
@RestController public class HelloController { @GetMapping("hello") public String index(){ return "hello"; } }
修改配置文件
#应用名称 spring: application: name: hello-service #为服务命名 server: port: 2222 eureka: client: service-url: defaultZone: http://localhost:1111/eureka/ #指定服务注册中心位置
启动应用,再次刷新http://localhost:1111/发现多了HELLO-SERVICE服务
这就已经成功实现了一个服务注册中心。
高可用注册中心
在微服务架构的分布式环境中,我们要考虑发生故障的情况。上面的例子只是一个单节点的注册中心,如果它发生故障宕机了,就会导致整个微服务系统挂掉,所以我们需要构建一个高可用的注册中心。
Eureka Server在设计上就考虑到了高可用问题,在Eureka的服务治理设计中,每一个服务提供者也是服务消费者,服务注册中心也不例外。在上面的例子我们就设置了两个参数
①eureka.client.register-with-eureka: 表示是否将自己注册到Eureka Server,默认为true。
②eureka.client.fetch-registry :表示是否从Eureka Server获取注册信息,默认为true。
Eureka Server的高可用实际就是将自己作为服务像其他服务注册中心注册自己,这样就可以实现一组互相注册的服务注册中心,以实现服务清单同步,达到集群高可用的效果。接下来我们实现一个三节点的服务注册中心。为了和单节点区分开,我重新创建一个应用。步骤和创建单节点的服务端一样,起名eureka-server-cluster-vFinchley.Rc2
然后删掉application.properties文件,创建application-peer1.yml,application-peer2.yml,application-peer3.yml
application-peer1.yml
spring: application: name: eureka-server server: port: 1111 eureka: instance: hostname: peer1 client: service-url: defaultZone: http://peer2:1112/eureka/,http://peer3:1113/eureka/ #map类型 多个逗号隔开 指向peer2和peer3
application-peer2.yml
spring: application: name: eureka-server server: port: 1112 eureka: instance: hostname: peer2 client: service-url: defaultZone: http://peer1:1111/eureka/,http://peer3:1113/eureka/ #map类型 多个逗号隔开 指向peer1和peer3
application-peer3.yml
spring: application: name: eureka-server server: port: 1113 eureka: instance: hostname: peer3 client: service-url: defaultZone: http://peer1:1111/eureka/,http://peer2:1112/eureka/ #map类型 多个逗号隔开 指向peer1和peer2
然后在/etc/hosts文件末尾添加对peer1、peer2、peer3的转换,windows系统位置C:\Windows\System32\drivers\etc
127.0.0.1 peer1 127.0.0.1 peer2 127.0.0.1 peer3
将应用打成jar包,然后分别以peer1、peer2、peer3运行jar
java -jar eureka-server-cluster-vFinchley.Rc2-vFinchley.RC2.jar --spring.profiles.active=peer1 java -jar eureka-server-cluster-vFinchley.Rc2-vFinchley.RC2.jar --spring.profiles.active=peer2 java -jar eureka-server-cluster-vFinchley.Rc2-vFinchley.RC2.jar --spring.profiles.active=peer3
然后分别打开http://localhost:1111/,http://localhost:1112/,http://localhost:1113/发现都有了另外的两个服务
然后我们在创建一个用来注册到服务注册中心集群的服务客户端。创建一个应用,起名eureka-client-cluster-vFinchley.Rc2,步骤和单节点的创建客户端一样。
修改application.yml,指定服务注册地址为多个
#应用名称 spring: application: name: hello-service #为服务命名 server: port: 2222 eureka: client: service-url: defaultZone: http://peer1:1111/eureka/,http://peer2:1112/eureka/,http://peer3:1113/eureka/ #指定服务注册中心位置
然后把单节点的Controller复制过来,启动应用,访问http://localhost:2222/hello
而且打开http://localhost:1111/,http://localhost:1112/,http://localhost:1113/也会发现分别多了HELLO-SERVICE服务。
现在我们关闭一个服务注册中心,发现http://localhost:2222/hello仍然可以访问。
打开一个注册中心,发现挂掉的服务也进入到unavailable-replicas行了
这就成功实现了一个高可用的服务注册中心。