学习 eureka 第一要清楚的事儿
什么是服务治理?
在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,在这种情况下,我们就需要使用到服务治理了。管理服务与服务之间的依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册的技术。
什么是服务注册与发现?
- 在服务注册与发现中,有一个注册中心(eureka)。当服务器启动时,会把当前自己的服务器信息(列如:服务地址、通讯地址等)以别名的方式注册到注册中心上(生产者)。另一方(消费者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。
- 远程调用框架核心思想:在于注册中心,由于使用注册中心管理每个与服务之间的一个依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心(存放服务地址相关的信息:接口地址)。
eureka 包含两个组件:Eureka Server 和 Eureka Client
- Eureka Server 服务注册中心
各个微服务节点通过配置启动后,会在 Eureka Server 中进行注册,这样 Eureka Server 中的服务注册表中将存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。- Eureka Client 通过注册中心进行访问
是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中表把这个服务节点移除(默认90秒)
什么是 eureka
Eureka是基于REST(代表性状态转移)的服务,主要在AWS云中用于查找服务,以实现负载均衡和中间层服务器的故障转移。我们称此服务为Eureka Server。Eureka还带有一个基于Java的客户端组件Eureka Client,它使与服务的交互更加容易。客户端还具有一个内置的负载均衡器,可以执行基本的循环负载均衡。在Netflix,更复杂的负载均衡器将Eureka包装起来,以基于流量,资源使用,错误条件等多种因素提供加权负载均衡,以提供出色的弹性。

更详细关于 eureka :https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance
1. eureka 单机版配置
1.1 eureka 服务端
(1)建 module
(2)配置 pom
(3)配置 yml
(4)改主启动类
(5)访问 http://localhost:7001/ 查看是否配置成功
pom.xml 引依赖 spring-cloud-starter-netflix-eureka-server
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.test.wl</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<dependency>
<groupId>com.test.wl</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>3.0.2</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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
</project>
application-dev.yml
server:
port: 7001
eureka:
instance:
# eureka 服务端实例的名称
hostname: localhost
client:
# 服务端不注册自己
register-with-eureka: false
# 表明自己就是注册中心,我的职责是维护服务实例,不需要去检索服务
fetch-registry: false
# 设置与 eureka server 交互的地址查询服务和注册服务的地址
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
主启动类 EurekaServerMain7001.java 加 @EnableEurekaServer注解
package com.test.wl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author wl
* @date 2021年5月27日 08:47:02
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServerMain7001.class, args);
}
}
启动 module,访问 http://localhost:7001/

1.2 eureka 客户端
(1)建 module
(2)配置 pom
(3)配置 yml
(4)改主启动类
(5)访问 http://localhost:7001/ 查看是否配置成功
pom.xml 引依赖 spring-cloud-starter-netflix-eureka-client
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application-dev.yml 加配置
eureka:
client:
# 服务端不注册自己
register-with-eureka: true
# 表明自己就是注册中心,我的职责是维护服务实例,不需要去检索服务
fetch-registry: true
# 设置与 eureka server 交互的地址查询服务和注册服务的地址
service-url:
defaultZone: http://localhost:7001/eureka/
主启动类 EurekaServerMain7001.java 加 @EnableEurekaClient注解
package com.test.wl;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author wl
* @date 2021年5月25日 17:20:31
*/
@MapperScan("com.test.wl.*.mapper")
@SpringBootApplication
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
启动 module,访问 http://localhost:7001/

2. eureka 集群配置(我中有你,你中有我)
执行过程:
- 启动 Eureka 注册中心
- 启动 eureka server 微服务,相当于启动生产者服务,生产者将自身信息(列如服务地址)以别名方式注册到 Eureka 注册中心
- eureka client (消费者服务)在调用接口时,使用服务别名到注册中心获取真正的 RPC 远程调用地址
- 消费者获得调用地址后,底层利用 HttpClient 技术实现远程调用
- 消费者获得服务地址后会缓存在本地 JVM 内存中,默认每间隔30秒更新一次服务调用地址
在 hosts 文件中添加(模拟两台服务器)
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
注册中心:7001 / 7002
server:
port: 7001
eureka:
instance:
# eureka 服务端实例的名称
hostname: eureka7001.com
client:
# 服务端不注册自己
register-with-eureka: false
# 表明自己就是注册中心,我的职责是维护服务实例,不需要去检索服务
fetch-registry: false
# 设置与 eureka server 交互的地址查询服务和注册服务的地址
service-url:
defaultZone: http://eureka7002.com:7002/eureka/
server:
port: 7002
eureka:
instance:
# eureka 服务端实例的名称
hostname: eureka7002.com
client:
# 服务端不注册自己
register-with-eureka: false
# 表明自己就是注册中心,我的职责是维护服务实例,不需要去检索服务
fetch-registry: false
# 设置与 eureka server 交互的地址查询服务和注册服务的地址
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
生产者:8001 / 8002
eureka:
client:
# 服务端不注册自己
register-with-eureka: true
# 表明自己就是注册中心,我的职责是维护服务实例,不需要去检索服务
fetch-registry: true
# 设置与 eureka server 交互的地址查询服务和注册服务的地址
service-url:
defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/
instance:
#名称显示
instance-id: payment8001
#ip是否显示
prefer-ip-address: true
eureka:
client:
# 服务端不注册自己
register-with-eureka: true
# 表明自己就是注册中心,我的职责是维护服务实例,不需要去检索服务
fetch-registry: true
# 设置与 eureka server 交互的地址查询服务和注册服务的地址
service-url:
defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/
instance:
#名称显示
instance-id: payment8002
#ip是否显示
prefer-ip-address: true
消费者:80
server:
port: 80
eureka:
client:
# 服务端不注册自己
register-with-eureka: true
# 表明自己就是注册中心,我的职责是维护服务实例,不需要去检索服务
fetch-registry: true
# 设置与 eureka server 交互的地址查询服务和注册服务的地址
service-url:
defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/
设置默认负载均衡策略 @LoadBalanced

启动项目

访问:http://eureka7001.com:7001/ 或 http://eureka7001.com:7001/ 除 DS Replicas 外,其他一致

访问:http://localhost/payment/1
由于配置了负载均衡,所以生产者交替显示
{"code":200,"message":"操作成功!,serverPort:8001","data":{"id":1,"serial":"张三"}}
{"code":200,"message":"操作成功!,serverPort:8002","data":{"id":1,"serial":"张三"}}
3. 服务发现 discovery
- 启动类上加注解
@EnableDiscoveryClient- 使用 DiscoveryClient
PaymentController.java /8001
package com.test.wl.payment.controller;
import com.test.wl.payment.entity.Payment;
import com.test.wl.payment.service.PaymentService;
import com.test.wl.util.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author wl
* @date 2021年5月25日 22:33:31
*/
@RestController
@Slf4j
@RequestMapping("/payment")
public class PaymentController {
@Autowired
private PaymentService paymentService;
@Autowired
private DiscoveryClient discoveryClient;
@PostMapping("/create")
public CommonResult<Integer> createPayment(@RequestBody Payment payment) {
return paymentService.createPayment(payment);
}
@GetMapping("/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
return paymentService.selectById(id);
}
@GetMapping("/discovery")
public Object discovery() {
List<String> services = discoveryClient.getServices();
services.forEach(service -> log.info("service:" + service));
List<ServiceInstance> serviceInstances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
serviceInstances.forEach(serviceInstance -> log.info(serviceInstance.getServiceId() + " " + serviceInstance.getHost() + " "+ serviceInstance.getPort() + " " + serviceInstance.getUri()));
return this.discoveryClient;
}
}
访问:http://10.10.8.200:8001/payment/discovery
打印结果:
2021-05-31 09:24:37.094 INFO 16952 --- [nio-8001-exec-4] c.t.w.p.controller.PaymentController : service:cloud-payment-service
2021-05-31 09:24:37.094 INFO 16952 --- [nio-8001-exec-4] c.t.w.p.controller.PaymentController : service:cloud-order-service
2021-05-31 09:24:37.095 INFO 16952 --- [nio-8001-exec-4] c.t.w.p.controller.PaymentController : CLOUD-PAYMENT-SERVICE 10.10.8.200 8001 http://10.10.8.200:8001
2021-05-31 09:24:37.095 INFO 16952 --- [nio-8001-exec-4] c.t.w.p.controller.PaymentController : CLOUD-PAYMENT-SERVICE 10.10.8.200 8002 http://10.10.8.200:8002
4. eureka 自我保护机制
- 默认情况下,如果Eureka Server在必定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例。但是当网络分区故障(延时、卡顿、拥挤)发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时 eureka 则不会移除这个微服务,启用自我保护机制。
- 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例,宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
如果 eureka 页面出现如图所示的情况,说明 eureka 开启了自我保护机制。

关闭 eureka 自我保护机制
application-dev.yml: /7001 生产者
server:
#自我保护机制,默认为true
enable-self-preservation: false
#清理间隔(单位:毫秒,默认是60*1000),当服务心跳失效后多久,删除服务
eviction-interval-timer-in-ms: 2000
application-dev.yml: /8001 消费者
instance:
#名称显示
instance-id: payment8001
#ip是否显示
prefer-ip-address: true
# Eureka客户单向服务端发送心跳的时间间隔,默然是30秒
lease-renewal-interval-in-seconds: 1
# Eureka服务端在收到最后一次心跳后等待时间上限,默然为90秒,超时将剔除服务
lease-expiration-duration-in-seconds: 2
关闭之后的效果:


跟尚硅谷大佬(阳哥)一起学 springcloud
视频链接:https://www.bilibili.com/video/BV18E411x7eT?from=search&seid=11397380345672811627
参考自:https://blog.csdn.net/MiSiTeLin/article/details/114930670
我的项目地址:https://gitee.com/wl_projects/springcloud.git


