注册中心
什么是注册中心
注册中心是Spring Cloud和Spring Cloud Alibaba系列的第一步。服务的注册与发现是最基本的操作。
在微服务中,注册中心主要体现为三种角色。首先是服务注册中心,也就是Registry,用于保存服务提供者的注册信息,当服务提供者的节点发生变更的时候,注册中心也会同步的变更,服务消费者在感知到这个变更后,会刷新本地内存中所缓存的服务节点列表。
第二就是服务提供者(server),服务提供者在自身启动的时候,向Registry注册服务,并向注册中心定期发送心跳来确保注册中心认为该服务还活着。
最后,是服务消费者,启动的时候,服务消费者会从注册中心订阅服务,把注册中心返回的服务节点列表缓存在本地内存中,由此来和服务提供者建立联系。
服务消费者从本地缓存的服务节点列表中,基于负载均衡算法选择一个服务提供者的示例来发起调用。
常见的注册中心与注册中心需要的功能
由此,对于一个服务注册中心来说,首先,需要有一个服务注册的API接口,让服务的提供者通过调用该接口完成服务注册。
需要一个心跳检查的接口,服务提供方定期通过该接口汇报自身的服务状态。
此外,还需要一些如服务的查询、变更查询、注销等接口。
常见的注册中心比如nacos,eureka,zookeeper,ETCD等等。此处详细留痕常用的spring cloud的eureka和spring cloud alibaba的nacos。
Eureka
什么是Eureka
Eureka是Netflix开源的服务发现框架,Spring Cloud对其进行了集成,并提供了良好的支持。Eureka分为Eureka Server和Eureka Client,Eureka Server是注册中心,Eureka Client是服务提供者和服务消费者。
Eureka Server需要配置一个端口,用于接收Eureka Client的注册请求,同时,Eureka Server需要配置一个地址,用于接收Eureka Client的查询请求。
Eureka的架构
从总体来说,Eureka是一个CS架构的东西。主要由两个组件组成,Eureka Server与Eureka Client。Eureka Server是服务注册中心,用于存储所有可用的服务实例信息。Eureka Client是应用程序的客户端,用于向Eureka Server注册服务并查找其他服务。
在Eureka中,每个服务都可以注册为一个Eureka Client,并将自己的信息注册到Eureka Server中。当服务启动时,它会向Eureka Server发送一个心跳,告诉Eureka Server自己还活着。如果Eureka Server在一段时间内没有收到心跳,它将自动将该服务从注册表中删除。
Eureka的流程
首先是启动Server。
接着是启动Client。
服务启动后,Client会向Server注册自己的信息,发送一个包含服务实例ID,服务主机名端口,服务健康状态,服务元数据登的POST请求。
当Eureka Server收到这些消息后,就会储存这些消息实例的信息到服务注册表里。
其他服务可以通过Eureka Client以负载均衡的方式发现其他可用实例并选择一个进行请求。
服务实例可能会在运行的过程中更改其状态,例如服务实例的健康状态可能会更改。当服务实例状态更改时,服务会向Eureka Server发送一个PUT请求,以更新其状态信息。Eureka Server将根据收到的信息更新服务实例的状态。
当服务实例停止时,服务实例会向Eureka Server发送一个DELETE请求,以从注册表中删除自己的信息。Eureka Server将根据收到的信息从注册表中删除该服务实例的信息。
Eureka的实践
Eureka是集成进spring cloud了的,因此,使用起来非常简单。
Eureka服务端
首先需要有一个Eureka的服务端。通过IDEA快速创建Spring Boot项目,并且选择Eureka服务端,也可在Pom文件添加响应的依赖。(此外,还需要web相关的依赖,来确保eureka的服务端可以正常使用)
创建成功后,在spring boot的启动类上加入Eureka服务端的注解。
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
配置文件如下:
server.port=8761
spring.application.name=eureka
eureka.instance.hostname=localhost
eureka.instance.prefer-ip-address=true
eureka.server.wait-time-in-ms-when-sync-empty=0
eureka.server.enable-self-preservation=false
eureka.server.eviction-interval-timer-in-ms=60000
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=false
eureka.client.instance-info-replication-interval-seconds=10
eureka.client.registry-fetch-interval-seconds=30
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka
eureka.instance.instance-id=${spring.application.name}:${spring.cloud.client.ip-address}:${spring.application.instance_id:${server.port}}
eureka.instance.lease-expiration-duration-in-seconds=90
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
通用的不表,eureka.instance.prefer-ip-address=true是指示Eureka注册服务时,优先使用IP地址而不是主机名。
eureka.server.wait-time-in-ms-when-sync-empty=0表示的是Eureka服务器在启动阶段同步注册信息的时候,如果注册信息是空的,那么服务器所需要等待的时间(毫秒)。一般默认是5分钟。
eureka.server.enable-self-preservation=false是用于控制Eureka服务器是否启用自我保护模式。在自我保护模式下,Eureka会保护服务注册表中的信息,即使出现网络分区也不会注销任何服务实例。
eureka.server.eviction-interval-timer-in-ms=60000设置Eureka服务器清理无效服务实例的时间间隔(毫秒)。
eureka.client.register-with-eureka=true用于指示客户端是否向Eureka注册自己。
eureka.client.instance-info-replication-interval-seconds=10设置客户端将实例信息复制到Eureka服务器的间隔时间(秒)。
eureka.client.registry-fetch-interval-seconds=30设置客户端从Eureka服务器获取注册信息的间隔时间(秒)。
eureka.instance.lease-expiration-duration-in-seconds=90设置Eureka客户端续租到期时间(秒),即服务实例在多少秒内没有向Eureka服务器发送心跳,服务器会将该实例从注册表中删除。
如图所示为eureka注册中心的显示。
当想要自己对Eureka做操作时,通常可采用Eureka REST API或者编程方式。
Eureka客户端
客户端也非常容易。
还是使用IDEA创建Spring Boot项目,并且选择Eureka客户端依赖,也可在Pom中直接添加。
随后配置Eureka的服务端地址,还是采用Properties格式如下。
server.port=8889
spring.application.name=eureka-client
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
随后在启动类添加:
@SpringBootApplication
@EnableDiscoveryClient
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
启动后,访问Eureka注册中心,可以看到Eureka客户端已经注册到Eureka服务器上。(还是JAVA在这里好用哇……)
Eureka的REST API
GET /eureka/apps:获取所有注册的应用程序和实例信息。
GET /eureka/apps/{appID}:获取指定应用程序的所有实例信息。
GET /eureka/apps/{appID}/{instanceID}:获取指定应用程序和实例的详细信息。
POST /eureka/apps/{appID}:注册一个新的应用程序实例。
PUT /eureka/apps/{appID}/{instanceID}:更新指定应用程序和实例的信息。
DELETE /eureka/apps/{appID}/{instanceID}:注销指定应用程序和实例。
如图所示为请求/eureka/apps获得注册信息的图片。其他同理。
Eureka的编程方式
首先需要确保项目中包含了Eureka的客户端依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
然后就可以采用类似于如下的编程方式,来获得Eureka现在的相关信息。
首先是Service:
@Service
public class DiscoveryService {
@Resource
private DiscoveryClient discoveryClient;
// 获得对应服务的实例
public List<ServiceInstance> getServiceInstances(String serviceName) {
return discoveryClient.getInstances(serviceName);
}
// 获取所有服务ID
public List<String> getAllServices() {
return discoveryClient.getServices();
}
// 获取所有服务的所有服务实例
public Map<String, List<ServiceInstance>> getAllServiceInstances() {
return getAllServices().stream()
.collect(Collectors.toMap(
serviceId -> serviceId,
this::getServiceInstances
));
}
}
调用对应接口如下:
Nacos
什么是Nacos
Nacos是阿里巴巴开源的一个动态服务发现、配置管理和服务管理平台。Nacos提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。Nacos就是注册中心+配置中心,可以取代Eureka+Config。
Nacos的安装
Nacos的安装非常简单,只需要下载解压即可,下载地址:https://github.com/alibaba/nacos/releases
下载完成后,进入bin目录,执行以下命令启动Nacos:
startup.cmd -m standalone
启动完成后,访问http://localhost:8848/nacos
即可看到Nacos的界面。
此外,还可以采用Docker或Kubernetes的相关方式来安装启动nacos,暂按不表。
Nacos的实践
Nacos的实践与Eureka类似,这里不再赘述,详见Eureka的实践。
值得注意的是,@EnableDiscoveryClient这样一个注解,不止适用于Eureka作为注册中心,还适用于如Nacos等其他注册中心来使用。
Nacos的Open API
与Eureka相似,Nacos也提供一系列OpenAPI可供操作,详见Nacos OpenAPI指南:https://nacos.io/zh-cn/docs/open-api.html
Nacos的编程方式
Nacos的编程方式与Eureka相似,参见:https://github.com/gagaducko/springboot-nacosapi-example
此处为一个采用Nacos编程方式对注册中心信息进行获取与管理的示例,这里不再赘述。
Nacos与Eureka的优劣
Eureka专注于服务的注册与发现,而nacos即是注册中心,也是配置中心,支持动态的配置管理。在生态上,Nacos除了与Spring Cloud有良好的兼容性外,同时也支持Spring Cloud Alibaba生态系统,也适合在Kubernetes环境下部署使用。
此外,在扩展性上,Eureka支持水平扩展,在CAP中是AP模型,遵循高可用性,即便是部分节点通信失败也能继续注册和发现,缺点在于极端情况下节点的数据可能就会不一样了,短时间内不同步。而Nacos则支持AP与CP两种模式,即可选择高可用,也可以选择强一致。Nacos 在集群模式下可以通过 Raft 一致性协议保证强一致性
另外,Eureka相对来说比较轻量级,适合服务数量较少的场景,而Nacos则适合大规模的微服务集群开发,内存和储存消耗较高但是性能和功能的扩展性更强,对于多语言的支持也更好。
配置中心
为什么需要配置中心
配置文件是一个很让人熟悉的东西,尤其是对于Spring Boot项目来说,完善配置文件是相当重要的,比如Mysql在项目中的配置,Redis在项目中的配置,以及其他的一些可能会变更的配置。
对于一些复杂的环境下,当修改配置后,必须重启服务,否则配置无法生效,这是相当麻烦的,因此,这种省事儿的配置方法是不太好的,最好是能够直接在一个地方修改配置文件,项目读取这个配置文件,省去在配置信息有所变化的情况下,不断打包打镜像重启的繁杂工作。
Spring Cloud Config
Spring Cloud Config是spring cloud家族中最早的配置 中心,也分为配置中心服务端和配置中心客户端。
通过集成Spring Cloud Config,可以采用数据库、SVN、本地文件等作为配置的储存,以下就三块来做一下Config的实践。
实现最简单的配置中心服务端
当使用Spring Cloud Config的情况下,可以加入如此依赖来实验一个config的服务端。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
而后在启动类上注入:
@EnableConfigServer
接着在配置文件中做配置,可以采用git的方式,也可以采用本地的方式。
如git:
spring.application.name=spring-cloud-config-server
server.port=8080
# 使用git作为远程配置
spring.cloud.config.server.git.uri=https://github.com/gagaducko/learning_demos
spring.cloud.config.server.git.username=git username
spring.cloud.config.server.git.password=git password
spring.cloud.config.server.git.default-label=main
spring.cloud.config.server.git.search-paths=config-demo
此处以本地为例:
spring.application.name=spring-cloud-config-server
server.port=8080
# 用本地配置
spring.cloud.config.server.native.search-locations=D:/code_gagaduck/learning_demos/config-demo
配置完成后,启动服务端,访问http://localhost:8080/{application}/{profile}[/{label}],即可获取到配置信息。
如访问http://localhost:8080/test/properties,即可获取到test.properties的配置信息。
创建配置中心客户端使用配置
创建一个Spring Boot项目,引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
在配置文件中做配置:
spring.application.name=spring-cloud-config-client
server.port=8081
spring.config.import=optional:configserver:
spring.cloud.config.uri=http://localhost:8080
spring.cloud.config.name=test
spring.cloud.config.profile=properties
#spring.cloud.config.label=main
配置完成后,启动服务端,即可获取到配置信息。
需要注意的是,如果是git,是需要有label这些来定位的。另外,对于SpringBoot3.X来说,配置加载机制发生了变化,需要手动指定 spring.config.import 属性,以导入配置服务器的配置源。即,需要通过spring.config.import=optional:configserver:来明确指出从配置服务器导入配置
当然,也可以加上如下方法来禁用对这一个的检查:
spring.cloud.config.enabled=false
例如写个简单的controller检查一下:
@RestController
public class TestController {
@Value("${env}")
private String env;
@Value("${user.username}")
private String username;
@Value("${user.password}")
private String password;
@RequestMapping("/env")
public String env() {
return "env in test is: " + env;
}
@RequestMapping("/username")
public String username() {
return "username in test is: " + username;
}
@RequestMapping("/password")
public String password() {
return "password in test is: " + password;
}
}
调用http://localhost:8081/username,获得回复:
username in test is: gagaducko
在将Spring Cloud Config注册到注册中心的情况下,与其他服务进行通信
将Spring Cloud Config注册到注册中心后,很显然的是,要发挥注册中心的作用,避免客户端程序直接与配置中心的服务端做交互,而要通过注册中心来做交互,也就是说要避免直接对spring cloud config的ip端口在客户端中进行配置,而要通过Eureka来进行实现。
参考上文,将server服务注册到注册中心中,启用为一个Eureka客户端,对于其他服务来说,引入eureka的client依赖,并配置客户端服务:
# 配置服务地址通过注册中心发现
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.service-id=spring-cloud-config-server
# Eureka 注册中心地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
这样,客户端在启动的时候,会通过注册中心去发现配置中心的服务示例,并获取配置信息。
实现配置的自动刷新
在Spring Cloud Config中,在项目启动的额时候加载配置内容。这一机制导致当配置内容修改后不会自动刷新的,因此,需要重启。这样是不太好的。可以通过@RefreshScope注解并结合actuator来实现配置的自动刷新。
需要做如下配置,首先要映入spring-boot-starter-actuator这个包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
然后在配置文件中添加如下配置:
management.endpoints.web.exposure.include=*
在客户端程序中,通过如下方式来刷新配置:
@RefreshScope
例如:
@RestController
@RefreshScope
这样,便可以通过调用这样一个接口来实现刷新配置了:
http://localhost:8081/actuator/refresh
调用后,配置内容便刷新了。
比如,将test.properties中的内容的username变为gagaducko111:
username in test is: gagaducko111
此外,也可通过增加监听器自动刷新,此处暂按不表,见网关实现动态路由的部分。
Nacos
Nacos除了是注册中心,也是配置中心。
创建配置中心服务端
当Nacos安装Ok后,就可以作为配置中心进行使用。此处不表。
创建配置中心客户端使用配置
对于需要使用Nacos配置中心的客户端来说,使用方式也是简单的。
Nacos配置中心的Open API
与Nacos注册中心相似,Nacos也提供一系列OpenAPI可供对配置中心进行操作,详见Nacos OpenAPI指南:https://nacos.io/zh-cn/docs/open-api.html
Nacos配置中心的编程方式
对于Nacos配置中心来说,也可以使用与注册中心相似的编程方式进行操作,详见https://github.com/gagaducko/springboot-nacosapi-example
此为采用编程方式对Nacos配置中心进行管理使用的一种方式。