基于 Consul 实现 MagicOnion(GRpc) 服务注册与发现

0.简介

0.1 什么是 Consul

Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。

这里所谓的服务,不仅仅包括常用的 Api 这些服务,也包括软件开发过程当中所需要的诸如 Rpc、Redis、Mysql 等需要调用的资源。

简而言之 Consul 就是根据 Key/Value 存储了一套所有服务的 IP/Port 集合,当你 Grpc 客户端需要请求某种服务的时候,具体的 IP 与端口不需要你自己来进行指定,而是通过与 Consul Agent 通信获得某个服务下面可用的 IP/Port 集合。

而 Consul 还提供了健康检查等附加的功能,你可以通过对可用服务节点的遍历来自己进行负载均衡或者服务选择。

0.2 为什么要用 Consul

没用 Consul 之前的情况是,我 new 一个 Channel 的话,需要指定 Grpc Server 的地址与端口,一单服务挂掉或者 Grpc Server 的 IP 地址或者端口有变更,那么我还得重新更改 setting 才能够使用我的服务。

使用了 Consul 之后我只需要去 Consul Agent 里面查询我指定的服务有哪些节点可用,返回给我对应的 IP 地址和端口,我就可以进行连接了。

1.准备工作

1.1 Consul 集群安装与配置

Consul 我是直接使用 Docker 的官方 Consul 镜像来进行安装的,直接执行以下命令 pull 到最新的镜像:

docker pull consul

拿到之后我们先运行一个服务:

docker run -d --name=dev-consul-server1 -e CONSUL_BIND_INTERFACE=eth0 consul agent -server -bootstrap

之后我们再运行两个 Consul Server:

docker run -d --name=dev-consul-server2 -e CONSUL_BIND_INTERFACE=eth0 consul agent -server -retry-join 172.17.0.20

这里 172.17.0.20 是之前 dev-consul-server1 的 IP 地址。

docker run -d --name=dev-consul-server3 -e CONSUL_BIND_INTERFACE=eth0 consul agent -server -retry-join 172.17.0.20

我们可以运行 consul members 命令来查看 Consul 集群信息:

docker exec -t dev-consul-server1 consul members 
Node          Address          Status  Type    Build  Protocol  DC   Segment
5019b941791a  172.17.0.20:8301  alive   server  1.1.0  2         dc1  <all>
ac53858f8c34  172.17.0.21:8301  alive   server  1.1.0  2         dc1  <all>
fc3aba2ddc25  172.17.0.22:8301  alive   server  1.1.0  2         dc1  <all>

可以看到已经有 3 个 Consul Server 启动了。

下面我们再来运行一个 Consul Client 作为服务注册与发现的端口:

docker run -d -p 8500:8500 --name=dev-consul-client -e CONSUL_BIND_INTERFACE=eth0 -e CONSUL_UI_BETA=true consul agent -retry-join 172.17.0.20 -bind 0.0.0.0 -ui -client 0.0.0.0

这里注意 -bind-client 命令是你绑定的 IP 地址,这里我直接将其与 0.0.0.0 绑定,而 -e CONSUL_UI_BETA=true 则是用于启动新版本的 WebUI 界面,-ui 是启用 WebUI 界面。

启动完成之后我们可以访问已经启动的 Client Agent 了:

2.客户端与服务端编写

在这里我以 Abp 框架作为演示,如何编写一个支持 Consul 的 Grpc 服务端与 Grpc 客户端,在演示当中所使用到的 Abp.Grpc.Server 包与 Abp.Grpc.Client 包可以从 NuGet 站点当中搜索安装,其源代码我托管到 GitHub 上面的,地址为:https://github.com/GameBelial/Abp.Grpc,欢迎 Star。

2.1 Grpc 服务端编写

2.1.1 Abp 集成

首先建立一个标准的 ASP.NET Core Web Application 程序,引入 AbpAbp.AspNetCoreAbp.Grpc.Server 包,项目取名为 Abp.Grpc.Server.Demo,类型选择空项目,在我们的 Startup 类当中编写如下代码:

using Abp.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace Abp.Grpc.Server.Demo
{
    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            // 添加 MVC
            services.AddMvc();
            // 添加 ABP 框架,注意更改 ConfigureServices 返回值为 IServiceProvider
            return services.AddAbp<AbpGrpcServerDemoModule>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            // 启用 ABP 框架中间件
            app.UseAbp();
            // 启用 MVC 中间件
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "defaultWithArea",
                    template: "{area}/{controller=Home}/{action=Index}/{id?}");

                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

2.1.2 建立项目启动模块

新建一个 AbpGrpcServerDemoModule 类,并编写以下代码:

using Abp.AspNetCore;
using Abp.Grpc.Server.Extensions;
using Abp.Modules;

namespace Abp.Grpc.Server.Demo
{
    // 此处依赖 ABP 的 AspNetCore 模块与我们的 GRPC 服务模块
    [DependsOn(typeof(AbpAspNetCoreModule),
        typeof(AbpGrpcServerModule))]
    public class AbpGrpcServerDemoModule : AbpModule
    {
        public override void PreInitialize()
        {
            Configuration.Modules.UseGrpcService(option =>
            {
                // GRPC 服务绑定的 IP 地址
                option.GrpcBindAddress = "0.0.0.0";
                // GRPC 服务绑定的 端口号
                option.GrpcBindPort = 5001;
                // 启用 Consul 服务注册
                option.UseConsul(consulOption =>
                {
                    // Consul 服务注册地址
                    consulOption.ConsulAddress = "10.0.75.1";
                    // Consul 服务注册端口号
                    consulOption.ConsulPort = 8500;
                    // 注册到 Consul 的服务名称
                    consulOption.RegistrationServiceName = "TestGrpcService";
                    // 健康检查接口的端口号
                    consulOption.ConsulHealthCheckPort = 5000;
                });
            })
            .AddRpcServiceAssembly(typeof(AbpGrpcServerDemoModule).Assembly); // 扫描当前程序集的所有 GRPC 服务
        }

        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(typeof(AbpGrpcServerDemoModule).Assembly);
        }
    }
}

2.1.3 编写健康检查控制器

新建一个文件夹叫做 Controllers ,并且新建一个 HealthController 类,其内容如下:

using Abp.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc;

namespace Abp.Grpc.Server.Demo.Controllers
{
    public class HealthController : AbpController
    {
        /// <summary>
        /// 健康检查接口
        /// </summary>
        public IActionResult Check()
        {
            return Ok("OJBK");
        }
    }
}

注意:此处应该继承自 AbpController 基类

2.1.4 编写 RPC 服务

新建一个 RpcServices 文件夹,并且新建一个 TestGrpcService 文件,其内容如下:

using MagicOnion;
using MagicOnion.Server;

namespace Abp.Grpc.Server.Demo.RpcServices
{
    public interface ITestGrpcService : IService<ITestGrpcService>
    {
        UnaryResult<int> Sum(int x, int y);
    }

    public class TestGrpcService : ServiceBase<ITestGrpcService>, ITestGrpcService
    {
        public UnaryResult<int> Sum(int x, int y)
        {
            return UnaryResult(x + y);
        }
    }
}

可以看到我们编写了一个简单的 Sum 方法,该方法接收两个 int 类型的参数,计算其和并返回。

2.1.5 编写 Dockerfile 文件

因为我们的 Consul 是放在 Docker 容器当中的,所以我们将我们的站点发布出去,并且编写一个 Dockerfile 文件,内容如下:

FROM microsoft/dotnet
ENV ASPNETCORE_URLS http://+:5000
## 开放 5000 网站端口
EXPOSE 5000
## 开放 5001 RPC 端口
EXPOSE 5001

WORKDIR /app
COPY ./ .

ENTRYPOINT [ "dotnet","Abp.Grpc.Server.Demo.dll" ]

将其拷贝到发布好的站点,并且执行 docker build 命令:

PS D:\Project\DEMO\Abp.Grpc.Server.Demo\Abp.Grpc.Server.Demo\bin\Release\netcoreapp2.1\publish> docker build -t grpc-server-demo .
Sending build context to Docker daemon   29.9MB
Step 1/7 : FROM microsoft/dotnet
 ---> d8381e1175a1
Step 2/7 : ENV ASPNETCORE_URLS http://+:5000
 ---> Using cache
 ---> da7659cff6d2
Step 3/7 : EXPOSE 5000
 ---> Using cache
 ---> 7ecfc480ad43
Step 4/7 : EXPOSE 5001
 ---> Using cache
 ---> 75f10934ad1e
Step 5/7 : WORKDIR /app
 ---> Using cache
 ---> dee9739da4cd
Step 6/7 : COPY ./ .
 ---> 1a5acc1f0298
Step 7/7 : ENTRYPOINT [ "dotnet","Abp.Grpc.Server.Demo.dll" ]
 ---> Running in a46efbabc7fc
Removing intermediate container a46efbabc7fc
 ---> 321201373ecf
Successfully built 321201373ecf
Successfully tagged grpc-server-demo:latest
SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories

构建完镜像之后,我们运行该镜像:

docker run -d -p 5000:5000 -p 5001:5001 --name=grpc-server-demo grpc-server-demo

2.1.6 查看 Consul

来到 Consul 的 UI 界面查看效果:

可以看到已经成功注册,说明已经成功了。

2.2 Grpc 客户端编写

2.2.1 Abp 集成

首先建立一个标准的 .Net Console 程序,引入 Abp.Grpc.Client 包,在我们的 Program 类当中编写如下代码:

using Abp.Grpc.Client.Demo.RpcServices;
using Abp.Grpc.Client.Utility;
using System;

namespace Abp.Grpc.Client.Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var bootstrapper = AbpBootstrapper.Create<AbpGrpcClientDemoModule>())
            {
                bootstrapper.Initialize();

                Console.WriteLine("Press enter to stop application...");
                Console.ReadLine();
            }

            Console.WriteLine("Hello World!");
        }
    }
}

2.2.2 建立项目启动模块

然后我们新建一个 AbpGrpcClientDemoModule 类,该类一样是一个启动模块,用于配置连接信息:

using Abp.Grpc.Client.Configuration;
using Abp.Grpc.Client.Extensions;
using Abp.Modules;

namespace Abp.Grpc.Client.Demo
{
    [DependsOn(typeof(AbpGrpcClientModule))]
    public class AbpGrpcClientDemoModule : AbpModule
    {
        public override void PreInitialize()
        {
            Configuration.Modules.UseGrpcClient(new ConsulRegistryConfiguration("10.0.75.1", 8500, null));
        }
    }
}

很简单,直接配置 Consul 注册的 IP 与端口号即可。

2.2.3 建立 RPC 接口定义

要调用我们 Server 提供的 RPC 端口的话,得编写一个接口定义,就是我们在 Server 项目里面写的那个,新建一个 ITestGrpcService 接口,内容如下:

using MagicOnion;

namespace Abp.Grpc.Client.Demo.RpcServices
{
    public interface ITestGrpcService : IService<ITestGrpcService>
    {
        UnaryResult<int> Sum(int x, int y);
    }
}

2.2.4 调用 RPC 接口

using Abp.Grpc.Client.Demo.RpcServices;
using Abp.Grpc.Client.Utility;
using System;

namespace Abp.Grpc.Client.Demo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var bootstrapper = AbpBootstrapper.Create<AbpGrpcClientDemoModule>())
            {
                bootstrapper.Initialize();

                // 调用接口
                var connectionUtility = bootstrapper.IocManager.Resolve<IGRpcConnectionUtility>();
                var result = connectionUtility.GetRemoteService<ITestGrpcService>("TestGrpcService").Sum(10, 5).ResponseAsync.Result;
                // 展示结果
                Console.WriteLine("Result:" + result);

                Console.WriteLine("Press enter to stop application...");
                Console.ReadLine();
            }

            Console.WriteLine("Hello World!");
        }
    }
}

调用接口的话,需要注入 IGRpcConnectionUtility 工具类,使用其 GetRemoteService 方法就可以调用你的远程方法,记住一定要传入有效的服务名称。

2.2.5 编写 Dockerfile 文件

一样的,我们新建一个 Dockerfile 文件,将我们的 client 也打包成镜像:

FROM microsoft/dotnet

WORKDIR /app
COPY ./ .

ENTRYPOINT [ "dotnet","Abp.Grpc.Client.Demo.dll" ]

内容很简单,一样的复制到发布成功的文件夹,构建镜像:

docker build -t grpc-client-demo .

构建之后运行:

docker run grpc-client-demo

不出意外的话会看到如下输出:

PS D:\Project\DEMO\Abp.Grpc.Client.Demo\Abp.Grpc.Client.Demo\bin\Release\netcoreapp2.1\publish> docker run grpc-client-demo
Result:15
Press enter to stop application...
Hello World!

3.代码分析

抛开 ABP 框架部分的代码,其实要实现服务注册很简单,核心就是 ConsulClient 这个类,下面就来分析一下 Abp.Grpc 库里面的代码。

3.1 注册服务

注册服务其核心就在于 ConsulClient.Agent.ServiceRegister() 方法,通过传入一个构造好的 AgentServiceRegistration 对象就可以成功注册一个服务到 Consul。

例如:

_agentServiceRegistration = new AgentServiceRegistration
{
    ID = Guid.NewGuid().ToString(),// 唯一ID
    Name = config.RegistrationServiceName,// 注册的服务名称
    Address = currentIpAddress, // 服务提供者地址
    Port = config.GrpcBindPort, // 服务提供者端口
    Tags = new[] { "Grpc", $"urlprefix-/{config.RegistrationServiceName}" }, // 注册的服务标签
    Check = new AgentServiceCheck // 健康检查
    {
        DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), // 取消注册时间
        Interval = TimeSpan.FromSeconds(10), // 检查间隔
        Status = HealthStatus.Passing, // 检查通过的状态
        Timeout = TimeSpan.FromSeconds(5), // 超时时间
        HTTP = $"http://{currentIpAddress}:{config.ConsulHealthCheckPort}/health/check" // 健康检查接口地址
    }
};

构建成功后通过 ConsulClient.Agent.ServiceRegister() 方法即可注册到 Consul。

取消注册则是通过 ConsulClient.Agent.ServiceDeregister 方法。

3.2 发现服务

服务发现相较于服务注册简单得多,只需要通过 ConsulClient.Catalog.Services 遍历其结果即可获得所有节点,并且通过 LINQ 来筛选出指定 tag 的服务。

4.其他相关参考资料

田园里的蟋蟀:Docker & Consul & Fabio & ASP.NET Core 2.0 微服务跨平台实践)

Edison Chou:.NET Core微服务之基于Consul实现服务治理

Cecilphillip:Using Consul for Service Discovery with ASP.NET Core

5.所使用到的代码

Abp.Grpc 库代码:https://github.com/GameBelial/Abp.Grpc

DEMO 代码:

https://github.com/GameBelial/Abp.Grpc.Server.Demo

https://github.com/GameBelial/Abp.Grpc.Client.Demo

原文地址:https://www.cnblogs.com/myzony/p/9168851.html

时间: 2024-08-13 13:34:11

基于 Consul 实现 MagicOnion(GRpc) 服务注册与发现的相关文章

【转帖】基于Zookeeper的服务注册与发现

http://www.techweb.com.cn/network/hardware/2015-12-25/2246973.shtml 背景 大多数系统都是从一个单一系统开始起步的,随着公司业务的快速发展,这个单一系统变得越来越庞大,带来几个问题: 1. 随着访问量的不断攀升,纯粹通过提升机器的性能来已经不能解决问题,系统无法进行有效的水平扩展 2. 维护这个单一系统,变得越来越复杂 3. 同时,随着业务场景的不同以及大研发的招兵买马带来了不同技术背景的工程师,在原有达达Python技术栈的基础

024.微服务之服务注册与发现(基于kubernetes / SpringCloud)

微服务 微服务是一种架构模式,一种分布式的架构风格. 顾名思义,micro service,将一个庞大的单体应用拆分成若干个“微小”的服务,服务间通过进程通讯完成原本在单体应用中的调用. 其中必要的六个基本技术为: 1.服务注册与发现: 2.进程间通信: 3.负载均衡: 4.分布式配置中心: 5.熔断器: 6.网关路由. 基于k8s.springcloud的服务注册与发现对比 k8s并没有引入新的注册中心,使用的就是k8s的kube-dns. k8s将Service的名称当做域名注册到kube-

分布式中几种服务注册与发现组件的原理与比较

Eureka.Consul.Zookeeper的基本原理与比较. 前言 在云计算和容器化技术发展火热的当下,对于微服务架构,服务注册与发现组件是必不可少的.在传统的服务架构中,服务的规模处于运维人员的可控范围内.当部署服务的多个节点时,一般使用静态配置的方式实现服务信息的设定.在微服务应用中,服务实例的数量和网络地址都是动态变化的,这对系统运维提出了巨大的挑战.因此,动态的服务注册与发现就显得尤为重要. 解决的问题 在一个分布式系统中,服务注册与发现组件主要解决两个问题:服务注册和服务发现. 服

简单RPC框架-基于Consul的服务注册与发现

*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* BLOCKS =============================================================================*/ p, blockquote, ul, ol, dl, table, pre { margin: 15px 0; } /* HEAD

Spring Cloud Consul 实现服务注册和发现

Spring Cloud 是一个基于 Spring Boot 实现的云应用开发工具,它为基于 JVM 的云应用开发中涉及的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管理等操作提供了一种简单的开发方式.通过 Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂.易部署和易维护的分布式系统开发工具包. Spring Cloud 包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Sprin

分布式服务注册和发现consul 简要介绍

Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其他分布式服务注册与发现的方案,Consul的方案更"一站式",内置了服务注册与发现框 架.分布一致性协议实现.健康检查.Key/Value存储.多数据中心方案,不再需要依赖其他工具(比如ZooKeeper等).使用起来也较 为简单.Consul用Golang实现,因此具有天然可移植性(支持Linux.windows和Mac OS X):安装包仅包含一个可执行文件,方便部署,与Docker等轻量级

consul服务注册与发现应用实战

上一讲:讲到consul发现的模板形式,这一讲我们聊一聊比较基础的consul的服务注册与发现,并且使用bind代理给服务做负载均衡,这个功能也是后面要补充的redis + consul 或者mha + consul的一个基础,我们先看一下环境: 配置环境(还是那句话,在生产环境把server配置成3-5台,agent随意): 192.168.113.174       server 192.168.113.175       agent 192.168.113.176       agent

.Net Core 商城微服务项目系列(二):使用Ocelot + Consul构建具备服务注册和发现功能的网关

1.服务注册 在上一篇的鉴权和登录服务中分别通过NuGet引用Consul这个包,同时新增AppBuilderExtensions类: public static class AppBuilderExtensions { public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app,IApplicationLifetime lifetime,ServiceEntity serviceEntity) {

服务注册与发现

服务注册与发现 1.什么是服务注册与发现 微服务将传统的"巨石"应用拆分成一个一个的组件应用,每个组件应用提供特定的服务,可以是一个,也可以是多个,并且组件所含服务应该是可以动态扩展的,随着时间推移.系统进化,可任意拆分.合并. 组件化应用和颗粒化的服务,遍布在系统的各个角落,由不同的项目成员进行维护,微服务的核心是化整为零.各司其职,这就要求开发人员不得操作其业务或服务范围以外的数据模型等资源,只能通过接口的访问,使用某一服务. 由于服务的跨度很大(公司很大的情况下).数量很多(数以