Spring Cloud - 注册中心

点击↑上方↑蓝色“编了个程”关注我~

每周至少一篇原创文章

这是本公众号的第 8 篇原创文章

什么是微服务注册中心?

在上一篇文章《Spring Cloud介绍》中,提到有一句话:微服务框架可以为这些微小的服务提供「统一的管理和必要的工具」,使它们更易于开发和维护。

“统一的管理和必要的工具”正是微服务框架与单纯的“分布式应用”的区别所在。我们在后续的文章也主要是介绍这样一些Spring Cloud提供的管理微服务的组件和工具。

微服务注册中心最主要的功能正是用来“管理”微服务的。它相当于一个信息中心,保存着每个微服务的ip地址等信息。这样当其它微服务要调用这个微服务时,就可以去注册中心拿到ip,再根据ip去访问相应的微服务。如下图:

微服务注册中心的作用

为什么需要注册中心?

注册中心相当于“婚介所”或者“房屋中介所”。试想一下,如果没有一个这样的中间角色,当一个微服务(消费者)需要调用另一个微服务(生产者)时,它需要保存生产者的地址(如ip,端口等信息)。而这个时候一旦生产者的地址产生了变化,比如:

  • 新增了节点

  • 减少了节点

  • 原有结点的ip或端口变化

就会导致所有的消费者更改配置。传统分布式系统是对每个API创建一个对外的网关,一般使用ELB等负载均衡工具再配上DNS系统来实现:

传统分布式拓扑架构

这样虽然一定程度上能解决服务调用之间的问题,但仍然需要维护大量的ELB/DNS等信息,而且当结点想要动态地增加或删除时,需要去修改ELB的配置。

使用注册中心后,结点的注册、删除、健康检查等功能都能自动化。消费者再也不需要手动去挨个寻找和维护任何生产者的地址信息,只是定时去注册中心取一下就行。

注册中心技术选型

当前主流的注册中心各特性的对比:

FeatureeurekaConsulzookeeperetcd
服务健康检查可配支持服务状态,内存,硬盘等(弱)长连接,keepalive连接心跳
多数据中心支持
kv 存储服务支持支持支持
一致性算法raftpaxos增强raft
capapcpcpcp
使用接口(多语言能力)http(sidecar)支持 http 和 dns客户端http/grpc
watch 支持支持 long polling/大部分增量全量/支持long polling支持支持 long polling
自身监控metricsmetricsmetrics
安全acl /httpsaclhttps 支持(弱)
spring cloud 集成已支持已支持已支持已支持

可以看出,除了Eureka,其它都是基于分布式一致性算法Paxos和Raft的框架。关于Paxos和Raft算法的介绍,可以看我的这两篇文章:

  • 分布式一致性算法:Raft

  • 分布式一致性算法:Paxos

关于分布式CAP的理论,本文不细讲,有兴趣的读者自己去了解一下。C代表一致性,A代表高可用性,P代表分区容错性。在分布式系统中,三者不能同时满足,而P是一定需要满足的,所以常见的分布式系统要么满足AP,要么满足CP。

Eureka是Netflix自己开发的,没有基于上述两个分布式一致性算法,所以一致性很弱。它是通过在客户端配置所有注册中心结点来实现高可用的:

eureka:
  client:
    service-url:
     defaultZone: http://peer2:1112/eureka/, http://peer1:1111/eureka/

Eureka官方宣布不再维护2.X版本。而1.X版本有一些小问题不能和Java 11完美兼容,需要手动去引入一些依赖包。

Consul功能比较强大,且和Spring Cloud也集成得很好,所以也是一个不错的选择。本文将使用Consul为例来搭建和使用注册中心。

使用Consul

原理

Consul基于go语言开发,下图是Consul官方的架构图。

Consul的每个节点称为agent,agent有两种模式:Client模式和Server模式。其中,Client模式不会持久化数据,而Server模式会持久化数据,且Server模式的节点会参加Leader的选举(基于Raft算法)。

为什么需要两种模式?这样做的好处是,我们只需要少量的Server模式的节点用于存储,而Client模式的节点可以很方便地扩展,Client节点可以响应对外的HTTP请求,可以做服务的健康检查等工作,大大减小了Server节点的压力。这样只需要少量的Server节点便可支撑大量的请求。

Consul架构图

Consul支持多数据中心,使用GOSSIP协议来进行通信。同一个数据中心使用LAN,跨数据中心使用WAN。

安装

Consul可以运行在不同的环境下。如果你想在本机运行一个Consul Server,只需要去官网的下载页面下载相应的二进制包,然后下载下来使用下面的命令就可以运行了:

consul agent -dev 

你也可以使用这个命令来在Docker里面运行一个consul Server:

docker run -d --name=consul -p 8500:8500 consul

其中8500端口暴露出来,用于提供Rest服务和Web面板。

使用

启动以后,就可以在8500端口看到WEB界面了。我这里使用的本地的docker启动,修改了hosts文件,所以URL上主机是docker,其实是指向我的docker宿主机的ip。

Consul web界面

最开始你只能看到consul这一个service。下面我们创建三个微服务:

  • service-order

  • service-product

  • service-user

Tips: 其实order-service这种可能具有更好的可读性,但为了查找模块方便,我把service放到了前面。

导入相应的依赖包。这里如果使用IDEA,推荐使用Spring Initializr, 可以自动生成gradle/maven依赖配置,勾选下列依赖:

  • Spring Web Starter

  • Spring Boot Actuator

  • Consul Discovery

这里Actuator用于支持健康检查和提供更多的端点,不是必须的。

然后每个微服务进行如下配置:

spring.application.name=service-user
server.port=9001
spring.cloud.consul.host=docker
spring.cloud.consul.port=8500
#注册到consul的服务名称
spring.cloud.consul.discovery.serviceName=service-user
# 本服务的主机地址,用于健康检查,默认是主机hostname,
# 这里因为consul在docker里,所以这样配置
spring.cloud.consul.discovery.hostname=192.168.99.1

有许多可配置项,不过大多都有默认配置。在IDEA里输入discovery即可看到提示。

配置项

这里有一个小坑,Consul每个service下可以有多个实例(instance),实例是根据instanceId来做唯一标识的,默认是服务名+端口号。所以如果你的微服务运行在多台机器上,具有一样的端口号,后注册的会覆盖之前注册的,导致Consul一个service只能注册一个instance。

参考这篇文章给出了两种解决方案,但我自己更倾向于在运行实例的时候把instanceId传进去,比如service-user-1,service-user-2等。

-Dspring.cloud.consul.discovery.instanceId=service-user-1

默认情况下,会每10秒进行一次健康检查,端点是/actuator/health。想了解更多的配置相关,可以去官方文档查阅。

注册中心集群

在学习的时候,用单节点就可以了。但实际使用的时候最好还是搭建一个集群。这里给一个使用docker搭建集群的相关命令,可用于学习:

# 创建三个Server节点
docker run -d --name=server-1 consul agent -server -bind=172.17.0.2 -bootstrap-expect=3 -node=server-1
docker run -d --name=server-2 consul agent -server -bind=172.17.0.3 -bootstrap-expect=3 -node=server-2 -retry-join=172.17.0.2
docker run -d --name=server-3 consul agent -server -bind=172.17.0.4 -bootstrap-expect=3 -node=server-3 -retry-join=172.17.0.2

# 创建一个Client节点
docker run -d --name=client-1 -p 8500:8500 -P consul agent -bind=172.17.0.5 -node=client-1

可以试试在集群启动起来后,重启server-1节点,查看其它节点的日志,会发现会发生Raft算法重新选举的过程。

在Spring Cloud的配置中,我们「一般是连接到一个Client节点」

你也许会问,我们在配置文件中只能配置一个地址,如果Client节点挂了怎么办?微服务还能正常调用吗?答案是可以的。

其实每个微服务在每次请求得到其它微服务的地址信息(CatalogServices)后,会在本地保存起来。如果它发现注册中心连不通,就会使用本地之前保存的微服务地址信息。

但需要注意的是,「如果Client不可用,新启动一个微服务会启动失败。而已启动的微服务会继续运行,只是会报错」

所以如果Client挂掉了不用慌,重启就行了。如果你不放心,可以在Client前面弄个负载均衡(比如Nginx之类的),基本上就很保险了!

代码地址

关于作者

微信公众号:编了个程(blgcheng)

个人网站:https://yasinshaw.com

笔名Yasin,一个有深度,有态度,有温度的程序员。工作之余分享编程技术和生活,如果喜欢我的文章,可以顺手关注一下公众号,也欢迎转发分享给你的朋友~

推荐阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值