使用 Consul 作为成员资格提供程序

Consul 是一个分布式、高度可用且数据中心感知的服务发现平台,其中包括简单的服务注册、运行状况检查、故障检测和键值存储。 前提是数据中心中的每个节点都运行 Consul 代理,该代理充当服务器或客户端。 每个代理通过可缩放的 gossip 协议进行通信。

Consul 的概述非常详细,包括此处的类似解决方案比较。

Consul 采用 Go 编写,并且是开放源代码;编译的下载适用于 macOS X、FreeBSD、Linux、Solaris 和 Windows

为什么选择 Consul?

当你需要提供不要求潜在客户拥有现有基础结构和合作 IT 提供程序的本地解决方案时,Consul 作为 Orleans 成员资格提供程序,是一个不错的选择。 Consul 是一个轻型单一可执行文件,没有依赖项,因此可以轻松内置到中间件解决方案中。 当 Consul 是发现、检查和维护微服务的解决方案时,与 Orleans 成员资格完全集成非常有意义,可确保操作的简易性。 Consul(也称为“Orleans 自定义系统存储”)中还有一个成员资格表,该表与 Orleans 的群集管理完全集成。

设置 Consul

Consul.io 上提供了有关设置稳定的 Consul 群集的广泛文档,在此处重复这一点没有任何意义。 但是,为了方便起见,我们提供了本指南,从而可以快速让 Orleans 与独立的 Consul 代理一起运行。

  1. 创建要安装 Consul 的文件夹(例如 C:\Consul)。

  2. 创建子文件夹:C:\Consul\Data(如果不存在,Consul 不会创建此文件夹)。

  3. 将 Consul.exe 下载并解压缩到 C:\Consul 中。

  4. 在 C:\Consul 中打开命令提示符并运行以下命令:

    ./consul.exe agent -server -bootstrap -data-dir "C:\Consul\Data" -client='0.0.0.0'
    

    在上述命令中:

    • agent:指示 Consul 运行托管服务的代理进程。 如果没有此开关,Consul 进程将尝试使用 RPC 配置正在运行的代理。
    • -server:将代理定义为服务器,而不是客户端(Consul 客户端是托管所有服务和数据的代理,但没有投票权决定,并且不能成为群集领导者)。
    • -bootstrap:必须引导群集中的第一个(并且只有第一个!)节点才能假设群集领导者。
    • -data-dir [path]:指定存储所有 Consul 数据的路径,包括群集成员资格表。
    • -client='0.0.0.0':通知 Consul 要打开该服务的 IP。

    还有许多其他参数,以及使用 JSON 配置文件的选项。 有关选项的完整列表,请参阅 Consul 文档。

  5. 通过在浏览器的 http://localhost:8500/v1/catalog/services 中打开服务终结点,验证 Consul 是否正在运行并准备好接受 Orleans 发出的成员资格请求。 正常运行时,浏览器会显示以下 JSON:

    {
        "consul": []
    }
    

配置 Orleans

若要配置 Orleans 以将 Consul 用作成员资格提供程序,接收器项目需要引用 Microsoft.Orleans.Clustering.Consul NuGet 包。 完成此操作后,可以在接收器的 Program.cs 文件中配置成员资格提供程序,如下所示:

IHostBuilder builder = Host.CreateDefaultBuilder(args)
    .UseOrleans(silo =>
    {
        silo.UseConsulSiloClustering(options =>
        {
            // The address of the Consul server
            var address = new Uri("http://localhost:8500");
            options.ConfigureConsulClient(address);
        });
    })
    .UseConsoleLifetime();

using IHost host = builder.Build();
host.Run();

前面的代码:

若要配置客户端,请引用同一个 NuGet 包并调用 UseConsulClientClustering 扩展方法。

客户端 SDK

如果你对使用 Consul 进行服务发现感兴趣,则大多数常用语言都有客户端 SDK

实现详细信息

成员资格表提供程序通过 Check-And-Set (CAS) 操作使用 Consul 的键/值存储功能。 每个接收器启动时,会注册两个键值条目,一个包含接收器详细信息,一个包含接收器上次报告它处于活动状态的时间。 后者指的是诊断“我处于活动状态”条目,而不是故障检测的检测信号,这些条目直接在接收器之间发送,并且不会写入表中。 使用 CAS 执行对表的所有写入以提供并发控制,这对 Orleans 的群集管理协议而言是必不可少的。

运行接收器后,可以在 Web 浏览器中访问 http://localhost:8500/v1/kv/?keys&pretty 以查看这些条目,将显示如下所示的内容:

[
    "orleans/default/192.168.1.11:11111@43165319",
    "orleans/default/192.168.1.11:11111@43165319/iamalive",
    "orleans/default/version"
]

所有密钥都带有前缀 orleans,该前缀在提供程序中硬编码,旨在避免与 Consul 的其他用户发生键空间冲突。 你可以使用这些密钥中的任何一个来检索其他信息。可以通过将密钥名称(不带引号)追加到 http://localhost:8500/v1/kv/ 中的 Consul KV 根目录来读取其中每个密钥。 这样做会向你呈现以下 JSON:

[
    {
        "LockIndex": 0,
        "Key": "orleans/default/192.168.1.11:11111@43165319",
        "Flags": 0,
        "Value": "[BASE64 UTF8 Encoded String]",
        "CreateIndex": 321,
        "ModifyIndex": 322
    }
]

解码 Base64 UTF-8 编码的字符串 Value 可提供实际的 Orleans 成员资格数据:

http://localhost:8500/v1/KV/orleans/default/[SiloAddress]

{
    "Hostname": "[YOUR_MACHINE_NAME]",
    "ProxyPort": 30000,
    "StartTime": "2023-05-15T14:22:00.004977Z",
    "Status": 3,
    "SiloName": "Silo_fcad0",
    "SuspectingSilos": []
}

http://localhost:8500/v1/KV/orleans/default/[SiloAddress]/IAmAlive

"2023-05-15T14:27:01.1832828Z"

客户端连接时,使用 URI http://192.168.1.26:8500/v1/KV/orleans/default/?recurse 读取一个 HTTP GET 中群集的所有接收器的 KV。

限制

将 Consul 用作成员资格提供程序时,需要注意一些限制。

Orleans 扩展了成员资格协议(表版本和 ETag)

Consul KV 当前不支持原子更新。 因此,Orleans Consul 成员资格提供程序仅实现 Orleans 基本成员资格协议,如 Orleans 中的群集管理中所述,并且不支持扩展的成员资格协议。 此扩展协议作为附加但不重要的接收器连接验证,并且作为尚未实现的功能的基础引入。

多个数据中心

Consul 中的键值对当前不会在 Consul 数据中心之间复制。 有一个单独的项目可处理此复制工作,但尚未得到证实支持 Orleans。

在 Windows 上运行时

Consul 在 Windows 上启动时,会记录以下消息:

==> WARNING: Windows is not recommended as a Consul server. Do not use in production.

显示该警告消息是因为在 Windows 环境中运行时未侧重于测试,而不是因为存在任何实际已知问题。 在决定 Consul 是否适合你之前阅读讨论

潜在的未来增强功能

  1. 证明 Consul KV 复制项目可以在多个 Consul 数据中心之间的 WAN 环境中支持 Orleans 群集。
  2. 在 Consul 中实现提醒表。
  3. 实现扩展的成员资格协议。 Consul 背后的团队计划实现原子操作,一旦此功能可用,就有可能消除提供程序的限制。