Spring Cloud Netflix简介
Spring Cloud Netflix是Spring Cloud组件的核心部分,其强大的功能也是微服务实现的基础。
-
Netflix Eureka:Cloud Load Balancing,一种基于REST的服务,用于定位服务以实现云中的负载均衡和中间层服务器的故障转移。
-
Netflix Hystrix:一种容错管理工具,旨在通过控制服务和第三方库的节点来为延迟和故障提供更大的容错能力。
-
Netflix Zuul:边缘服务工具,这是一种边缘服务,提供动态路由、监控、弹性、安全性等。
-
Netflix Archaius:配置管理API,包括一系列配置管理API,提供动态类型化属性、线程安全的配置操作、轮询框架、回调机制等功能。
-
负载均衡:
客户端负载均衡——Netflix Ribbon
服务端负载均衡:——Feign(其也是依赖于Ribbon,只是将调用方式RestTemplete 更改成Service 接口)
微服务架构面临的4个核心问题:
1. 服务很多,客户端该怎么访问?
2. 这么多服务,服务之间如何通信?
3. 这么多服务,如何治理?
4. 某个服务挂了怎么办?
Spring Cloud Netflix作为Spring Cloud家族的一员,就是用来解决这些问题的。
上图可以看出Netflix
是对外暴露的服务管理者接下来就从Netflix
组件开始认识微服务。
Eureka
服务注册和发现,它提供了服务注册中心、服务发现客户端以及查看所有已注册服务的便捷界面。所有服务都使用Eureka的服务发现客户端将自己注册到Eureka服务器上。
服务发现是基于微服务的架构的主要原则之一。尝试手动配置每个客户端或某种形式的约定可能会很困难且脆弱。 Eureka 是 Netflix 服务发现服务器和客户端。可以配置和部署服务器以实现高可用性,每个服务器将注册服务的状态复制到其他服务器。
Eureka包括Eureka,分为服务器组件和客户端组件:
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在后台界面中直观的看到。
Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就别一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
其他登记中心:
C:数据一致性
A:高可用性
P:分区容错性
1. Zookeeper是一个分布式服务框架,是Apache Hadoop的子项目。主要用于解决分布式应用中经常遇到的一些数据管理问题,例如:统一命名服务、状态同步服务、集群管理、分布式应用配置项管理等,其本质是存储+监控
2、Nacos是一个动态服务发现、配置管理和服务管理平台,可以让构建云原生应用变得更加容易。简单来说,Nacos就是注册中心+配置中心的组合,帮助我们解决微服务开发中必然会涉及到的服务注册与发现、服务配置、服务管理等问题。 Nacos是Spring Cloud阿里巴巴的核心组件之一,负责服务的注册和发现,以及配置。
3、Eureka由Netflix开源,并由Pivatal集成到SpringCloud系统中。它是基于RestfulAPI格式开发的服务注册和发现组件。
4、Consul是HashiCorp基于Go语言开发的一款服务发布和注册服务软件,支持多数据中心分布式、高可用的服务发布和注册。它使用Raft算法来保证服务一致性并支持健康检查。
服务注册
服务注册是基于注册中心的,所以需要先搭建注册中心。
- 创建一个新的模块项目
每个模块是一个独立的spring boot程序。
- 导入依赖项
分模块开发,父模块配置故要导入版本。(eureka-server 3.1.0和spring boot 2.6.9版本不冲突)在服务端模块即eureka_server
导入。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>3.1.0</version>
</dependency>
- 寄存器配置
配置eureka实例信息并修改相关配置以便更好的运行。
# 配置服务名称 == 注册中心server
spring.application.name=eureka_server
# 服务端口号
server.port= 9000
# 配置服务实例ip
eureka.instance.hostname=localhost
#是否将eureka注册到注册中心(本自身不注册)
eureka.client.register-with-eureka=false
#是否从eureka中获取注册地址(后台已ip显示而不是域名)
eureka.client.fetch-registry=false
# 配置eureka客户端要连接的服务端信息
eureka.client.service-url.defaultZone=http://localhost:9000/eureka/
# 注册中心实例配置
# 配置服务ip地址为localhost(默认为本机ip地址,导致本地无法访问)
eureka.instance.ip-address=localhost
# 配置后台Status显示格式
eureka.instance.instance-id=${eureka.instance.hostname}:${spring.application.name}:${server.port}
# 使用ip地址注册(默认域名)
eureka.instance.prefer-ip-address=true
- 配置启动类
spring 的配置都依赖于IoC容器的Bean来实例化,同理eureka的配置也需要借助配置类EurekaServerAutoConfiguration
。在启动程序中添加@EnableEurekaServer
注解使配置生效。详情见@EnableEurekaServer
@SpringBootApplication
//eureka 启动类
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
输入:http://localhost:9000
也能进入eureka后台系统
- 服务注册
注册中心搭建好之后就可以将服务注册到注册中心了,首先在bill_service
的pom导入服务端端依赖:
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.1.0</version>
</dependency>
配置服务器相关信息:
# 配置数据源相关信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/smbms?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=root
server.port=8081
# 关联注册中心
eureka.client.service-url.defaultZone=http://localhost:9000/eureka/
# 配置eureka的状态显示
eureka.instance.hostname=localhost
eureka.instance.instance-id=${eureka.instance.hostname}:${spring.application.name}:${server.port}
# 使用ip地址注册
eureka.instance.prefer-ip-address=true
# 配置服务的名称
spring.application.name=order_service
# 配置服务ip地址
eureka.instance.ip-address=localhost
# 忽略网卡的影响
#Npcap Loopback Adapter:为忽略的网卡名称
spring.cloud.inetutils.ignored-interfaces[0]=Npcap Loopback Adapte
另一个模块配置一致,最后启动,需要在启动类上添加eureka客户端的启动类@EnableDiscoveryClient
或者@EnableEurekaClient
:
@SpringBootApplication
@EnableDiscoveryClient
public class BillServiceApplication {
public static void main(String[] args) {
SpringApplication.run(BillServiceApplication.class, args);
}
}
只需启动注册中心和服务:
Eureka Server: 提供服务发现的能力,各个微服务启动时,会向Eureka Server注册信息,比如ip、端口、微服务名称等。 Eureka Server会存储这些信息
Eureka Client: Java 客户端,用于简化与Eureka Server的交互微服务启动后,会周期性(默认30S)向Eureka Server发送心跳以续约自己的“租期”
如果Eureka Server在一定时间内(默认90S)没有接收到某个微服务实例的心跳,Eureka Server将注销该实例。默认情况下,Eureka Server 同时也是 Eureka Client . 多个Eureka Server之间通过复制的方式来实现服务注册表中数据的同步
Eureka Client会缓存服务注册表中的信息,两个好处 第一,微服务无需每次都请求查询Eureka Server ,降低Server的压力。 第二,即使Eureka Server所有节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者并完成调用。
服务调用
首先确认服务本身没有问题,编写api接口、dao、pojo、service、controller等:
@RestController
@RequestMapping(value = "/provider")
public class ProviderController {
@Autowired
ProviderService providerService;
@GetMapping(value = "/{id}")
ProviderMessage getById(@PathVariable int id){
ProviderMessage byId = providerService.getById(id);
return byId;
}
}
服务没问题后就可以进行模块的调用了,模拟其他服务调用这两个服务的过程,首先必须明白在服务的代码中不允许高耦合型,也是就是不能出现http地址的类似代码。通过微服务的ServiceInstance
对象可以获取服务实例,而服务实例又包含了该服务的相关信息,因此服务测试模块也需要注册到注册中心。另外,RestTemaplte
对象可以从代码中访问api接口并获取实例对象。
创建一个新的测试模块:
将测试模块注册到注册中心(通过配置完成):
# 服务注册到注册中心
# 服务名称
spring.application.name=test_module
# 关联注册中心地址
eureka.client.service-url.defaultZone=http://localhost:9000/eureka/
# 配置服务端口
server.port=8083
# 配置实例主机名级相关信息
eureka.instance.hostname=localhost
eureka.instance.instance-id=${eureka.instance.hostname}:${spring.application.name}:${server.port}
# 是否使用ip注册
eureka.instance.prefer-ip-address=true
# 配置服务端ip地址
eureka.instance.ip-address=localhost
# 忽略多网卡对网卡的影响
spring.cloud.inetutils.ignored-interfaces[0]=Npcap Loopback Adapter
配置作为客户端的模块并启动客户端注解@EnableEurekaClient
实现,注入RestTempalte
对象
@SpringBootApplication
@EnableEurekaClient
public class TestModuleApplication {
//java代码访问url获取返回值的对象
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate(); }
public static void main(String[] args) {
SpringApplication.run(TestModuleApplication.class, args);
}
}
注意被调用的服务所有的java bean对象在测试服务也需要新建,如在bill_service
服务中又两个对象:
那么在测试模块中返回值用到了这两个对象,所以也需要新建。
最后编写测试模块的api接口:
@RestController
@RequestMapping(value = "/test")
public class TestController {
//获取服务中心实例
@Autowired
private DiscoveryClient discoveryClient;
//java代码访问api接口的实例对象
@Autowired
private RestTemplate restTemplate;
//bill_service的调用
@GetMapping(value = "/bill/{id}")
public BillMessage testMethod1(@PathVariable Integer id){
List<ServiceInstance> bill_service = discoveryClient.getInstances("bill_service");
//该服务只有一个
ServiceInstance instance = bill_service.get(0);
BillMessage billMessage = restTemplate.getForObject(instance.getUri() + "/bill/" + id, BillMessage.class);
return billMessage;
}
}
启动所有服务:
在测试模块调用bill_service服务:http://localhost:8083/test/bill/1
调用成功!微服务的注册与调用已基本完成、当前环境下需要什么服务就构建然后注册到注册中心就可以了,例如需要一个role_service则构建一个role_service的服务,通过配置注册到注册中心,通过@EnableEurekaClient
获取服务,通过RestTemplate
在java代码调用服务。
多注册中心
从上面的例子我们可以看出,只有一个注册中心是非常不安全的,因为它承担着非常重要的功能。所以一般有多个注册中心。
本地模拟多个注册中心:
复制eureka_server
模块,更改配置文件
将其他注册中兴的地址配置到每个注册中心,该部分是多注册中心的核心:
# 配置eureka客户端要连接的服务端信息
eureka.client.service-url.defaultZone=http://localhost:9000/eureka/,http://localhost:7000/eureka/,http://localhost:8000/eureka/
每个注册中心都可以分布式部署,从而增加多个注册中心,提高生产力和稳定性。
之前的注册中心,没有自己注册,后台看不到也获取不到注册中心信息。多注册中心模式需要自行注册并修改相关配置:
# 将本身注册到注册中心
eureka.client.register-with-eureka=true
到注册中心注册后启动服务如下:
在相互注册二时也是遇到了一个问题:Eureka 相互注册、仅显示对方或仅显示其中一个问题
相互注册完成后,注册中心模拟分布式就搭建完成了:
eureka在将自我注册时需要配置两个选项
eureka.client.service-url.defaultZone
追加自己路径,eureka.client.register-with-eureka=true
开启自我注册。
eureka.client.service-url
配置选项是指定eureka服务端的注册地址 ,这个是客户端使用的,告诉客户端服务端的地址,声明注册地址
相互注册主要依靠配置文件。两台eureka_server的配置文件如下:
# 配置服务名称 == 注册中心server
spring.application.name=eureka_server_copy
# 服务端口号
server.port=7000
# 配置服务实例ip
eureka.instance.hostname=machine2
#是否将eureka注册到注册中心(本自身注册)
eureka.client.register-with-eureka=true
#是否从eureka中获取注册地址(后台已ip显示而不是域名)
eureka.client.fetch-registry=false
# 配置eureka客户端要连接的服务端信息
eureka.client.service-url.defaultZone=http://127.0.0.1:9000/eureka/,http://127.0.0.1:7000/eureka/
# 注册中心实例配置
# 配置服务ip地址为localhost(默认为本机ip地址,导致本地无法访问)
eureka.instance.ip-address=localhost
# 配置后台Status显示格式
eureka.instance.instance-id=${eureka.instance.hostname}:${spring.application.name}:${server.port}
# 使用ip地址注册(默认域名)
eureka.instance.prefer-ip-address=true
# 配置服务名称 == 注册中心server
spring.application.name=eureka_server
# 服务端口号
server.port=9000
# 配置服务实例ip
eureka.instance.hostname=machine1
#是否将eureka注册到注册中心(本自身注册)
# 将本身注册到注册中心
eureka.client.register-with-eureka=true
#是否从eureka中获取注册地址(后台已ip显示而不是域名)
eureka.client.fetch-registry=false
# 配置eureka客户端要连接的服务端信息
eureka.client.service-url.defaultZone=http://127.0.0.1:7000/eureka/,http://127.0.0.1:9000/eureka/
# 注册中心实例配置
# 配置服务ip地址为localhost(默认为本机ip地址,导致本地无法访问)
eureka.instance.ip-address=localhost
# 配置后台Status显示格式
eureka.instance.instance-id=${eureka.instance.hostname}:${spring.application.name}:${server.port}
# 使用ip地址注册(默认域名)
eureka.instance.prefer-ip-address=true
服务同步
对于具有多个注册中心的微服务,当每个服务注册到注册中心时,这些服务如何在多个注册中心同步?
启动两个注册中心:
启动一个服务bill_service
该服务未进行任何修改,启动后刷新后台页面发现,两台服务器之间竟然自动同步了:
两个注册中心都有bill的服务,eureka注册的服务信息自动同步。
程序的bill服务的配置,是之注册到9000
这个端口的,也就是该地址下的系统自动同步到了7000
端口下的服务,同时服务注册也是只注册到9000端口的:
# 关联注册中心地址
eureka.client.service-url.defaultZone=http://localhost:9000/eureka/
这种依赖性是非常强的。服务都依赖于9000端口的服务,所以服务一般都会注册到所有的注册中心。步骤也非常简单。您只需将其他注册中心的地址添加到服务器注册地址中即可。能。
对于provider_service
注册地址配置如下:
eureka.client.service-url.defaultZone=http://localhost:9000/eureka/,http://localhost:7000/eureka/
启动服务
注册中心之间仍然同步服务的注册信息,效果是一样的,而且这样没有依赖的约束避免了主注册节点的影响。
配置文件可以修改eureka的很多设置,比如后台Status的显示格式、IP显示、服务续订等,都可以直接通过配置文件修改。
Eureka服务器原理
Spring Cloud 集成了Netflix OSS的多个项目,形成了spring-cloud-netflix项目。该项目包括以下几个项目:
Eureka提供REST服务,主要用于集群中的服务器。客户端组件实现负载均衡功能,创建业务组件集群部署的环境。该框架用于将业务组件分组到Eureka容器中,并自动维护和监控它们。
Eureka集群需要Eureka服务器。业务组件可以注册到Eureka服务器,其他客户端通过服务器获取服务并远程调用。
- 服务终端
注册到服务器的组件实例保存在注册中心,并通过心跳维护状态。客户端也有同样的机制。服务器端主要有以下任务。首先,向服务器端注册服务。其次,向服务器发送心跳。三、获取登记名单。