1 - 名称解析的设计及文档
名称解析
- 文档:gRPC服务配置
服务配置
-
文档:gRPC服务配置
-
Proposal:Service Configs in DNS: 关于此提案的讨论在 https://groups.google.com/g/grpc-io/c/DkweyrWEXxU/discussion
-
service_config.proto: 超长内容,xds的配置也在里面
2 - 文档:gRPC名称解析
概述
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
orunix://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
oripv6:[::]:1234
port
是使用的端口。如果没有指定,使用443
- 可以指定多个逗号分隔的地址,地址形式为
今后还可以增加其他schema,如 “etcd”。
Resolver 插件
gRPC客户端类库将使用指定的schema来挑选合适的解析器插件,并将完全限定的名称字符串传递给它。
解析器应该能够联系权威机构(authority)并得到解析,然后将其返回给gRPC客户端类库。返回的内容包括:
-
解析的地址列表(包括IP地址和端口)。每个地址可以有一组与之相关的任意属性(键/值对),这些属性可用于从解析器向负载均衡策略传递信息。
-
service config
插件API允许解析器持续观察一个端点,并根据需要返回更新的解析。
3 - 文档: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
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字节,尽管规范中说应该允许。
请反馈这些考虑因素是否会成为本设计的重大缺点(在这种情况下,很可能要改变设计)。