2.4 Eureka详解
2.4.1 优化集群:高可用的注册中心
-
Eureka demo即服务的注册中心,事实上Eureka demo也可以是一个集群,形成高可用的Eureka注册中心
-
服务同步
- 多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中的某个节点时
- 该节点会把服务的信息同步给集群中的每个节点,从而实现数据同步。
- 因此,无论客户端访问到Eureka Server集群中的任意一个节点,都可以获取到完整的服务列表信息。
-
搭建高可用的注册中心
- 我们假设要搭建两条EurekaServer的集群,端口分别为:10086和10087
-
application-10086.yml
# 端口号 server: port: 10086 # eureka的配置 eureka: client: service-url: defaultZone: http://localhost:10087/eureka/
-
application-10087.yml
# 端口号 server: port: 10087 # eureka的配置 eureka: client: service-url: defaultZone: http://localhost:10086/eureka/
-
所谓的高可用注册中心,其实就是把EurekaServer自己也作为一个服务进行注册,这样多个EurekaServer之间就能互相发现对方,从而形成集群。因此我们做了以下修改:
- 删除了register-with-eureka=false和fetch-registry=false两个配置。
因为默认值是true,这样就会吧自己注册到注册中心了。
-
把service-url的值改成了另外一台EurekaServer的地址,而不是自己
-
使用SpringBoot启动加载两个配置文件
2.4.2 优化:服务提供者配置
服务提供者Eureka_Service要向Eureka_demo注册服务,并且完成服务续约等工作
-
服务注册
- 服务提供者在启动时,会检测配置属性中的:eureka.client.register-with-erueka=true参数是否正确,默认就是true。如果值确实为true,则会向EurekaServer发起一个Rest请求,并携带自己的元数据信息,完成注册操作。
-
服务续约
- 在注册服务完成以后,服务提供者会维持一个心跳(定时向EurekaServer发起Rest请求),告诉EurekaServer:“我还活着”。这个我们称为服务的续约(renew);
eureka: instance: lease-expiration-duration-in-seconds: 10 #服务失效时间(默认90秒) lease-renewal-interval-in-seconds: 5 #发送心跳续约时间(默认30秒)
- 这两个值在生产环境不要修改,默认即可。但是在开发时,这个值有点太长了,经常我们关掉一个服务,会发现Eureka依然认为服务在活着。所以我们在开发阶段可以适当调小
2.4.3 优化:服务消费者配置
当服务消费者启动是,会检测eureka.client.fetch-registry=true参数的值,如果为true,则会从Eureka Server服务的列表只读备份,然后缓存在本地。并且每隔30秒会重新获取并更新数据。我们可以通过下面的参数来修改
eureka:
client:
registry-fetch-interval-seconds: 5 #从注册中心,获得列表的间隔时间(默认30秒)
生产环境中,我们不需要修改这个值。
但是为了开发环境下,能够快速得到服务的最新状态,我们可以将其设置小一点。
2.4.4 注册中心优化:失效剔除和自我保护
-
失效剔除
有些时候,我们的服务提供方并不一定会正常下线,可能因为内存溢出、网络故障等原因导致服务无法正常工作。Eureka Server需要将这样的服务剔除出服务列表。因此它会开启一个定时任务,每隔60秒对所有失效的服务(超过90秒未响应)进行剔除。
可以通过eureka.server.eviction-interval-timer-in-ms参数对其进行修改,单位是毫秒,生成环境不要修改。
-
自我保护
这是触发了Eureka的自我保护机制。当一个服务未按时进行心跳续约时,Eureka会统计最近15分钟心跳失败的服务实例的比例是否超过了85%。在生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因为服务可能没有宕机。Eureka就会把当前实例的注册信息保护起来,不予剔除。生产环境下这很有效,保证了大多数服务依然可用
eureka:
server:
enable-self-preservation: false # 关闭自我保护模式(默认为打开)
eviction-interval-timer-in-ms: 10000 # 扫描失效服务的间隔时间/毫秒(默认为60*1000ms)
3. 负载均衡
3.1 服务提供者
-
同一个名称的服务,只要提供多个实例,注册到eureka中,就可以自动形成集群。
-
步骤一:配置yml文件
-
application-8081.yml 仅配置端口号
server:
port: 8081
- application-8082.yml 仅配置端口号
server:
port: 8082
- 步骤二: 为两个yml文件配置SpringBoot启动类
- 步骤三: 启动测试
3.2 开启负载均衡
因为Eureka中已经集成了Ribbon,所以我们无需引入新的依赖。直接修改代码:
-
服务提供方
-
导入RestTemplate依赖
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.5</version> </dependency>
-
测试数据
-
package com.czxy.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* Created by liangtong.
*/
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping
public ResponseEntity<String> test(HttpServletRequest request){
// 返回自己的服务器端口号
return ResponseEntity.ok("测试数据" + request.getServerPort());
}
}
-
服务使用方
-
编写配置类,配置RestTemplate实例
package com.czxy.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * Created by liangtong. */ @Configuration public class HttpConfig { [@Bean](https://my.oschina.net/bean) @LoadBalanced //让RestTemplate支持负载均衡,也就是说支持“服务名”访问 public RestTemplate restTemplate(){ return new RestTemplate(); } }
-
步骤二:修改dao,使用RestTemplate进行远程调用时,使用“服务名”进行调用即可。
package com.czxy.controller; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; /** * Created by 澈 on 2019/12/10. */ @RestController @RequestMapping("/data") public class DataController { @Resource private RestTemplate restTemplate; @GetMapping public ResponseEntity<String> dataDemo01(){ //使用服务名进行访问 return restTemplate.getForEntity("http://service/test",String.class); } }
-
测试----未指定端口号,轮换访问两个服务器
-
来源:oschina
链接:https://my.oschina.net/u/4087782/blog/3140372