Eureka服务注册与发现
介绍
又称服务中心,管理各种服务功能包括服务的注册、发现、熔断、负载、降级等。
任何一个服务都不能直接去掉用,都需要通过注册中心来调用。通过服务中心来获取服务你不需要关注你调用的项目IP地址,由几台服务器组成,每次直接去服务中心获取可以使用的服务去调用既可。
由于各种服务都注册到了服务中心,就有了很多高级功能条件。比如几台服务提供相同服务来做客户端负载均衡(Ribbon);监控服务器调用成功率来做断路器(Hystrix),移除服务列表中的故障点;监控服务调用时间来对不同的服务器设置不同的权重、智能路有(Zuul)等等。
Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现。Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server,并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。Spring Cloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。
Eureka的两个组件
Eureka由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。Eureka客户端是一个java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换支持。
单机版Eureka
-
创建
module
(cloud-eureka-server7001) -
引入
pom
依赖在父工程中:
<dependencies> <!--eureka-server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <!--公共模块--> <groupId>org.example</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--一般为通用配置--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
在你要使用Eureka的服务模块中的pom加入
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
3.在application.yml
中进行Eureka
配置
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false 表示自己端就是祖册中心,我的职责就是维护服务实例,并不是去检索服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Service交互的地址查询服务和注册服务都需要依赖这个地址
4.在springboot启动类里面使用@EnableEurekaServer
来开启 Eureka Server
@SpringBootApplication
@EnableEurekaServer//开启Eureka Server
public class ServerMain7001 {
public static void main(String[] args) {
SpringApplication.run(ServerMain7001.class,args);
}
}
5.启动module
访问 http://localhost:7001 会出现以下页面.
微服务入驻Eureka Server
-
引入依赖
<!-- eureka-client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
-
在
application.yaml
中配置eureka: client: register-with-eureka: true #表示见自己的服务注册到Eureka Server 中 ,默认为true fetch-registry: true #是否从Eureka server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 service-url: defaultZone: http://localhost:7001/eureka
-
开启
Eureka client
@SpringBootApplication @EnableEurekaClient//千万不要写错不要写成了EnableEurekaServer public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class, args); } }
-
启动看结果 访问 http://localhost:7001/
集群版Eureka
-
因为我们要模拟几台服务器做集群,所以我们先在 C:\Windows\System32\drivers\etc 路径下的
hosts
文件后面加上 (你要玩几台就加几个,由于这个文件是系统文件所以需要把文件复制到桌面来修改在替换回去)- 127.0.0.1 cloud7001.com
- 127.0.0.1 cloud7002.com
-
创建一个
cloud-eureka-server7002
(把cloud-eureka-server7001
的配置弄过来后面稍稍改下配置就好) -
因为 多个注册中心是:互相注册相互守望 ,所以修改配置
cloud-eureka-server7002
和cloud-eureka-server7001
的application.yaml-
cloud-eureka-server7001
—application.ymlserver: port: 7001 eureka: instance: hostname: eureka7001.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己 fetch-registry: false #false 表示自己端就是祖册中心,我的职责就是维护服务实例,并不是去检索服务 service-url: defaultZone: http://eureka7002.com:7002/eureka/ #设置与Eureka Service交互的地址查询服务和注册服务都需要依赖这个地址
-
cloud-eureka-server7002
—application.ymlserver: port: 7002 eureka: instance: hostname: eureka7002.com #eureka服务端的实例名称 client: register-with-eureka: false #false表示不向注册中心注册自己 fetch-registry: false #false 表示自己端就是祖册中心,我的职责就是维护服务实例,并不是去检索服务 service-url: #集群版需要互相掉 defaultZone: http://eureka7001.com:7001/eureka/ #设置与Eureka Service交互的地址查询服务和注册服务都需要依赖这个地址
-
-
然后运行看下效果
- 可以看到是互相依赖互相守望的
配置集群的支付服务模块
-
创建
cloud-provider-payment8002
(同样我们吧cloud-provider-payment8001
的配置复制过来稍稍的修改一下就好) -
修改配置
-
application.yml(同时修改8001-8002)
server: port: 8002 #记得端口要改成对应的 spring: application: name: cloud-payment-service #服务名称 datasource: type: com.alibaba.druid.pool.DruidDataSource #当前数据源操作类型 driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://rm-bp15x4v3331c04pq86o.mysql.rds.aliyuncs.com:3306/db2019?useUnicode=true&characterEncoding=UTF-8&useSSL=false username: root password: Hzx3869327 eureka: client: register-with-eureka: true #表示见自己的服务注册到Eureka Server 中 ,默认为true fetch-registry: true #是否从Eureka server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 service-url: # defaultZone: http://localhost:7001/eureka defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka instance: instance-id: payment8002 prefer-ip-address: true #显示ip mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.hzx.springcloud.entities #所有entity别名所在包
-
-
修改
cloud-consumer-order80
-
application.yaml
server: port: 80 spring: application: name: cloud-consumer-service #服务吗 eureka: client: register-with-eureka: true #表示见自己的服务注册到Eureka Server 中 ,默认为true fetch-registry: true #是否从Eureka server抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 service-url: # defaultZone: http://localhost:7001/eureka 单机版 defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
-
controller改成
//先暂时固定 // private static final String PAYMENT_URL="http://localhost:8001"; private static final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE";//Eureka 上对应的服务名
-
主要的一点记得吧
RestTemplate
开启负载均衡具体:-
在配置
RestTemplate
中的Config中添加@LoadBalanced
/** *LoadBalanced 负载均衡 * @return */ @Bean @LoadBalanced//赋予RestTmplate负载均衡的能力 public RestTemplate getRestTemplate(){ return new RestTemplate(); }
-
-
-
运行看效果
-
访问http://eureka7001.com:7001/
-
使用postman访问
http://localhost/consumer/payment/get/44
访问第一次
访问第二次
可以看到负载均衡起作用了
写操作就不写了,不出问题也是完全ok的
-
Eureka自我保护机制
默认情况下,当eureka server
在一定时间内没有收到实例的心跳,便会把该实例从注册表中删除(默认是90秒),但是,如果短时间内丢失大量的实例心跳,便会触发eureka server的自我保护机制,比如在开发测试时,需要频繁地重启微服务实例,但是我们很少会把eureka server
一起重启(因为在开发过程中不会修改eureka
注册中心),当一分钟内收到的心跳数大量减少时,会触发该保护机制。可以在eureka
管理界面看到Renews threshold
和Renews(last min)
,当后者(最后一分钟收到的心跳数)小于前者(心跳阈值)的时候,触发保护机制,会出现红色的警告:
EMERGENCY!EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT.RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEGING EXPIRED JUST TO BE SAFE.
官方对于自我保护机制的定义:
自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。
关闭Eureka的自我保护机制
将Eureka Server中的Application.yaml
将server.enable-self-preservation
设置为false
server:
enable-self-preservation: false #将Eureka的自我保护机制设置为false就是禁用
为了能更快的看到效果我这里也设置一下这个
# Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
# Eureka服务端在收到最后一次心跳后等待时间上限 ,单位为秒(默认是90秒),超时剔除服务
lease-expiration-duration-in-seconds: 2
测试:
发现Eureka很贴心很明确的告诉了我们自我保护机制已经禁用了
这是后我把服务给关了,等待1秒可以发现他立马就注销了这个服务
但是一般情况下是不会关闭这个机制的,因为这个自我保护机制对于我们来说很友好
微服务发现Discovery
对于注册进Eureka里的服务,可以通过服务发现来获得该服务的信息,也是非常的简单
具体操作步骤:
-
修改cloud-provider-payment8001的Controller
@Autowired private DiscoveryClient discoveryClient; //以及一个方法 @GetMapping(value = "/payment/discovery") @ResponseBody public Object Discovery(){ List<String> services = discoveryClient.getServices(); for (String s:services ) { log.info("*******element"+s); } List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); for (ServiceInstance si:instances ) { log.info("************instances"+si.getInstanceId()+"\t"+si.getServiceId()+"\t"+si.getHost()+"\t"+si.getPort()+"\t"+si.getUri()); } return this.discoveryClient; }
-
还有最重要的一步在主启动类上加
@EnableDiscoveryClient
注解 -
测试
控制台成功输出了