设计高性能外部函数¶
本主题介绍外部函数的并发性、可靠性和可扩展性,包括有关使用异步外部函数的信息。
本主题内容:
异步与同步远程服务¶
远程服务可以是同步的,也可以是异步的。
- 同步:
对同步远程服务的调用是阻塞式调用。在结果准备就绪之前,远程服务不会发送任何响应。无法对服务进行轮询。
同步代码比异步代码更容易实现。
- 异步:
在调用方等待结果期间可以轮询异步远程服务。
异步处理降低了对于超时的敏感度。
有关异步服务的更多信息,请参阅 Microsoft 有关 异步请求-回复模式 (https://docs.microsoft.com/en-us/azure/architecture/patterns/async-request-reply) 的描述。(此信息的适用范围不限于 Microsoft Azure。)
同步远程服务接收 HTTP POST 请求,然后处理请求并返回结果。根据处理数据所需时间,从收到请求到返回结果之间可能会存在长时间的延迟。
异步远程服务接收 HTTP POST 请求,并返回表明已收到请求的确认(通常几乎是即时的)。然后,调用方 (Snowflake) 执行轮询循环,在该循环中发出一个或多个 HTTP GET 请求(通常每个请求之间会有较长时间的延迟)以检查异步处理的状态。GET 不会在请求正文中发送任何数据,但包含与原始 POST 标头相同的标头。
当远程服务超出代理服务(例如 Amazon API Gateway)等组件内置的超时时,异步远程服务很有用。
远程服务不一定是纯同步或纯异步形式。在不同的时间,远程服务可同步运行,也可异步运行,具体取决于请求中的数据量、正在处理的其他请求数量等因素。
Snowflake 的外部函数实现通常兼容同步和异步这两类第三方函数库。
下图对比了同步处理与异步处理。上面的路径是同步的。下面的路径(包括一个或多个 HTTP GET 请求)是异步的。
要查看同步和异步外部函数的示例,请参阅 Snowflake 函数示例。
同步远程服务¶
在用户调用外部函数之前,开发者和 Snowflake 账户管理员必须配置 Snowflake 以访问代理服务。通常,这些步骤大致按下方所示顺序完成(从上图右侧开始,向左朝着 Snowflake 移动)。
开发者必须编写远程服务,并且该远程服务必须通过 HTTPS 代理服务公开。例如,远程服务可能是在 AWS Lambda 上运行并通过 Amazon API Gateway 中的资源公开的 Python 函数。
在 Snowflake 中, ACCOUNTADMIN 或具有 CREATE INTEGRATION 权限的角色必须创建一个“API 集成”对象,该对象包含身份验证信息,使 Snowflake 能够与代理服务进行通信。API 集成是使用 SQL 命令 CREATE API INTEGRATION 创建的。
Snowflake 用户必须执行 SQL 命令 CREATE EXTERNAL FUNCTION。用户必须使用具有 API 集成的 USAGE 权限且具有创建函数的足够权限的角色。
备注
从加载将“在 Snowflake 之外执行”的代码的意义上讲, CREATE EXTERNAL FUNCTION 命令实际上并没有创建外部函数。相反, CREATE EXTERNAL FUNCTION 命令会创建一个数据库对象,该对象 间接引用 在 Snowflake 外部执行的代码。更确切地说, CREATE EXTERNAL FUNCTION 命令创建了一个包含以下内容的对象:
HTTPS 代理服务中充当中继函数的资源的 URL。
用于对代理服务进行身份验证的 API 集成的名称。
实际上是远程服务别名的名称。此别名用于 SQL 命令,例如
SELECT MyAliasForRemoteServiceXYZ(col1) ...;
Snowflake 中的别名、HTTPS 代理服务资源的名称和远程服务的名称可能彼此不同。(但为三者使用相同的名称可以简化管理。)
尽管上述步骤是执行外部函数的最常见方式,但可以做一些调整。例如:
远程服务可能不是此链条中的最后一步;远程服务可以调用另一个远程服务来完成部分工作。
如果远程服务不接受和返回 JSON 格式的数据,则 HTTPS 代理服务的资源(中继函数)可将数据从 JSON 格式转换为另一种格式(并将返回的数据转换回 JSON)。
尽管 Snowflake 建议远程服务采用没有副作用、不保留任何状态信息的真正函数(即接受 0 个或更多输入参数并返回输出的一段代码)的行为方式,但这并非严格要求。远程服务可以执行其他任务,例如,在某个值(如数据中的温度读数)过高时发送警报。在极少数情况下,远程服务可能会保留状态信息,例如发出的警报总数。
异步远程服务¶
当远程服务超过代理服务等组件内置的超时时, 异步 远程服务很有用。
异步远程服务涉及到与上述相同的组件(客户端、Snowflake、代理服务和远程服务),以及与上述相同的一般步骤。但 HTTP 请求和响应的详细信息不同。
异步行为由编写远程服务的人员(以及 Snowflake)实现。异步远程服务的 SQL 语句与同步远程服务相同。
如果您正在编写自己的远程服务,且希望使其与 Snowflake 的异步处理兼容,请按如下方式编写远程服务的行为:
最初收到针对特定 批次 的行的 HTTP POST 时,远程服务返回 HTTP 代码 202(“正在处理...”)。
如果远程服务在 POST 之后、输出准备就绪之前收到任何 HTTP GET 请求,则返回 HTTP 代码 202。
在远程服务生成所有输出行后,它会等待具有相同批次 ID 的下一个 HTTP GET,然后返回接收到的行以及 HTTP 代码 200(“成功完成...”)。
简而言之,对于收到的每个批次,远程服务都会返回 202,直到结果准备就绪,随后下一个 GET 接收结果,再返回 HTTP 200。
对于每个批次,Snowflake 都使用异步远程服务,如下所示:
Snowflake 发送 HTTP POST,其中包含要处理的数据以及唯一批次 ID。
如果 Snowflake 收到 HTTP 202 响应,则 Snowflake 会进入循环,直到满足以下条件之一:
Snowflake 接收到数据和 HTTP 200。
已达到 Snowflake 的内部超时时间。
Snowflake 收到错误(例如 HTTP 响应代码 5XX)。
在循环的每次迭代中,Snowflake 都会延迟,然后发出 HTTP GET,其中包含的批次 ID 与响应方 HTTP POST 的批次 ID 相同,这样远程服务就可以返回正确批次的信息。
循环内部的延迟最初很短,但每次收到 HTTP 202 响应时,延迟就会延长,直至达到 Snowflake 的超时时间。
如果在返回 HTTP 200 之前就达到了 Snowflake 的超时时间,则 Snowflake 会中止 SQL 查询。
目前,Snowflake 的超时时间为 10 分钟(600 秒),用户不能对此进行配置。这个超时时间在未来可能会调整。
备注
从一定程度上来说,查询超时的频率取决于远程服务的可扩展性。如果远程服务经常超时,另请参阅有关 可扩展性 的讨论。
可扩展性¶
远程服务、代理服务以及 Snowflake 和远程服务之间的其他任何步骤都必须能处理发送给它们的峰值工作负载。
一些云平台提供商对代理服务和远程服务设有默认使用限制或其他配额,这可能会限制外部函数调用的吞吐量。
更大的 Snowflake 仓库大小 可增加发送请求的并发性,这可能会超过代理服务的配额。
通过查看查询简介中的 Retries due to transient errors 值,用户可以查看 Snowflake 必须(因限制或其他错误)为查询重试发送请求批次的次数。
远程服务的可扩展性¶
编写远程服务的开发者应该考虑:
远程服务的调用频率。
每次调用发送的行数。
处理每行所需的资源。
调用的时间分布(峰值与平均值)。
随着调用方从少数开发者和测试者转变为整个组织,容量可能需要随着时间的推移而增加。如果多个组织使用远程服务,则容量可能需要随着组织数量的增加而增加。此外,随着组织数量和多样性的增加,工作负载的大小和时间可能变得更加难以预测。
远程服务提供商负责提供足够的容量,以处理峰值工作负载。可以使用不同的技术来扩展服务。如果远程服务由其作者管理,则作者可能需要显式为该服务预配足够的容量,以处理峰值。或者,作者可能会决定使用托管的自动扩展/弹性服务,例如 AWS Lambda。
远程服务在超载时应返回 HTTP 响应代码 429。如果 Snowflake 看到 HTTP 429,则会降低其发送行的速率,并重试发送未成功处理的行批次。
有关排查可扩展性问题的更多信息,请参阅 排查可扩展性和性能问题。
如果远程服务调用超时的原因是每次调用都需要很长时间,而非系统普遍过载,请参见有关如何构建 异步远程服务 的说明。
代理服务的可扩展性¶
代理服务也应该具备可扩展性。幸运的是,主要云提供商提供的代理服务通常都具备可扩展型。
但部分代理服务存在默认的使用限制,包括 Amazon API Gateway 和 Azure API 管理在内。在请求速率超过该限制时,这些代理服务会对请求进行限制。如有必要,可以请 AWS 或 Azure 调高代理服务的配额。
开发或管理外部函数的用户应记住以下平台特定信息:
- Amazon API Gateway:
Amazon API Gateway 本身就是一项托管 AWS 服务,可根据用户的工作负载自动扩展。用户应该熟悉 ` API Gateway 的各种限制 <https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html (https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html)>`_。
可配置 Amazon API Gateway 以帮助扩展远程服务。具体而言,可以将 API Gateway 配置为启用请求的缓存和/或限制,以按需减少远程服务的负载:
启用缓存 (https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html)
启用限制 (https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html)
由于限制会影响超时和重试,用户可能还需要查看有关 Snowflake 如何处理超时和重试的信息:
- Azure API 管理服务:
对于 Azure API 管理,限制取决于为服务选择的 SKU。这些限制记录在 Azure 订阅服务限制 (https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#api-management-limits) 的“ API 管理限制”部分中。
由于限制会影响超时和重试,用户可能还需要查看有关 Snowflake 如何处理超时和重试的信息:
排查可扩展性和性能问题¶
使用 QUERY_HISTORY、QUERY_HISTORY_BY_* 函数观察性能特征,并帮助调试性能问题。
使用 Query Profile 页面 查看各请求的平均延迟。
使用 Query Profile 页面 查看由于瞬态错误(包括题为 请勿假定远程服务只传递每行一次 的部分中列出的错误)而重试请求的次数。
监控远程服务资源使用情况,以了解其如何扩展到负载,并确保远程服务有足够的容量来处理峰值负载。
登录 Amazon API Gateway 或远程服务,获取每个请求的详细信息。
控制 Snowflake 向其远程服务发送请求的并发性。有关更多详细信息,请参阅 并发性。
当远程服务超载时,从远程服务返回 HTTP 响应代码 429。应尽早返回,而非等待延迟增加。
考虑到代理服务的超时。例如,截至 2020 年 7 月,Amazon API Gateway 的超时时间为 30 秒。有多种因素可能导致超时,包括远程服务过载。
Snowflake 尝试在合理的时间内重试瞬态错误/超时,但是如果服务持续过载且重试不成功,查询最终会中止。
并发性¶
资源需求取决于行在多个调用之间的分布方式(这两种分布方式截然不同:许多并行调用但每个调用只有几行,或是总行数不变,但仅使用一个调用)。支持大容量的系统不一定支持高并发性,反之亦然。应该对所需峰值并发性及最大合理的单个工作负载进行估测,并提供足够的资源来处理这两种类型的峰值。
此外,并发估测应考虑到 Snowflake 可以并行处理外部函数调用。单个用户发出的单个查询可能会导致对远程服务的多次并行调用。有几个因素会影响从 Snowflake 到代理服务或远程服务的并发调用次数,其中包括:
如果外部函数有 副作用,则正确处理并发性可能特别复杂。结果可能因处理用户行的顺序而异。(Snowflake 建议避免编写或使用有副作用的远程服务。)
可靠性¶
根据远程服务的运行位置,您可能需要考虑以下因素:
可靠性。
错误处理。
调试。
升级(如果远程服务有可能添加新功能或需要修复错误)。
如果远程服务并非无状态,则可能还需要考虑在失败后恢复。(Snowflake 强烈建议将远程服务设置为无状态服务。)
有关超时和重试的信息,请参阅 考虑超时错误 和 请勿假定远程服务只传递每行一次。