Spring Cloud Eureka 是 Spring Cloud Netflix 微服务套件中的一部分, 它基于 Netflix
Eureka 做了二次封装, 主要负责完成微服务架构中的服务治理功能。 Spring Cloud 通过为Eureka 增加了 Spring Boot 风格的自动化配置,只需通过简单引入依赖和注解配置就能让 Spring Boot 构建的微服务应用与 Eureka 服务治理体系进行整合。服务治理可以说是微服务架构中最为核心和基础的模块, 它主要用来实现各个微服务实例的自动化注册与发现。
-
服务治理:
服务注册:
在服务治理框架中, 通常都会构建一个注册中心, 每个服务单元向注册
中心登记自己提供的服务, 将主机与端口号、 版本号、 通信协议等 一些附加信息告
知注册中心, 注册中心按服务名分类组织服务清单。 比如, 我们有两个提供服务A
的进程分别运行于 192.168.0.100:8000和192.168.0.101:8000位置上,
另 外 还 有三个 提 供 服 务B的 进 程 分 别运行千192.168.0.100:9000 、
192.168.0.101:9000、 192.168.0.102:9000位置上。 当这些进程均启动,
并向注册中心注册自己的服务之后, 注册中心就会维护类似下面的
一
个服务清单。
另外,
服务注册中心还需要以心跳的方式去监测清单中的服务是否可用, 若不可用
需要从服务清单中剔除, 达到排除故障服务的效果。
服务发现:
由于在服务治理框架下运作,
服务间的调用不再通过指定具体的实例地
址来实现, 而是通过向服务名发起请求调用实现。 所以, 服务调用方在调用服务提
供方接口的时候, 并不知道具体的服务实例位置。 因此, 调用方需要向服务注册中
心咨询服务, 并获取所有服务的实例清单, 以实现对具体服务实例的访问。
比如,
现有服务C希望调用服务A, 服务C就需要向注册中心发起咨询服务请求, 服务注
册中心就会将服务A的位置清单返回给服务C, 如按上例服务A的情况,C便获得
了服务A的两个可用位置 192.168.0.100:8000和192.168.0.101:8000。
当服务C要发起调用的时候, 便从该清单中以某种轮询策略取出 一 个位置来进行服
务调用, 这就是后续我们将会介绍的客户端负载均衡。
这里我们只是列举了一种简
单的服务治理逻辑, 以方便理解服务治理框架的基本运行思路。 实际的框架为了性
能等因素, 不会采用每次都向服务注册中心获取服务的方式, 并且不同的应用场景
在缓存和服务剔除等机制上也会有一些不同的实现策略。
Netflix Eureka
eurake包含服务端组件,也包含客户端组件,主要用于java语言实现的分布式系统。
eureka服务端也被称为注册中心。主要处理服务的注册与发现。在应用程序运行期间,eureka客户端向服务端注册自己所提供的服务并且周期性的发送心跳来更新服务租约。
-
搭建服务注册中心:
pom依赖:
<parent>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-parent</artifactid>
<version>l.3.7.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-eureka-server</artifactid>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-dependencies</artifactid>
<version>Brixton.SRS</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
启动类:
在一个普通的springboot启动类上加@EnableEurakeServer就可以开启此功能
@EnableEurekaServer
@SpringBootApplication
@EnableDiscoveryClient
public class EurekaApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(EurekaApplication.class).web(true).run(args);
}
}
该服务注册中心会把自己作为客户端来尝试向服务端注册自己,所以要禁用客户端注册行为。需要在application.properties中增加配置:
server.port=l 111
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false #由于该应用为注册中心,所以设置
为 false, 代表不向注册中心注册自己
eureka.client.fetch-registry=false #由于注册中心的职责就是维护服务实例,
它并不需要去检索服务, 所以也设置为 false
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${serve
r.port}/eureka/
注册服务提供者
1.pom:
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boo七-starter-web</artifactid>
</dependency>
<dependency>
<group工d>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-test</artifactid>
<scope>test</scope>
</dependency>
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-eureka</artifactid>
</dependency>
</dependencies>
<dependencyManagemen七>
<dependencies>
<dependency>
<group工d>org.springframework.cloud</groupid>
<ar巨fac七Id>spring-cloud-dependencies</artifac七Id>
<version>Brixton.SRS</version>
<type>pom</type>
<scope江mport</scope>
</dependency>
</dependencies>
</dependencyManagement>
2.主类添加@EnableDiscoveryCLient注解
3.application.properties配置文件
通过spring.application.name属性为服务命名
eureka.client.serviceUrl.defaultZone属性指定注册中心地址
客户端打印出
com.ne七flix.discovery.DiscoveryClient: DiscoveryClient—HELLO-SERVICE/PC-201602152056:hello-service-registration status: 204
服务端打印出
c.n.e.registry.AbstractinstanceRegistry : Registered instance
HELLO-SERVICE/PC-201602152056:hello-service with status UP (replication=true)
表示注册成功
-
高可用注册中心
充分考虑发生故障的情况,所以在生产环境中要对各个组件进行高可用部署,对于微服务和注册中心都是如此。
Eureka的高可用实际上就是将自己作为服务向其他注册中心注册自己
创建application-peer1.properties, 作为peer1服务中心的配置, 并将serviceUrl指向peer2
spring.application.name=eureka-server
server.port=llll
eureka.instance.hostname=peerl
eureka.client.serviceUrl.defaultZone=h七tp://peer2:1112/eureka/
创建application-peer2.properties, 作为peer2服务中心的配置, 并将serviceUr l指向peer1:
spring.application.name=eureka-server
server.port=lll2
eureka.instance.hostname=peer2
eureka.client.serviceUrl.defaultZone=http://peerl:llll/eureka/
在hosts文件中添加对peerl 和 peer2的转换, 让上面配置的host形式的serviceUr l能在本地正确访间到;
127.0.0.1 peer1
127.0.0.1 peer2
通过spring.profiles.active属性来分别启动peer1和peer2:
java -jar eureka-server-1.0.0.jar --spring.profiles.active=peer1
java -jar eureka-server-1.0.0.jar --spring.profiles.active=peer2
启动一个注册到两个注册中心的微服务:
spring.application.name=hello-service
eureka.client.serviceUrl.defaultZone=http://peerl:llll/eureka/,http://peer2:lll
2/eureka/
这样即使注册中心peer1因为意外原因被关闭,那么hello-service也能注册到peer2注册中心,实现服务注册中心的高可用性。
-
服务发现于消费
rabbon在Eureka的服务发现的基础上,实现了一套对服务实例的选择策略,从而实现对服务的消费。
实战准备:
1.启动eureka注册中心
2.启动两个不同端口的hello服务
3.创建ribbon服务:
1.pom文件新增依赖 spring-cloud-starter-ribbon
2.创建主类,添加注解@EnableDiscoveryCLient使应用注册为Eurake客户端应用
3.创建RestTemplete的Spring bean实例,添加@LoadBalanced注解开启客户端负载均衡
@EnableDiscoveryClient
@SpringBootApplication
public class RabbinApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
4.实现一个接口,地址:/ribbon-customer,通过RestTemplete实例对hello服务的接口进行调用
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET)
public String helloConsumer() {
return restTemplate.getForEntity("http://HELLO/hello",
String.class).getBody();
}
}
5.配置文件:
spring:
application:
name: ribbon
server:
port: 9000
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1114/eureka
ribbon启动之后会显示当前客户端维护的hello服务列表情况,访问localhost:9000/rabbon-customer,可以观察到两个hello服务轮询进行输出日志,由此得出结论ribbon就是对服务轮询访问实现基于客户端的负载均衡。
-
Eureka详解
Eurake的三个核心角色: 服务注册中心、服务提供者、服务消费者;因为实际情况要比理想中的更加复杂,所以简单的应用大都无法满足实际应用场景,所以还需要根据实际情况来做配置调整和拓展。客户端既可以是服务提供者也可以是服务消费者,可以理解为一个admin里面整合了Ribbon。
服务提供者
1.服务注册
服务提供者启动时会发送rest请求将自己注册到注册中心,并自身携带一些元数据信息,注册中心接受到这个rest请求之后,会将元数据信息存放到一个双层map中,第一层的key为服务名,第二层的key为服务实例名。
eurake.client.register-with-eurake=true 若设置为false将不会启动注册操作。
2.服务同步
如架构图中所示,两个服务提供者分别注册到了不同的注册中心,他们的信息同时由两个注册中心所维护,因为两个注册中心相互注册,所以当一个请求发送到某个注册中心时,该请求会被转发到另一个注册中心,从而实现注册中心之间的服务同步。所以服务提供者的信息可以再任意一个注册中心中获取到。
3.服务续约
服务提供者每隔(默认30秒)一段时间向注册中心发送心跳,让注册中心知道他的存在,以防止被注册中心剔除掉,这叫做服务续约。
eurake.instance.lease-renewal-interval-in-seconds参数用于定义服务续约任务的间隔时间 默认30秒;
eurake-instance.expiration-duration-in-seconds参数用于定义服务失效的时间,默认90秒;
服务消费者
1.获取服务
当启动服务消费者时。消费者会向注册中心发送请求来获取已经注册到注册中心中的一份只读缓存清单,这份缓存清单每隔一段时间更新一次。
eurake.client.fetch.registry=true 是否开启获取服务
eurake.client.registry.fetch.interval-seconds=30 缓存更新时间
2.服务调用
消费者在获取服务清单之后,会对服务提供者进行轮询访问,从而实现客户端的负载均衡。
eurake有region和zone的概念,一个region包含多个zone,每个服务都被注册到一个region'的zone中。服务调用时优先访问同处一个zone中的服务提供方。
3.服务下线
服务进行正常关闭操作时,会触发一个下线的rest请求给eurake server。eurake会把事件传播出去。
服务注册中心
1.失效剔除
eurake启动时会创建一个定时任务,若服务提供者在制定时间(90秒)未进行续约,那么eurake就会将该服务剔除。
2.自我保护
服务注册到eurake后会维护一个心跳连接,不断地告诉eurake我还活着。eurake会统计心跳失败比例低于85%的服务,eurake会保护这些注册信息,使其不会过期。本地调试容易触发保护机制,所以可以使用
eureka.server.enable-self-preservation=false 关闭保护机制 注册中心会将不可用的实例剔除