应如何托管 GRPC 服务

本文关键字:服务 GRPC 何托管 | 更新日期: 2023-09-27 18:32:58

我使用链接中给出的示例在C#中创建了一个GRPC服务器。现在我想弄清楚我应该如何托管此服务器,以便实现以下目标:

  • 我应该将此服务器设置为控制台应用程序还是Windows服务。如果我将其设为 Windows 服务,那么更新该服务将很麻烦(这是一个很大的负面影响(,如果我将其设为控制台应用程序,那么更新只需要关闭 exe。但随之而来的是错误关闭相同的代价。还有其他更好的方法吗?
  • 使用IIS,
  • 此问题不会在那里,因为我可以简单地从LB中删除站点并停止该网站以执行更新,但是由于GRPC不会成为IIS的一部分,因此我不确定有什么方法可以使其工作。

欢迎任何有关更好架构的参考。

应如何托管 GRPC 服务

我们可以使用 Microsoft.Extensions.Hosting pacakge 来托管 .net 核心控制台应用程序,方法是使用 HostBuilder API 开始构建 gRPC 主机并进行设置。

为了运行 gRPC 服务,我们首先需要在托管服务中启动/停止Grpc.Core.Server。托管服务基本上是一段代码,在主机本身启动时由主机运行,在主机停止时也是如此。以下代码实现一个GrpcHostedService来重写IHostedService接口:

using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Microsoft.Extensions.Hosting;
namespace Grpc.Host
{
    public class GrpcHostedService: IHostedService
    {
        private Server _server;
        public GrpcHostedService(Server server)
        {
            _server = server;
        }
        public Task StartAsync(CancellationToken cancellationToken)
        {
            _server.Start();
            return Task.CompletedTask;
        }
        public async Task StopAsync(CancellationToken cancellationToken) => await _server.ShutdownAsync();
    }
}

Program.cs中,使用 HostBuilder API 开始构建我们的 grpc 主机并对其进行设置:

public class Program
{
    public static async Task Main(string[] args)
    {
        var hostBuilder = new HostBuilder()
             // Add configuration, logging, ...
            .ConfigureServices((hostContext, services) =>
            {
                // Better to use Dependency Injection for GreeterImpl
                Server server = new Server
                {
                    Services = {Greeter.BindService(new GreeterImpl())},
                    Ports = {new ServerPort("localhost", 5000, ServerCredentials.Insecure)}
                };
                services.AddSingleton<Server>(server);
                services.AddSingleton<IHostedService, GrpcHostedService>();
            });
        await hostBuilder.RunConsoleAsync();
    }
}

通过这样做,通用主机将自动在我们的托管服务上运行 StartAsync,而该服务又会在Server实例上调用 StartAsync,实质上是启动 gRPC 服务器。

当我们使用 Control-C 关闭主机时,通用主机将自动在我们的托管服务上调用 StopAsync,这将再次在Server实例上调用 StopAsync,这将执行一些清理。

有关主机生成器中的其他配置,您可以查看此博客。

我将再添加一个选项。

使用dot net core,您现在可以将其作为Linux守护程序运行。

目前 gRPC 不支持与 ASP.Net/IIS 集成。您需要在控制台中或作为 Windows 服务托管服务器。

您可能希望这是一项 Windows 服务,以便更轻松地在重新启动或崩溃时保持服务器运行。如果你想轻松地将控制台应用程序变成Windows服务,我建议使用优秀的TopShelf Nuget。

可以像更新控制台应用一样更新服务。

  • 停止 Windows 服务。 net stop <service-name}>
  • 复制更新的程序集。
  • 启动 Windowsservice net start <service-name>

我的公司(Shortbar(正在为 gRPC 上的一个名为 HOLMS 的酒店管理系统构建应用程序服务器。我们的设置如下:

  • 霍尔姆斯。应用程序是一个 .NET 类库(程序集(,用于执行服务器的实际工作
  • 霍尔姆斯。Application.ConsoleRunner 是一个托管 HOLMS 的 C# 控制台应用程序。应用。控制台运行器由 (1( 开发人员使用以方便(在问题中提到(以及 (2( 在 Docker 容器内运行的生产场景,其中容器运行时(例如 Amazon ECS(实现作业控制/扩展。它遵循"12 因素应用"准则,包括将自身作为单个、独立、无状态的进程运行、快速启动/关闭和环境变量配置注入。系统记录到标准输出,该标准输出被清空,但在生产环境中(例如相扑,日志等(中排出。这就是我们的 SaaS 多租户解决方案将如何投入生产。
  • 霍尔姆斯。Application.ServiceRunner 包 HOLMS。应用程序到 Windows 服务中,适用于更传统的本地情况,其中客户的 IT 组将自行运行服务。此程序包使用 Windows 注册表进行配置,并依赖于 Windows 服务作业控制进行启动/关闭/重新启动。它记录到 Windows 事件日志中。

ConsoleRunner 和 ServiceRunner 每个只有大约 200 行代码;在大多数情况下,它们只是包装应用程序包,然后调用它。

希望这有帮助。