微服务的注册中心
1 什么是注册中心
1.1 定义
-
注册中心是微服务架构中最基础也是最重要的组件
-
注册中心本质上是为了解耦微服务
-
注册中心主要用于提供服务的发现与注册
-
注册中心相当于微服务之间的通讯录,记录着所有微服务的地址
-
注册中心能实现微服务之间的相互调用
1.2 举例
现在有一组服务器集群
随着各个服务的业务需求越来越大,就需要给各个模块添加服务器
此时就需要一个集中的管理对象——注册中心
注册中心能实现自动注册各个服务器,一旦服务器上线,就会被自动注册到注册中心,一旦服务器下线,就会被自动从注册中心剔除
有了注册中心,就可以根据业务需求给业务模块增加服务器,毕竟算力不够就加服务器嘛,增加服务器后,注册中心自动上线服务器,不需要这么多服务器时,也可以手动下线服务器
2 常见的注册中心
有Eureka、Consul、Nacos、Zookeeper,前三者属于springcloud体系,最后一个属于double类体系,两种体系代表两种注册中心实现方案,虽然是不同的方案,但是最终实现的效果相同
这几个注册中心对比如下
Eureka | Nacos | Consul | Zookeeper | |
---|---|---|---|---|
CAP | AP | CP/AP | CP | CP |
雪崩保护 | 有 | 有 | 无 | 无 |
创建方式 | 内部项目 | 外部程序 | 外部程序 | 外部程序 |
版本状态 | 停止升级 | 版本迭代 | 版本迭代 | 版本迭代 |
文档 | 英文 | 英文 | 中文 | 英文 |
SpringCloud集成 | 支持 | 支持 | 支持 | 不支持 |
Dubbo集成 | 支持 | 不支持 | 不支持 | 支持 |
3 CAP理论
CAP理论是分布式系统中一个很重要的理论,它描述的是一个分布式系统最多只能满足CAP中的两个条件,不可能同时满足三个条件
三种条件中,P通常都有,所以一般只分为CP和AP
- C(Consistency):这里指的是强一致性。保证在一定时间内,集群中的各个节点会达到较强的一致性,同时,为了达到这一点,一般会牺牲一点响应时间。而放弃C也不意味着放弃一致性,而是放弃强一致性。允许系统内有一定的数据不一致情况的存在
- A (Avalibility):可用性。意味着系统一直处于可用状态。个别节点的故障不会影响整个服务的运作,可以理解为容错率更高
- P(Partition Tolerance):分区容忍性。当系统出现网络分区等情况时,依然能对外提供服务。想到达到这一点,一般来说会把数据复制到多个分区里,来提高分区容忍性。这个一般是不会被抛弃的
4 Eureka
4.1 介绍
Eureka是Netflix开发的服务发现框架,它是Spring Cloud Netflix微服务套件中的一部分,它是基于Netflix Eureka二次开发的项目,可以更好的与SpringBoot进行集成。
Eureka用于提供服务的注册与发现,它通过心跳机制和全/增量更新来维护所有的服务和客户端列表,同时也默认提供高可用集群方案。
Spring Cloud Eureka本身也是一个基于SpringBoot扩展的子项目,启动以及配置等信息写法完全与SpringBoot一致。
创建Spring Cloud Eureka项目与创建SpringBoot一样简单快速。
Eureka已经不升级了,但是还有很多公司在使用
4.2 Eureka服务端
4.2.1 创建服务端
首先创建eureka服务端,也就是注册中心
通过springboot骨架创建eureka服务端,作为服务端,只需要加入eureka server
此时整个项目的pom文件中就会自动引入eureka的依赖
接着只需要在springboot启动类上使用注解@EnableEurekaClient即可开启eureka服务端
4.2.2 配置eureka服务端的yml
4.2.2.1 配置eureka服务端的端口
此时启动springboot,控制台会显示eureka在请求重连
原因就是还没有按照官方说明配置yml,按照官方文档说明配置即可
其中设置端口别名时并不会按照官方的标准来写,因为一个项目中还有其他的配置,为了进行区分,要修改为如下配置
最终配置
在配置好之后,可以发现还是会报这个错误,但是不影响使用,是因为整个springboot项目启动时,eureka首次启动在eureka被注册到springboot之前,此时肯定会报错,等springboot启动完成,并将eureka注册成功后,eureka会再次启动,此时就正常运行了
所以,在一切配置顺利的情况下,这个错误是必定会发送但只会发生一次
4.2.2.2 eureka服务端其他常用配置
配置 | 说明 |
---|---|
eureka.instance.hostname | 修改当前主机名称 |
eureka.instance.appname | 修改当前实例名称。实例名称用作在监控页面显示 |
eureka.client.registerWithEureka(或eureka.client.register-with-eureka) | 是否注册自身到Eureka服务器。如果是单台且当前应用本身就是服务器,则可以把值设置为false |
eureka.client.fetchRegistry(或eureka.client.fetch-registry) | 是否从Eureka服务器获取注册信息。如果是单台且当前应用就是服务器,则可以把值设置为false |
spring.application.name [常用] | 声明当前应用名称,可作为监控网页的显示 |
4.3 Eureka服务监控网页
4.3.1 栏目介绍
配置好yml后,直接启动springboot项目,此时就可以通过本机ip+8761端口访问eureka的服务监控网页
System Status(注册中心基本信息)
属性 | 说明 |
---|---|
Environment | 指定环境,默认为test,可以不改 |
Data center | 数据中心 |
Current time | 当前系统时间 |
Uptime | 已运行时长 |
Lease expiration enabled | 是否启用租约过期。自我保护机制关闭时,该值默认是true,自我保护机制开启之后为false |
Renews threshold | server 期望在每分钟中收到的心跳次数 |
Renews (last min) | 上一分钟内收到的心跳次数 |
DS Replicas(注册中心基本信息)
属性 | 说明 |
---|---|
Instances currently registered with Eureka | 当前已注册到注册 |
General Info (当前服务器基本信息)
属性 | 说明 |
---|---|
total-avail-memory | 总共可用的内存 |
environment | 环境名称,默认test |
num-of-cpus | CPU个数 |
current-memory-usage | 当前已经使用内存的百分比 |
server-uptime | 服务在线时间 |
registered-replicas | 相邻集群复制节点 |
unavailable-replicas | 不可用的集群复制节点 |
available-replicas | 可用的相邻集群复制节点 |
Instance Info(当前实例基本信息)
属性 | 说明 |
---|---|
ipAddr | 实例ip |
status | 实例状态 |
4.3.2 监控网页上的红字提醒
Spring Eureka 服务注册中心在三种情况下会出现红色加粗的字体提示:
- 自我保护机制开启时(enable-self-preservation: true):
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
- 自我保护机制关闭时(enable-self-preservation: false):
RENEWALS ARE LESSER THAN THE THRESHOLD. THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
- 自我保护机制关闭了,但是一分钟内的续约数没有达到85%,可能发生了网络分区,会有如下提示
THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.
4.4 Eureka客户端
4.4.1 说明
所谓客户端,就是配置了Eureka接口的tomcat服务器,实际开发中,每一个业务模块的每一个节点都应该是一个单独的项目,单独放在一台服务器上,分别对应一个eureka客户端,但那得是超大型项目,更多的是一台服务器上放一个业务模块,一个业务模块就是一个springcloud项目,然后通过启动多个tomcat服务器实现多线程处理当前业务模块,从而充分利用服务器的cpu和内存
下面为了便于学习,仅在一台电脑上的一个springcloud项目中创建多个业务模块,每个业务模块对应一个eureka客户端,如果要实现业务集群,就给单个子模块配置多个tomcat服务器并同时启动。
4.4.2 创建带Eureka客户端的springcloud项目
在使用springboot骨架创建项目时,需要勾选eureka客户端以及springboot web
此时整个项目的pom文件中就会自动引入eureka的依赖
<!--EurekaClint依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
然后在springboot启动类上使用注解开启eureka注册中心
最后要配置客户端的端口以及要注册到的eureka服务端ip及端口号
server:
port: 8081
spring:
application:
name:eureka-client
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka
4.4.3 创建多个Eureka客户端
4.4.3.1 根据业务模块创建多个子模块
作为springcloud项目,根据业务模块拆分的子模块效果如图,复杂一点的会建立十几个子模块,更复杂的就是子模块改为父模块,再建子模块,创建思路就是按照java创建包的思路,层层递进,逐级拆分
现在为每一个子模块都配置上eureka客户端
首先要在外层client模块的pom中声明这个父模块打包方式是pom
然后将两个子模块挂载到这个父项目中
此时子模块的pom只需要依赖父模块
并且设置子模块打包方式为jar
4.4.3.2 配置各个子模块的yml
分别配置各个子模块的yml,比如order模块和user模块
4.4.3.3 配置各个子模块的启动类
分别配置各个子模块的启动类,比如user模块
4.4.4 实现子模块之间的调用
任何调用子模块的请求,都应该经过注册中心,假如是两个子模块之间互相调用,也要经过注册中心
举例,现在order模块有一个接口,需要返回订单信息和用户信息,而用户信息需要调用user模块的接口
此时order模块就需要获取user模块返回的数据,但是不能直接调用user模块的接口,那就写死了,也不叫微服务了,order模块应该去注册中心查找user模块,流程如图
通过注册中心调用时,如果user模块有三台tomcat组成集群,那么注册中心就会根据负载均衡,从中任选一个调用
通过查看eurekaClintAutoConfiguration或者查看官方文档,可以知道要实现子模块之间的调用,只需要借助EurekaClient对象提供的方法
全文代码如下
1. order模块通过注册中心获得了user模块的访问url
2. 通过使用RestTemplate对象提供的getForObject方法,获得了user模块返回的对象
3. RestTemplate是 spring-data框架中提供的用于访问restful服务的类,可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接(等同于封装了HttpClient),只需要传入url及返回值类型即可。
@RestController
@RequestMapping("/order")
public class OrderController {
@Resource
private EurekaClient eurekaClient;
@RequestMapping("/{id}")
public Object getOrder(@PathVariable("id") Integer id){
//根据应用名称去查找对应的应用信息
Application application = eurekaClient.getApplication("user-system");
//获取当前应用下的服务器实例列表
List<InstanceInfo> instances = application.getInstances();
String userInfoStr = "";
if(instances.size() > 0){
InstanceInfo instanceInfo = instances.get(0); //获取第一个实例
String hostName = instanceInfo.getHostName();
Integer port = instanceInfo.getPort();
String url = "http://"+hostName + ":" + port + "/user/" + id;
RestTemplate restTemplate = new RestTemplate();
//getForObject方法 第一个参数是URl 第二个参数是返回的数据类型
userInfoStr = restTemplate.getForObject(url, String.class);
}
HashMap<String, Object> map = new HashMap<>();
map.put("orderInfo","订单信息");
map.put("userInfo",userInfoStr);
return map;
}
}
现在通过浏览器访问order模块,order模块再通过注册中心访问user模块获得数据,最终返回给浏览器的结果如图
4.4.5 为单个模块创建多个tomcat 实现业务集群
现在可以给user模块再配置一个tomcat服务器,以增强这个项目的承受力,只需要在tomcat界面拷贝一个原先配置给user模块的tomcat服务器,然后在图示位置设置修改端口
--server.port=8081
在tomcat界面设置的端口会覆盖项目中user模块的yml配置文件中的配置,如果愿意,可以把yml中的所有参数全部搬过来,这就意味着完全覆盖了yml配置文件中的设置——只要能保证写对
此时就可以在user模块下启动两个tomcat服务器,整体项目如下图
4.5 实现高可用Eureka服务端
4.5.1 服务端高可用原理解析
如果只有一个Eureka服务端,也就是只有一个注册中心,那么如果它掉线了整个项目就没办法运行了,所以要启动多台eureka,实现高可用集群
具体原理见下图,总之基于高可用原理,我们可以将我们的Eureka服务端进行两两注册,形成集群。
4.5.2 实现方式
根据官方文档,可以在eureka服务端项目的yml中配置多个eureka
此时eureka的yml配置如下,可以看到两个eureka分别注册到了对方上,并且还注册了自己
spring:
application:
name: eureka-server #声明eureka的实例名称,会在监控页面显示
---
server:
port: 8761 #声明eureka的默认端口
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/ # 声明当前注册中心的地址,将当前服务也注册到注册中心上
spring:
profiles: S1 #当前配置片段名称
---
server:
port: 8762 #声明eureka的默认端口
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/ # 声明当前注册中心的地址,将当前服务也注册到注册中心上
spring:
profiles: S2 #当前配置片段名称
然后在tomcat界面创建两个tomcat服务器,分别设置如下参数
--spring.profiles.active=对应的配置片段名称
此时查看Eureka服务端A,可以看到它注册了自己和服务端B,eureka服务端B同理
整体项目结构如图,A注册自己和B,B注册自己和A,如果服务端A宕机就自动替换为服务端B
最后还要将各个子项目注册到服务端B上
4.6 实际使用场景
eureka是一个AP结构的注册中心,所以在使用时,如果看到如下情况,并不代表这些服务器都在线,可能已经有部分下线了,只是存在延迟,还没有立马同步
实际一个项目运行时,并不是看这些东西,而是会由运维人员使用专业监控工具(比如zabbix)去监控各个服务器,如果服务器挂了,会有自动重启脚本重启服务
运维看到的情况大致如图,只有这种可视化界面才能让运维知道,哪里挂了要重启,哪里资源不足要加服务器
5 consul
5.1 介绍
这是一个独立的应用,和eureka完全不同,它是一个程序,可以直接启动,没有配置文件,需要在启动后再配置,放在linux直接运行,直接调用它提供的API即可
5.2 特点
- 服务注册发现
Consul客户能够注册一个服务,比如api或mysql,其他客户可以在Consul上查询一个指定服务的提供者。Consul提供DNS和HTTP的服务发现接口。
- 健康检查
Consul可以灵活的使用脚本等来检测注册在其上的服务是否可用,不健康的服务Consul也能够灵活处理,比如提供服务的主机内存使用超过90%,我们可以配置让Consul不要把这样的服务提供给服务调用者。
- key/value存储
这个功能和etcd有些类似,可以通过HTTP API方便地使用。
- 多数据中心支持
Consul支持开箱即用的多数据中心支持,这意味着用户不用建立额外的抽象层让业务扩展到各个区域。
5.3 安装服务端
从官网下载的是一个程序
但是不能直接双击运行,得通过命令行启动
## 启动命令
consul agent -dev
## 关闭命令
consul leave
启动完毕后,可以看到该程序针对不同的访问协议提供了不同的端口
通过8500端口,进入了服务端的控制页面
5.4 创建带consul客户端的springcloud项目
Spring Cloud Consul地址:https://spring.io/projects/spring-cloud-consul
5.4.1 springboot项目中使用consul客户端
如图,在创建项目时勾选consul
也可以在springboot项目中,手动通过pom文件导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--监控可选 可以不加 不加不影响代码运行 consul监控页面会有个错误-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
5.4.2 创建多个子模块
为了便于学习,在项目下创建多个子模块
5.4.3 配置各个子模块的启动类
分别配置每一个子模块的启动类
5.4.4 配置各个子模块的yml
分别配置每一个子模块的yml文件,要设置子模块所在端口,子模块名字,以及要注册的consul服务端ip和端口号
5.4.5 实现子模块之间的调用
基于DiscoveryClient对象提供的方法,实现子模块之间的调用,并且通过RestTemplate对象提供的方法获得了user模块返回的对象,代码如下
@RestController
@RequestMapping("/order")
public class OrderController {
@Resource
private DiscoveryClient discoveryClient;
@RequestMapping("/{id}")
public Object getOrder(@PathVariable("id") Integer id){
String userInfo = "";
List<ServiceInstance> instances = discoveryClient.getInstances("user-system");
if(instances.size() > 0){
ServiceInstance serviceInstance = instances.get(0);
String host = serviceInstance.getHost();
int port = serviceInstance.getPort();
String url = "http://" + host + ":" + port + "/user/"+id;
RestTemplate restTemplate = new RestTemplate();
userInfo = restTemplate.getForObject(url, String.class);
}
HashMap<String, Object> map = new HashMap<>();
map.put("orderInfo" , "订单信息");
map.put("userInfo" , userInfo);
return map;
}
}
6 Nacos
6.1 什么是nacos
-
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
-
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
这是对中国人最友好的注册中心,全中文的官方文档,官方说Nacos把很多东西都提供好了,只管用就行了,它的部署由运维负责,所以开发人员都不用管这个东西
6.2 nacos能做什么
6.2.1 综述
6.2.2 动态配置服务
能解决springcloud中的配置中心问题
具体说明如下
- 动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
- 动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。
- 配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。
- Nacos 提供了一个简洁易用的UI (控制台样例 Demo) 帮助您管理所有的服务和应用的配置。Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。
6.2.3 动态DNS配置
基于这个功能,nacos能做注册中心,也能做配置中心,还能解决springcloud的动态路由问题
所以有的时候大家都直接用nacos,因为这样就不需要另外准备别的微服务组件了
具体说明如下
- 动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易地实现以 DNS 协议为基础的服务发现,以帮助您消除耦合到厂商私有服务发现 API 上的风险。
- Nacos 提供了一些简单的 DNS APIs TODO 帮助您管理服务的关联域名和可用的 IP:PORT 列表.
6.3 nacos框架
nacos框架如图
6.4 nacos服务端
6.4.1 新建一个数据库
运行nacos文件夹下提供的sql文件,创建一个数据库
这个数据库用于保存nacos创建的各种账户权限以及配置信息
6.4.2 配置nacos的配置文件
打开nacos安装目录下的application.Proparties,配置db属性,值为刚才创建的数据库
6.4.3 单机模式下启动nacos服务端
如果是wim系统下,那么就在cmd命令行下,使用startup.cmd,或者直接双击启动
如果是linux系统下,那么就用命令启动startup.sh
在win下启动如图
启动成功之后,可以看见nacos端口号是8848
6.4.4 进入nacos控制页面
启动之后,通过访问ip+8848端口号(默认)进入nacos控制页面的登录页面
初始的账号和密码都是nacos,输入后就能进入控制页面
6.5 nacos客户端
6.5.1 创建带nacos的springboot项目
nacos更新速度跟不上springcloud,所以被踢掉了,没办法通过springboot骨架创建的加入
此时只能通过使用springcloudalibaba创建springboot项目
使用阿里巴巴提供的springboot项目,可以看到nacos还存在里面
而且阿里巴巴提供的springboot项目还有以下特点:
1. 存在中文
2. springboot可选版本只有低版本(国内的许多项目都是几年前的,这很符合国情)
6.5.2 配置yml
刚创建的项目自带yml配置文件,其中的配置已经被阿里巴巴提前配好了
但是由于为了方便学习,所以在这个springboot项目下根据业务创建多个子模块,需要分别配置每个子模块的yml
6.5.3 配置启动类
直接在各个子模块的启动类上使用注解
6.5.4 运维的管理页面
启动整个springboot项目之后,如图,可以管理微服务项目的各个tomcat服务器,还能手动下线服务器
7 Zookeeper
7.1 什么是zookeeper
Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高。
7.2 zookeeper能做什么
8 总结
注册中心就是提供了一个web容器,把目前所有在线的服务器集中起来保存、管理,当服务器彼此之间想要调用的时候,可以通过注册中心找到需要调用的业务集群地址以及端口,这就实现了随时扩展服务器,因为一经扩展,服务器就会自动注册到注册中心,别的服务器需要调用业务接口时,就能通过注册中心发现新增的服务器,这就方便了扩展服务器。
如果还是使用Nginx,那还得手动改配置文件,现在算力不够直接加服务器,操作也非常简单,只需要在新增的服务器上运行打包好的springboot项目的jar包即可——jar包中已经封装好了注册中心客户端的相关配置
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步