前言
生产者与消费者
上一节通过RestTemplate实现了生产者与消费者之间的调用关系,也提到了这种方式在分布式架构中是存在着问题的。
例如:商品微服务是消费者的同时还是其他服务的生产者,那么他们的调用配置都需要变更。当然可以采用nginx等反向代理来实现,但是当有数百个微服务岂不是被搞si了。针对这个问题引出了服务发现的概念,如下图所示:
服务发现机制:
1、服务生产者和服务消费者在启动的时候都会把自己的网络地址(IP+端口)注册到服务发现组件,服务消费者要调用的时候先到服务发现组件里面查询服务提供者的IP+端口然后进行调用。
2、任何服务都有宕掉的可能,如果服务生产者挂了那就需要将服务发现组件里注册的对应节点剔除掉,所以当服务消费者和生产者注册到服务发现组件后就会隔段时间发起心跳,如果接受不到节点信息就剔除掉。
服务发现组件功能
1、服务注册表
可以将服务注册表看做是数据库,因为本身就是将当前可用服务示例的网络信息(IP+端口)记录下来。提供查询API和管理API,使用查询API可以获得可用的服务示例,使用管理API实现注册和注销;
2、服务注册
将网络信息(IP+端口)存放到服务注册表。
3、健康检查
上面提到的心跳检查就是其中一个功能,将不可用的网络信息进行剔除,保证服务消费者能够调用到正常的网络信息。
服务发现的方式
1、客户端发现
例如:Eureka、zookeeper等。
2、服务器端发现
例如:Consul + nginx
Eureka简介
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转义的目的。Spring Cloud将它集成在其子项目spring-cloud-netflix中,用来实现Spring Cloud的服务发现功能。
实现一个Eureka Server
第一步:添加Eureka依赖(pom.xml)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
第二步:Spring Boot启动类增加注解
/**
* @Auther: Lin
* @Date: 2019-07-29 23:01
* @Description: 使用Eureka做服务发现
*/
@SpringBootApplication
@EnableEurekaServer
public class MicroserviceDiscoveryEurekaApplication {
public static void main(String[] args){
SpringApplication.run(MicroserviceDiscoveryEurekaApplication.class,args);
}
}
第三步:增加Eureka配置(application.ml)
server:
port: 8761
eureka:
client:
# 是否要注册到其他Eureka Server实例
register-with-eureka: false
# 是否要从其他Eureka Server实例获取数据
fetch-registry: false
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
备注:Eureka默认端口为8761。
第四步:启动测试
访问地址:http://127.0.0.1:8761,如下图所示:
出现上面控制台页面说明Eureka单机部署成功。
将用户(user)和商品(goods)服务注册到Eureka Service
基于SpringCloud实战(一)中的microservice-consumer-goods和microservice-provider-user微服务,将服务注册到Eureka Service。
第一步:添加Eureka Client依赖(pom.xml)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
备注:goods和user两个工程pom.xml都需添加
第二步:添加注解
#microservice-provider-user 微服务
@SpringBootApplication
#@EnableEurekaClient
public class MicroserviceProviderUserApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceProviderUserApplication.class, args);
}
}
#microservice-consumer-goods 微服务
@SpringBootApplication
#@EnableEurekaClient
public class MicroserviceDiscoveryEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceDiscoveryEurekaApplication, args);
}
}
备注:Spring Cloud 的Edgware版本之前客户端启动类需要增加@EnableDiscoveryClient或 @EnableEurekaClient,从Edgware开始,可省略
第三步:添加配置
#microservice-provider-user 微服务
spring:
application:
# 指定注册到eureka server上的服务名称
name: microservice-provider-user
eureka:
client:
service-url:
# eureka server的通讯地址,注意路径
defaultZone: http://127.0.0.1:8761/eureka/
instance:
# 是否将IP注册到eureka server,false:否,ture:是
prefer-ip-address: true
#microservice-consumer-goods 微服务
spring:
application:
# 指定注册到eureka server上的服务名称
name: microservice-consumer-goods
eureka:
client:
service-url:
# eureka server的通讯地址,注意路径
defaultZone: http://127.0.0.1:8761/eureka/
instance:
# 是否将IP注册到eureka server,false:否,ture:是
prefer-ip-address: true
第四步:启动测试
按照顺序启动Eureka Server、用户微服务和商品微服务;
访问Eureka控制台查看,地址:http://127.0.0.1:8761
常见问题汇总
问题1:Eureka的注册页面,发现有一串红字:
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
原因:出现以上报错是因为Eureka进入了自我保护机制,默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳时,EurekaServer将会注销该实例(默认90s)。但是当网络发生故障时,微服务与EurekaServer之间无法通信,这样就会很危险了,因为微服务本身是很健康的,此时就不应该注销这个微服务,而Eureka通过自我保护机制来预防这种情况,当网络健康后,该EurekaServer节点就会自动退出自我保护模式;
这时再次将客户端微服务启动,刷新服务注册中心会发现,自我保护状态已取消。
配套代码
主代码库:https://github.com/yundianzixun/spring-cloud-study
Eureka Service:https://github.com/yundianzixun/spring-cloud-study/tree/master/microservice-discovery-eureka
microservice-provider-user :https://github.com/yundianzixun/spring-cloud-study/tree/master/microservice-provider-user
microservice-consumer-goods:https://github.com/yundianzixun/spring-cloud-study/tree/master/microservice-consumer-goods
注意:本文归作者所有,未经作者允许,不得转载