本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1、Eureka基础知识
1.1、什么是服务治理?
在传统的rpc
远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。
SpringCloud
封装了Netflix
公司开发的Eureka
模块来实现服务治理。
1.2、什么是服务注册与发现?
Eureka Server
作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka
的客户端连接到Eureka Server
并维持心跳连接。这样系统的维护人员就可以通过Eureka Server
来监控系统各个微服务是否正常运行。
服务注册与发现
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息,比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者、服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC
调用RPC
。远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc
远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))。
1.3、Eureka两大组件
Eureka
包含两个组件:Eureka Server
和Eureka Client
。
Eureka Server
:提供服务注册服务,各个微服务节点通过配置启动后,会在Eureka Server
中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。Eureka Client
:通过注册中心进行访问。是一个Java客户端,用于简化Eureka Server
的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server
发送心跳(默认周期为30秒)。如果Eureka Server
在多个心跳周期内没有接收到某个节点的心跳,Eureka Server
2、单机Eureka构建步骤
1. 建Module
- 名称为
cloud-eureka-server7001
2. 改POM
<?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>cloud02</artifactId>
<groupId>com.xiao</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>com.xiao</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
复制代码
3. 改YML
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名字
client:
#表识不向注册中心注册自己
register-with-eureka: false
#表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
复制代码
4. 主启动
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
复制代码
5. 测试结果
6. 包结构截图
3、支付模块入驻Eureka Server
1. 建Module
- 前面已经写过支付模块,直接拿来使用。名称为
cloud-provider-payment8001
。
2. 改POM
新增的内容
<!--新添加的依赖-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
复制代码
3. 改YML
新增的内容
# 新添加的内容
eureka:
client:
# 标识自己要入驻 Eureka Server
register-with-eureka: true
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
复制代码
4. 主启动
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
复制代码
5. 测试结果
4、订单模块入驻Eureka Server
1. 建Module
- 前面已经写过订单模块,直接拿来使用。名称为
cloud-consumer-order80
。
2. 改POM
新增的内容
<!--新添加的依赖-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
复制代码
3. 改YML
新增的内容
spring:
application:
name: cloud-order-service
eureka:
client:
register-with-eureka: true
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
复制代码
4. 主启动
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
复制代码
5. 测试结果
5、集群Eureka构建
5.1、Eureka工作原理
- 先启动
eureka
注册中心 - 启动服务提供者
payment
支付服务 - 支付服务启动后会把自身信息(比如服务地址以别名方式注册进
eureka
) - 消费者
order
服务在需要调用接口时,使用服务别名去注册中心获取实际的RPC
远程调用地址。 - 消费者获得调用地址后,底层实际是利用
HttpClient
技术实现远程调用。 - 消费者获得服务地址后会缓存在本地
jvm
中,默认每间隔30
秒更新一次服务调用地址。
5.2、Eureka集群原理说明
- 多个
Eureka Server
相互注册,互相守望,对外呈现一个Eureka
服务,从而实现高可用。
5.3、Eureka集群搭建步骤
1. 准备工作
在主机中修改对应的映射文件
添加的内容为
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
复制代码
2. 建Module
- 新建
Module
,名称为cloud-eureka-server7002
。
3. 改POM
cloud-eureka-server7002
的pom
文件不变,cloud-eureka-server7002
的pom
文件和cloud-eureka-server7001
的相同。
4. 改YML
cloud-eureka-server7001
的YML
文件
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名字
client:
register-with-eureka: false #表识不向注册中心注册自己
fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://eureka7002.com:7002/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
复制代码
cloud-eureka-server7002
的YML
文件
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com #eureka服务端的实例名字
client:
register-with-eureka: false #表识不向注册中心注册自己
fetch-registry: false #表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ #设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址
复制代码
5. 主启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class,args);
}
}
复制代码
6. 测试结果
5.4、将支付模块入驻Eureka Server
将yml
文件修改为以下内容
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
eureka:
client:
# 标识自己要入驻 Eureka Server
register-with-eureka: true
fetchRegistry: true
#defaultZone: http://localhost:7001/eureka 单机版
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.xiao.cloud.entities
复制代码
5.5、将订单模块入驻Eureka Server
将yml
文件修改为以下内容
server:
port: 80
spring:
application:
name: cloud-order-service
eureka:
client:
register-with-eureka: true
fetchRegistry: true
service-url:
#defaultZone: http://localhost:7001/eureka 单机版
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
复制代码
5.6、支付服务提供者的集群搭建步骤
1. 新建一个名称为新建cloud-provider-payment8002的 Module
- 其与
cloud-provider-payment8001
唯一不同的就是yml
文件的端口号为8002
。
2. 对支付模块的controller类进行修改
import com.xiao.cloud.entities.CommonResult;
import com.xiao.cloud.entities.Payment;
import com.xiao.cloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
@RestController
@Slf4j
public class PaymentController {
@Autowired
private PaymentService paymentService;
@Value("${server.port}")
private String ServerPort;
@PostMapping("/payment/create")
public CommonResult create(@RequestBody Payment payment){
int result = paymentService.create(payment);
log.info("*****插入结果为:" + result);
if(result > 0){
return new CommonResult(200,"插入数据库成功,端口号为:" + ServerPort,result);
}else {
return new CommonResult(444,"插入数据库失败",null);
}
}
@GetMapping("/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("*****查询结果为:" + payment);
if(payment != null){
return new CommonResult(200,"查询数据库成功,端口号为:" + ServerPort,payment);
}else {
return new CommonResult(444,"查询数据库失败,没有对应记录,id为:" + id,null);
}
}
}
复制代码
- 当进行查询的时候将端口号也进行输出。
- 除上述修改以外,其他部分都和
cloud-provider-payment8001
相同。
3. 对订单模块的controller类中的URL进行修改
public static final String URL = "http://CLOUD-PAYMENT-SERVICE";
复制代码
- 这里我们通过微服务的名称进行访问。
4. 对订单模块的配置类进行修改
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;
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
复制代码
- 多添加了一个
@LoadBalanced
注解,从而实现负载均衡。
5. 测试结果
多次使用订单模块对支付模块进行调用,每次调用的端口号不尽相同。从而实现负载均衡。
5.7、actuator微服务信息完善
在cloud-provider-payment8001
和cloud-provider-payment8002
的yml
配置文件中加入以下内容
eureka:
instance:
instance-id: payment8001 # 如果是cloud-provider-payment8002,则此处为payment8002
prefer-ip-address: true
复制代码
- 对服务名称进行修改。
- 并且在访问的时候有
ip
显示。
5.8、服务发现Discovery配置
1. 用途
- 我们可以通过
Discovery
配置来获取服务的相关详细信息。
2. 在Controller类上新添的内容
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/payment/discovery")
public Object discovery(){
List<String> services = discoveryClient.getServices();
for (String service : services) {
log.info("*****服务:" + service);
}
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info("****详细信息:" + instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
}
return this.discoveryClient;
}
复制代码
3. 在主启动类上新加的注解
@EnableDiscoveryClient
复制代码
4. 测试结果
5.9、Eureka自我保护
5.9.1、现象
5.9.2、自我保护机制的内容
- 一句话:某时刻某一个微服务不可用了,
Eureka
不会立刻清理,依旧会对该微服务的信息进行保存。 - 属于
CAP
里面的AP
分支。 - 自我保护机制是一种应对网络异常的安全保护措施。
5.9.3、为什么需要自我保护机制?
- 为了防止
EurekaClient
可以正常进行,但是与EurekaServer
网络不通情况下,EurekaServer
不会立刻将EurekaClient
服务剔除。
5.9.4、怎么进制自我保护?
在Eureka服务端yml文件中加入下述内容
eureka:
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
复制代码
在Eureka客户端yml文件加入下述内容
eureka:
instance:
# Eureka客户端向服务端发送心跳的时间间隔,单位为秒
lease-expiration-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒,超时将剔除服务
lease-expiration-duration-in-seconds: 2
复制代码