【Spring Cloud一】微服务基本知识
目前公司项目使用的注册中心主要是Spring Cloud Alibaba的Nacos做的注册中心和配置中心。之前也是对Nacos的基本原理通过手写代码的方式进行了实现。出于对于Eureka的好奇所以就对Spring Cloud Neflix的Eureka进行理论学习和实践。
Eureka是一个注册发现中心,Eureka是Netflix公司开源的一个服务注册与发现的组件。
Eureka是Netflix贡献给Spring Cloud的一个框架,Eureka和其他Netflix公司的服务组件一起被Spring Cloud社区整合为Spring Cloud Netflix模块。
在过去传统的架构中,两个服务之间进行跨服务调用的常用方式是直接调用。但是随着系统的规模和复杂性的增加。直接调用的方式存在一些局限性,所以就引入了服务注册发现中心来解决这些问题。
动态性和伸缩性:在传统的直接调用中,服务之间的连接通常是硬编码的方式。例如:在A服务里面需要编码上B服务提供URL,来发送调用请求。如果服务实例数量发生变化,那么就需要手动修改代码或者配置来适应新的实例。
而服务注册和服务发现允许服务动态注册和注销,从而使系统根据实际情况自动进行调整和适应变化。
高可用性和容错性:在直接调用方式中,如果某个服务实例不可用,调用方可能会面临连接失败或错误。**而服务注册和服务发现可以让调用方获取到多个可用的服务实例,**并后序结合Ribbon实现负载均衡,从而提高系统的可用性和容错性。
整个系统有一台Eureka服务端,有一台服务提供者B和一台服务消费者A(都集成了Eureka客户端)。
整体实现的效果是:
当服务提供者B和服务消费者A启动时,会将自己的注册信息注册到Eureka服务端中。
我们在服务消费者中根据服务提供者B的应用程序名,通过Eureka客户端向Eureka服务端发送获取服务提供者B的注册信息。
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.12.RELEASEversion>
<relativePath/>
parent>
<groupId>com.wangweigroupId>
<artifactId>eureka-server01artifactId>
<version>0.0.1-SNAPSHOTversion>
<name>erueka-server01name>
<description>eureka-server01description>
<properties>
<java.version>8java.version>
<spring-cloud.version>Hoxton.SR12spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
#单机版配置
server:
port: 8761 #eureka的默认端口
spring:
application:
name: eureka-server #应用名称 不要使用特殊字符
eureka: #eureka的配置分为三类 server client 实例的 eurka-server即是服务端又是客户端
server:
eviction-interval-timer-in-ms: 10000 #服务端间隔多少毫秒做定期删除操作
renewal-percent-threshold: 0.85 #续约百分比 超过85%的应用没有和你续约 那么eureka会保护服务 不会剔除任何一个服务
instance: #实例的配置
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
hostname: localhost #主机名称或者服务ip
prefer-ip-address: true #以ip的形式显示具体的服务信息
lease-renewal-interval-in-seconds: 5 #服务实例的续约时间间隔
启动类上添加开启Eureka注册中心的功能
@SpringBootApplication
@EnableEurekaServer//开启eureka的注册中心的功能
public class EruekaServer01Application {
public static void main(String[] args) {
SpringApplication.run(EruekaServer01Application.class, args);
}
}
访问:http://localhost:8761/
可以看到已经将服务端进行了注册
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.12.RELEASEversion>
<relativePath/>
parent>
<groupId>com.wangweigroupId>
<artifactId>eureka-client-bartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>eureka-client-bname>
<description>eureka-client-bdescription>
<properties>
<java.version>8java.version>
<spring-cloud.version>Hoxton.SR12spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
server:
port: 8081
spring:
application:
name: eureka-client-b
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
register-with-eureka: true #设置为fasle 不往eureka-server注册
fetch-registry: true #应用是否拉取服务列表到本地
registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答
instance: #实例的配置
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
hostname: localhost #主机名称或者服务ip
prefer-ip-address: true #以ip的形式显示具体的服务信息
lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔
添加开启Eureka客户端的注解
@SpringBootApplication
@EnableEurekaClient
public class EurekaClientBApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientBApplication.class, args);
}
}
可以看到eureka-client-b已经注册到了Eureka服务端上。
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.12.RELEASEversion>
<relativePath/>
parent>
<groupId>com.wangweigroupId>
<artifactId>eureka-client-aartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>eureka-client-aname>
<description>eureka-client-adescription>
<properties>
<java.version>8java.version>
<spring-cloud.version>Hoxton.SR12spring-cloud.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
register-with-eureka: true #设置为fasle 不往eureka-server注册,默认为true
fetch-registry: true #应用是否拉取服务列表到本地
registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答
instance: #实例的配置
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
hostname: localhost #主机名称或者服务ip
prefer-ip-address: true #以ip的形式显示具体的服务信息
lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔
在启动类上添加开启Eureka客户端的注解
@SpringBootApplication
@EnableEurekaClient
public class EurekaClientAApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientAApplication.class, args);
}
}
@RestController
public class DiscoveryController {
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("test/{serviceName}")
public String Discovery(@PathVariable String serviceName){
//这就是服务发现 通过服务应用名称 找到服务的具体信息
List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
ServiceInstance serviceInstance = instances.get(0);
String ip=serviceInstance.getHost();
int port=serviceInstance.getPort();
System.out.println(ip+port);
return ip+port;
}
}
通过调用test接口,我们可以看到通过服务应用名称,可以找到注册到Eureka上服务的具体信息。
我们将服务B进行下线处理之后,我们可以看到Eureka服务端已经将其剔除。
server:
port: 8761 #eureka的默认端口
spring:
application:
name: eureka-server #应用名称 不要使用特殊字符
eureka:
client:
service-url: #eureka服务端和客户端的交互地址,不写的话默认是 8761,集群的话地址用,隔开。
defaultZone: http://peer2:8762/eureka,http://peer3:8763/eureka
fetch-registry: true #是否拉取服务列表
register-with-eureka: true #是否注册自己(单击eureka一般关闭注册自己,集群需要开启)
server:
eviction-interval-timer-in-ms: 10000 #服务端间隔多少毫秒做定期删除操作,清楚无效阶段的频率
renewal-percent-threshold: 0.85 #续约百分比 超过85%的应用没有和你续约 那么eureka会保护服务 不会剔除任何一个服务
enable-self-preservation: true #server的自我保护机制,避免因为网络原因造成误剔除。
instance: #实例的配置
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
hostname: peer1 #主机名称或者服务ip
prefer-ip-address: true #以ip的形式显示具体的服务信息
lease-renewal-interval-in-seconds: 5 #服务实例的续约时间间隔
lease-expiration-duration-in-seconds: #表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间
按照Eureka服务端再新建两个Eureka服务端,主要的区别在于配置文件中的配置。
通过下面图:我们可以看出Eureka集群中的Eureka服务是彼此相互服务注册和互相服务发现。这样做的好处是如果我其中一台Eureka服务宕机了。我的集群能够立即的提供服务,这是一种去中心化的思想。与常见的主从模式的集群不同,如果主从模式中的集群中的主服务宕机,那么是不能够立即提供完整的服务的,它需要一定的选举机制,再次选出一个主服务器之后才能提供完整的服务,这期间有一段的时间整个集群是无法提供完整服务的。
#集群版
server:
port: 8761 #eureka的默认端口
spring:
application:
name: eureka-server #应用名称 不要使用特殊字符
eureka:
client:
service-url: #eureka服务端和客户端的交互地址,不写的话默认是 8761,集群的话地址用,隔开。
defaultZone: http://peer2:8762/eureka,http://peer3:8763/eureka
fetch-registry: true #是否拉取服务列表
register-with-eureka: true #是否注册自己(单击eureka一般关闭注册自己,集群需要开启)
registry-fetch-interval-seconds: 10 #定期拉取注册信息 为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗越大
server:
eviction-interval-timer-in-ms: 10000 #服务端间隔多少毫秒做定期删除操作,清楚无效阶段的频率
renewal-percent-threshold: 0.85 #续约百分比 超过85%的应用没有和你续约 那么eureka会保护服务 不会剔除任何一个服务
enable-self-preservation: true #server的自我保护机制,避免因为网络原因造成误剔除。
instance: #实例的配置
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
hostname: peer1 #主机名称或者服务ip
prefer-ip-address: true #以ip的形式显示具体的服务信息
lease-renewal-interval-in-seconds: 5 #服务实例的续约时间间隔
lease-expiration-duration-in-seconds: #表示eureka server至上一次收到client的心跳之后,等待下一次心跳
#集群版
server:
port: 8762
spring:
application:
name: eureka-server #应用名称 不要使用特殊字符
eureka:
client:
service-url: #eureka服务端和客户端的交互地址,不写的话默认是 8761,集群的话地址用,隔开。
defaultZone: http://peer1:8761/eureka,http://peer3:8763/eureka
fetch-registry: true #是否拉取服务列表
register-with-eureka: true #是否注册自己(单击eureka一般关闭注册自己,集群需要开启)
registry-fetch-interval-seconds: 10 #定期拉取注册信息 为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消
server:
eviction-interval-timer-in-ms: 10000 #服务端间隔多少毫秒做定期删除操作,清楚无效阶段的频率
renewal-percent-threshold: 0.85 #续约百分比 超过85%的应用没有和你续约 那么eureka会保护服务 不会剔除任何一个服务
enable-self-preservation: true #server的自我保护机制,避免因为网络原因造成误剔除。
instance: #实例的配置
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
hostname: peer2 #主机名称或者服务ip
prefer-ip-address: true #以ip的形式显示具体的服务信息
lease-renewal-interval-in-seconds: 5 #服务实例的续约时间间隔
lease-expiration-duration-in-seconds: 5 #表示eureka server至上一次收到client的心跳之后,等待下一次心跳
#集群版
server:
port: 8763
spring:
application:
name: eureka-server #应用名称 不要使用特殊字符
eureka:
client:
service-url: #eureka服务端和客户端的交互地址,不写的话默认是 8761,集群的话地址用,隔开。
defaultZone: http://peer1:8761/eureka,http://peer2:8762/eureka
fetch-registry: true #是否拉取服务列表
register-with-eureka: true #是否注册自己(单击eureka一般关闭注册自己,集群需要开启)
registry-fetch-interval-seconds: 10 #定期拉取注册信息 为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消
server:
eviction-interval-timer-in-ms: 10000 #服务端间隔多少毫秒做定期删除操作,清楚无效阶段的频率
renewal-percent-threshold: 0.85 #续约百分比 超过85%的应用没有和你续约 那么eureka会保护服务 不会剔除任何一个服务
enable-self-preservation: true #server的自我保护机制,避免因为网络原因造成误剔除。
instance: #实例的配置
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
hostname: peer3 #主机名称或者服务ip
prefer-ip-address: true #以ip的形式显示具体的服务信息
lease-renewal-interval-in-seconds: 5 #服务实例的续约时间间隔
lease-expiration-duration-in-seconds: 5 #表示eureka server至上一次收到client的心跳之后,等待下一次心跳
#集群版
server:
port: 8080
spring:
application:
name: eureka-client-a
eureka:
client:
service-url:
defaultZone: http://peer1:8761/eureka,http://peer2:8762/eureka,http://peer3:8763/eureka #集群中的所有服务地址,这样可以保证如果有一个服务宕机,还可以使用其他服务
register-with-eureka: true #设置为fasle 不往eureka-server注册
fetch-registry: true #应用是否拉取服务列表到本地
registry-fetch-interval-seconds: 10 #定期拉取注册信息 为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答
instance: #实例的配置
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
hostname: localhost #主机名称或者服务ip
prefer-ip-address: true #以ip的形式显示具体的服务信息
lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔
lease-expiration-duration-in-seconds: 5 #表示eureka server至上一次收到client的心跳之后,等待下一次心跳
##集群版
server:
port: 8081
spring:
application:
name: eureka-client-b
eureka:
client:
service-url:
defaultZone: http://peer1:8761/eureka,http://peer2:8762/eureka,http://peer3:8763/eureka #集群中的所有服务地址,这样可以保证如果有一个服务宕机,还可以使用其他服务
register-with-eureka: true #设置为fasle 不往eureka-server注册
fetch-registry: true #应用是否拉取服务列表到本地
registry-fetch-interval-seconds: 10 #定期拉取注册信息 为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答
instance: #实例的配置
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
hostname: localhost #主机名称或者服务ip
prefer-ip-address: true #以ip的形式显示具体的服务信息
lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔
lease-expiration-duration-in-seconds: 5 #表示eureka server至上一次收到client的心跳之后,等待下一次心跳
这里我们同样调用test接口进行测试。可以看到是可以获取服务B的注册信息的。
如果我们这是我们将集群中的Eureka服务下线一台依旧是可以提供服务的,不会有任何影响
以上就是Eureka的基本内容了,Eureka提供的服务主要是服务注册和服务发现。分别介绍了单机版、集群版、以及Eureka的常用配置。
对于Eureka的配置其实大部分都是有默认配置的。我们可以在EurekaClientConfigBean、EurekaServerConfigBean、EurekaInstanceConfigBean这三个类中去进行了解。