1 - 名称解析的设计及文档

介绍名称解析的设计及文档

名称解析

  • 文档:gRPC服务配置

服务配置

2 - 文档:gRPC名称解析

gRPC名称解析

https://github.com/grpc/grpc/blob/master/doc/naming.md

概述

gRPC支持DNS作为默认的名称系统。在不同的部署中,有许多替代的名称系统被使用。我们支持一个足够通用的API,以支持一系列的名称系统和相应的名称语法。各种语言的 gRPC 客户端库将提供一个插件机制,因此可以插入不同名称系统的解析器。

详细设计

名称语法

用于 gRPC channel 构建的完全限定的自包含名称,使用 RFC 3986中定义的URI语法。

URI schema 指示要使用的解析器插件,如果没有指定schema前缀或schema未知,默认使用dns方案。

URI路径表示要解析的名称。

大多数 gRPC 实现都支持以下URI schema:

  • dns:[//authority/]host[:port] – DNS (默认)

    • host 是要通过DNS解析的主机名
    • port 是要为每个地址返回的端口,如果没有指定,则使用443 (但是某些实现对于非加密channel默认使用80)
    • authority 表示要使用的 DNS 服务器,尽管这只被一些实现所支持。在C-core中,默认的DNS解析器不支持这个功能,但基于c-ares的解析器支持以 “IP:port “的形式指定这个功能)。
  • unix:path or unix://absolute_path – Unix domain sockets (Unix systems only)

    • path 表示所需socket的位置。
    • 在第一种形式中,路径可以是相对的,也可以是绝对的;在第二种形式中,路径必须是绝对的(即实际上会有三个斜线,两个在path之前,另一个用来开始绝对路径)。

gRPC C-core实现支持以下方案,但其他语言可能不支持:

  • ipv4:address[:port][,address[:port],...] – IPv4 addresses

    • 可以指定多个逗号分隔的地址,地址形式为address[:port]

      • address 是使用的 IPv4 地址
      • port 是使用的端口。如果没有指定,使用443
  • ipv6:address[:port][,address[:port],...] – IPv6 addresses

    • 可以指定多个逗号分隔的地址,地址形式为address[:port]
      • address 是使用的 IPv6 地址. 要使用 port 则地址 address 必须用中括号 ([ and ])包起来. 例如: ipv6:[2607:f8b0:400e:c00::ef]:443 or ipv6:[::]:1234
      • port是使用的端口。如果没有指定,使用443

今后还可以增加其他schema,如 “etcd”。

Resolver 插件

gRPC客户端类库将使用指定的schema来挑选合适的解析器插件,并将完全限定的名称字符串传递给它。

解析器应该能够联系权威机构(authority)并得到解析,然后将其返回给gRPC客户端类库。返回的内容包括:

  • 解析的地址列表(包括IP地址和端口)。每个地址可以有一组与之相关的任意属性(键/值对),这些属性可用于从解析器向负载均衡策略传递信息。

  • service config

插件API允许解析器持续观察一个端点,并根据需要返回更新的解析。

3 - 文档:gRPC服务配置

gRPC服务配置

https://github.com/grpc/grpc/blob/master/doc/service_config.md

目标

服务配置是一种机制,它允许服务所有者发布参数,让其服务的所有客户端自动使用。

格式

服务配置的格式由 grpc.service_config.ServiceConfig protocol buffer message 定义。请注意,随着新功能的引入,未来可能会添加新的字段。

架构

服务配置与服务器名相关联。名称解析器插件在被要求解析某个服务器名称时,会同时返回解析的地址和服务配置。

名称解析器以 JSON 形式将服务配置返回给 gRPC 客户端。各个解析器实现决定服务配置的存储位置和格式。如果解析器实现以 protobuf 形式获取服务配置,则必须使用正常的 protobuf 到 JSON 的转换规则将其转换为 JSON。另外,解析器实现也可以以 JSON 形式获取服务配置,在这种情况下,它可以直接返回服务配置。

有关 DNS 解析器插件如何支持服务配置的详情,请参见 gRFC A2: Service Config via DNS.

例子

下面是一个protobuf形式的服务配置示例:

{
  // 使用 round_robin 负载均衡策略
  load_balancing_config: { round_robin: {} }
  // 这个方法配置适用于 "foo/bar" 方法和 service "baz"的所有方法
  method_config: {
    name: {
      service: "foo"
      method: "bar"
    }
    name: {
      service: "baz"
    }
    // 匹配方法的默认超时
    timeout: {
      seconds: 1
      nanos: 1
    }
  }
}

下面是同样的JSON形式的服务配置示例:

{
  "loadBalancingConfig": [ { "round_robin": {} } ],
  "methodConfig": [
    {
      "name": [
        { "service": "foo", "method": "bar" },
        { "service": "baz" }
      ],
      "timeout": "1.0000000001s"
    }
  ]
}

API

服务配置在以下API中使用:

  • 在 resolver API中,用于解析器插件,以便将服务配置返回给gRPC客户端
  • 在 gRPC 客户端 API 中,用户可以查询 channel 以获取与通道相关的服务配置(用于调试)。
  • 在 gRPC 客户端 API 中,用户可以显式地设置服务配置。这可以用来在单元测试中设置配置。它还可以用来设置默认配置,如果解析器插件没有返回服务配置,就会使用该配置。

4 - 提案:service configs via dns

通过dns进行服务配置

https://github.com/grpc/proposal/blob/master/A2-service-configs-in-dns.md

摘要

本文档提出了一种在DNS中编码gRPC服务配置数据的机制,供开源世界使用。

背景

服务配置机制最初是为Google内部使用而设计的。然而,除了一部分之外,所有原始设计在开源世界中都能正常工作。这一部分就是服务配置数据在DNS中如何编码的规范。这个提案填补了这个缺失的部分。

提案

这个提案有两个部分。第一部分是增加一些JSON包装,用于控制服务配置的更改如何进行金丝雀测试。第二部分是描述服务配置如何在DNS中进行编码。

Canarying Changes

金丝雀变更

当部署对服务配置的变更时,通过缓慢增加看到新版本的客户端数量,能够对更改进行金丝雀测试以避免大范围的中断,这是非常有用的。为此,可以按顺序列出多个服务配置的选择,以及决定特定客户机将选择哪个的标准:

// A list of one or more service config choices.
// The first matching entry wins.
[
  {
    // Criteria used to select this choice.
    // If a field is absent or empty, it matches all clients.
    // All fields must match a client for this choice to be selected.
    // If any unexpected field name is present in this object, the entire
    // config is considered invalid.
    //
    // Client language(s): a list of strings (e.g., "c++", "java", "go",
    // "python", etc).  Each string is case insensitive.
    "clientLanguage": [string],
    // Percentage: integer from 0 to 100 indicating the percentage of
    // clients that should use this choice.  If present, the number must
    // match the regular expression `^0|[0-9]|[1-9][0-9]|100$`
    // All other numbers are considered invalid.
    "percentage": number,
    // Client hostname(s): a list of strings.  Each name is case 
    // sensitive and must be an exact match of the hostname according to
    // the system.
    "clientHostname": [string],

    // The service config data object for clients that match the above
    // criteria.  (The format for this object is defined in
    // https://github.com/grpc/grpc/blob/master/doc/service_config.md.)
    // If this field is not an object, or is missing, or is otherwise 
    // invalid, the entire config is considered invalid.
    "serviceConfig": object
  }
]

如果服务配置选择不能被解析,或者在其他方面语义上无效,整个配置必须按照 Service Config Error Handling 丢弃。

在DNS TXT记录中编码

在DNS中,服务配置数据(以上一节中记录的形式)将通过RFC-1464中描述的机制,使用属性名 grpc_config 在TXT记录中进行编码。属性值将是一个包含服务配置选择的JSON列表。TXT记录将是一个与gRPC服务器名称相同的DNS名称,但前缀为 _grpc_config. ……

例如,这里是服务器 myserver 的 TXT 记录示例:

_grpc_config.myserver  3600  TXT "grpc_config=[{\"serviceConfig\":{\"loadBalancingPolicy\":\"round_robin\",\"methodConfig\":[{\"name\":[{\"service\":\"MyService\",\"method\":\"Foo\"}],\"waitForReady\":true}]}}]"

请注意,根据RFC-1035第3.3节的规定,TXT记录每个字符串限制为255字节。然而,可以有多个字符串,它们将被连接在一起,如RFC-4408第3.1.3节所述。总的DNS响应不能超过65535字节。(更多讨论请参见下面的 “未解决的问题 “部分。)

需要注意的是,由于TXT记录必须是ASCII码,这也限制了服务配置的内容也是ASCII码(如服务和方法名称、负载均衡策略名称等)。

理由

服务配置被设计为作为名称解析的一部分而返回,所以在DNS中进行编码是最合理的。当然,使用 DNS 以外的其他命名系统的网站可以用自己的机制实现自己的解析器,对服务配置数据进行编码。

当在DNS中对服务配置进行编码时,TXT记录是 “显而易见 “的选择,因为服务配置实际上是与DNS名称相关联的附加元数据。

我们在DNS条目中使用 _grpc_config 前缀,允许为主记录为CNAME记录的服务指定服务配置,因为DNS不允许为包含CNAME记录的同一名称指定任何其他记录。

实现

在C-core中,作为c-ares DNS解析器的一部分,已经完成了实施。我们目前正在努力使c-ares解析器成为C-core的默认DNS解析器。这需要诸如Windows和Node的支持,以及增加地址排序。

未解决的问题(如果适用)

DNS TXT记录确实有一些限制,这里需要考虑到。尤其是

  • 如果DNS响应超过512字节 就会从UDP退回到TCP,这就增加了开销
  • DNS的总响应不能超过65535字节。
  • 目前还不清楚各个DNS实现是否会允许接近65535字节,尽管规范中说应该允许。

请反馈这些考虑因素是否会成为本设计的重大缺点(在这种情况下,很可能要改变设计)。