前言

在这几年的工作中,也经历过几个微服务项目,大多数都上了k8s,基本上都看不到Consul的身影,所以在工作之余折腾了下Consul,作为个人来讲还是得学习下,所以也就顺便通过文章来记录下学习过程。还有就是现在基本上只要提到微服务,其中涉及到的知识点就会很繁多,遇到的问题也会很多,建议阅读本文前先了解下“什么是Consul?”,”什么是注册中心、服务注册、服务发现?”,”为什么需要有服务注册与服务发现?”等等,然后可以参考大佬的文章,讲的非常详细了 Consul概念及其架构方式
然后本文只是个人学习与分享,不喜勿喷,谢谢。

什么是Consul?

这里只简单介绍下Consul,网上相关文章也比较多,就不过多陈述
Consul官网:https://www.consul.io
开源地址:https://github.com/hashicorp/consul、https://github.com/G-Research/consuldotnet

Consul 作为一种分布式服务工具,为了避免单点故障常常以集群的方式进行部署,在 Consul 集群的节点中分为 Server和 Client两种节点(所有的节点也被称为Agent),Server 节点保存数据,Client 节点负责健康检查及转发数据请求到 Server;Server 节点有一个 Leader 节点和多个 Follower 节点,Leader 节点会将数据同步到 Follower 节点,在 Leader 节点挂掉的时候会启动选举机制产生一个新的 Leader。

Client 节点很轻量且无状态,它以 RPC 的方式向 Server 节点做读写请求的转发,此外也可以直接向 Server 节点发送读写请求。下面是 Consul 的架构图:

Consul 作为一种分布式服务工具,为了避免单点故障常常以集群的方式进行部署,在 Consul 集群的节点中分为 Server 和 Client 两种节点(所有的节点也被称为Agent),Server 节点保存数据,Client 节点负责健康检查及转发数据请求到 Server;Server 节点有一个 Leader 节点和多个 Follower 节点,Leader 节点会将数据同步到 Follower 节点,在 Leader 节点挂掉的时候会启动选举机制产生一个新的 Leader。

Client 节点很轻量且无状态,它以 RPC 的方式向 Server 节点做读写请求的转发,此外也可以直接向 Server 节点发送读写请求。下面是 Consul 的架构图,很好的解释了Consul的工作原理。

57b1d92c45db6de5cf4ba9db7523518c.png

环境准备

.Net 6

Docker desktop

Visual Studio 2022

安装Consul

Consul 支持各种平台的安装,安装文档:https://www.consul.io/downloads,为了快速使用,我这里选择用 docker 方式安装。

docker pull consul --默认拉取latest

docker run -d --name consul -p 8500:8500 consul:latest --使用镜像 consul:latest 启动容器,将容器的8500端口映射到主机的8500端口

启动Consul,打开默认地址 http://localhost:8500 可以看到Consul的UI界面

46ba72dfa8864406db8163e56d8937f3.png

项目搭建

我们先准备2个Service(Minimal Api)以及一个Client(空 Web)

然后准备一个类库 Service.Framework 用于封装Consul IOC注册

8db7edf14371bd9e241a7a98a2f5a168.png

在Service.Framework 中安装

NuGet包

4eb55437643cd84b08b4ebcbdf4a88bc.png

然后将 Consul 配置信息添加至各自项目的 appsettings.json 文件中

bb28d72cedba42f911d7dcb8331f48f2.png

因为我们要将项目都运行在docker中,所以这里的地址要用 host.docker.internal 代替,使用 localhost 无法正常启动,如果不在 docker 中运行,这里就配置层 localhost。

服务注册

配置Consul 服务注册

我们首先需要将ServiceA与ServiceB注册到Consul中

我们直接在Service.Framework 添加扩展方法
ConsulExtend.cs

d61cc9a2ff0ee36f5d9a2f467c0d16b4.png

Program.cs

28fcd2e96307f1b2d262766d00ebf1f6.png

ConsulRegister.cs

bb16dd71f44080bf38fc396d5e532bc1.png

然后直接在对应Service项目进行IOC注册即可

e19924f524ef11fbd1ab50dfd61567f3.png

配置健康检查

然后我们还需要配置对应健康检查,用来监控服务可用性,主动区分出不可用服务。
这里我们使用中间件的方式
在Service.Framework中添加HealthCheckMiddleware.cs

24cf6c1714ab757146b106fbc85eafe5.png

这里健康检查地址需要与appsetting.json文件中配置的地址对应

475e6621115b38cd6737a3a2b09f0d07.png

然后在对应服务项目中使用即可
Program.cs(示例代码为 ServiceA,ServiceB服务可以自行添加)

8affadad78dbdc98ff4158c99f7f9760.png

增加测试接口

直接在Program.cs 直接添加即可

559eadbc5186fc58820215cad8b9086e.png

增加docker支持

这里我因为选择的是在docker中运行,所以需要为项目添加docker支持。

接下来我们通过 Visual Studio为ServiceA与ServiceB项目生成对应的Dockfile文件

daf808b205a68038ab80ddaef9b6c0b2.png

ServiceA

506d59226226f390ca471bbbe8706a65.png

ServiceB

beb9f0f940e9c2f1c495082937f25b2a.png

编译镜像

然后定位到项目根目录,使用命令去编译两个镜像,service_a和service_b(这里不清楚的可以参考我之前的文章 .NET 6 从0到1使用Docker部署至Linux环境)

docker image build -f ./ServiceA/Dockerfile -t service_a .

docker image build -f ./ServiceB/Dockerfile -t service_b .

6afa09f077faaa63e842fdb365d98cef.png

查看编译好的镜像

3711081ef360f4c15715b5a1fceb5e8a.png

运行镜像

接下来运行镜像启动项目实例

docker run -d -p 5050:80 --name service_a1 service_a --ConsulRegisterOptions:Port="5050"
docker run -d -p 5060:80 --name service_b1 service_b --ConsulRegisterOptions:Port="5060"

然后这里注意一下 ConsulRegisterOptions:Port="5050"
这里的意思是会替换appsetting.json 文件中的ConsulRegisterOptions配置文件中Port的内容,这里可以方便后面启动多实例时指定对应端口,本示例为单实例也可不需要此项内容,默认使用配置文件中的Port

docker run -d -p 5050:80 --name service_a1 service_a
docker run -d -p 5060:80 --name service_b1 service_b

分别执行命令

fe927c20c801ddd24939e7d75fc90e26.png

然后访问 http://localhost:8500 查看Consul查看服务是否注册成功

dca010e4407629428ab9ff4a242a1912.png

cae21e736f971012551461d654a532f3.png

发现服务注册成功,健康检查也已通过,后面服务地址端口也都对应。

服务实例集群

然后我们继续为服务启动多个实例

docker run -d -p 5051:80 --name service_a2 service_a --ConsulRegisterOptions:Port="5051"
docker run -d -p 5052:80 --name service_a3 service_a --ConsulRegisterOptions:Port="5052"

docker run -d -p 5061:80 --name service_b2 service_b --ConsulRegisterOptions:Port="5061"
docker run -d -p 5062:80 --name service_b3 service_b --ConsulRegisterOptions:Port="5062"

42e4838cf315d28ef96795808e4b8418.png

6b3377882ead2e5f8c5522f66424f3f7.png

当然这里如果你觉得比较繁琐,也可以使用docker compose来编排脚本启动服务实例

访问服务接口

接下来我们试着访问访问接口,看看能不能出现效果

3c943d7d20c27d01496f2fb2a49f802b.png

因为终端编码问题,导致显示乱码,这个不影响,ok,至此服务注册大功告成

服务发现

我们直接在Client项目的Program.cs中准备两个接口

代码很简单

3ee250b227b2f7a6224334e9c0162786.png

下面这个接口,我把上面的代码封装了一下,弄了个抽象类,然后模拟了3种调度策略,意思一样的

bd0349ad7561fd9842401a2aae7efb4e.png

用之前记得先在IOC注册一下

builder.Services.AddConsulDispatcher(ConsulDispatcherType.Polling);

066d1c4da615fcf7b3c738a121483081.png

然后我们分别访问两个接口,模拟访问3次,看下效果:

ServiceADiscoveryTest

f2ad5195751ba90a003aab9983cb6e88.png

ServiceBDiscoveryTest

a2ad7cf71a7f0385edf8f4a11829aeb8.png

至此,服务发现就大功告成,就算其中某个节点挂掉,服务也可以正常运行。

结尾

本文只是简单的实现了Consul的服务注册和发现,至于怎么更好的应用到实际项目,还得继续探索。

后面会继续学习网关等相关知识,感兴趣的同学欢迎继续关注!

代码仓库地址

https://github.com/fengzhonghao8-24/ConsulIntroduction

作者:Mamba8-24

出处:https://www.cnblogs.com/Mamba8-24/

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐