Snowpark Container Services:使用服务¶
Snowpark Container Services 使您能够轻松部署、管理和扩展容器化应用程序。创建应用程序并将应用程序映像上传到 Snowflake 账户中的存储库后,您就可以将应用程序容器作为服务运行。
服务表示 Snowflake 在 计算池 上运行您的容器化应用程序,计算池是虚拟机 (VM) 节点的集合。服务分为两类:
长期运行的服务。 长期运行的服务就像不会自动结束的 Web 服务。创建服务后,Snowflake 会管理正在运行的服务。例如,如果某个服务容器出于某种原因停止,Snowflake 会重新启动该容器,以便服务不间断地运行。
作业服务。 作业服务会在代码退出时终止,与存储过程类似。当所有容器都退出时,作业服务便已完成。
Snowpark Container Services 提供了一组 SQL 命令,您可以使用这些命令创建并管理服务。这些对象包括:
更改服务。 ALTER SERVICE、DROP SERVICE
获取服务信息。 SHOW SERVICES、DESCRIBE SERVICE
启动服务¶
启动服务所需的最低限度信息包括:
创建长期服务¶
使用 CREATE SERVICE 创建长期运行的服务。
使用内联规范创建服务。大多数情况下,在开发过程中,您可以选择内联规范,如下所示:
CREATE SERVICE echo_service IN COMPUTE POOL tutorial_compute_pool FROM SPECIFICATION $$ spec: containers: - name: echo image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:tutorial readinessProbe: port: 8000 path: /healthcheck endpoints: - name: echoendpoint port: 8000 public: true $$;
使用暂存区信息创建服务。在生产环境中部署服务时,建议应用关注点分离设计原则,并将规范上传到一个暂存区,提供暂存区信息 CREATE SERVICE 命令,如下所示:
CREATE SERVICE echo_service IN COMPUTE POOL tutorial_compute_pool FROM @tutorial_stage SPECIFICATION_FILE='echo_spec.yaml';
执行作业服务¶
使用 EXECUTE JOB SERVICE 创建作业服务。此命令同步运行,在作业服务的所有容器退出后返回响应。
使用内联规范执行作业服务:
EXECUTE JOB SERVICE IN COMPUTE POOL tutorial_compute_pool NAME = example_job_service FROM SPECIFICATION $$ spec: container: - name: main image: /tutorial_db/data_schema/tutorial_repository/my_job_image:latest env: SNOWFLAKE_WAREHOUSE: tutorial_warehouse args: - "--query=select current_time() as time,'hello'" - "--result_table=results" $$;
使用暂存区信息执行作业服务:
EXECUTE JOB SERVICE IN COMPUTE POOL tutorial_compute_pool NAME = example_job_service FROM @tutorial_stage SPECIFICATION_FILE='my_job_spec.yaml';
使用规范模板¶
有时,您可能希望使用相同的规范创建多项服务,但采用不同的配置。例如,假设您以一种服务规范定义了一个 环境变量,并且您希望使用相同的规范创建多项服务,但环境变量的值不同。
借助规范模板,您可以为规范中的字段值定义变量。在创建服务时,您需要为这些变量提供值。
使用规范模板的流程分为两个步骤:
使用变量作为各种规范字段的值来创建规范。使用
{{ variable_name }}
语法来指定这些变量。例如,以下规范为镜像标签名称使用名为“tag_name”的变量,以便您可以为每项服务指定不同的镜像标签。spec: containers: - name: echo image: myorg-myacct.registry.snowflakecomputing.cn/tutorial_db/data_schema/tutorial_repository/my_echo_service_image:{{ tag_name }} ... endpoints: …
在 CREATE SERVICE 命令中提供规范模板,以创建服务。您使用 SPECIFICATION_TEMPLATE 或 SPECIFICATION_TEMPLATE_FILE 指定模板。使用 USING 参数指定变量的值。 例如,以下语句使用来自 Snowflake 暂存区的规范模板。USING 参数将
tag_name
变量设置为值'latest'
。CREATE SERVICE echo_service IN COMPUTE POOL tutorial_compute_pool FROM @STAGE SPECIFICATION_TEMPLATE_FILE='echo.yaml' USING (tag_name=>'latest');
在规范中定义变量的准则¶
使用
{{ variable_name }}
语法将变量定义为规范中的字段值。这些变量可以具有默认值。要指定默认值,请在变量声明中使用
default
函数。例如,以下规范定义具有默认值的两个变量(character_name
和endpoint_name
)。spec: containers: - name: echo image: <image_name> env: CHARACTER_NAME: {{ character_name | default('Bob') }} SERVER_PORT: 8085 endpoints: - name: {{ endpoint_name | default('echo-endpoint') }} port: 8085
此外,您还可以为
default
函数指定可选布尔参数,以指示是否要在为变量传递空白值时使用默认值。请考虑以下规范:spec: containers: - name: echo image: <image_name> env: CHARACTER_NAME: {{ character_name | default('Bob', false) }} SERVER_PORT: 8085 endpoints: - name: {{ endpoint_name | default('echo-endpoint', true) }} port: 8085
在规范中:
对于
character_name
变量,布尔参数设置为false
。因此,如果变量设置为此参数的空字符串值 (''),则该值将保留空值;不使用默认值(“Bob”)。对于
echo_endpoint
变量,布尔参数设置为true
。因此,如果向此参数传递空值,则使用默认值(“echo-endpoint”)。
默认情况下,
default
函数的布尔参数为false
。
为规范变量传递值的准则¶
在 CREATE SERVICE 命令中指定 USING 参数,为变量提供值。USING 的一般语法是:
USING( var_name=>var_value, [var_name=>var_value, ... ] );
其中
var_name
区分大小写,并且应该是有效的 Snowflake 标识符(请参阅 标识符要求)。var_value
可以是字母数字值或有效 JSON 值。示例:
-- Alphanumeric string and literal values USING(some_alphanumeric_var=>'blah123', some_int_var=>111, some_bool_var=>true, some_float_var=>-1.2) -- JSON string USING(some_json_var=>' "/path/file.txt" ') -- JSON map USING(env_values=>'{"SERVER_PORT": 8000, "CHARACTER_NAME": "Bob"}' ); -- JSON list USING (ARGS='["-n", 2]' );
CREATE SERVICE 中的 USING 参数必须为规范变量提供值(规范为其提供默认值的变量除外)。否则,返回错误。
示例¶
以下示例显示如何使用规范模板创建服务。这些示例中的 CREATE SERVICE 命令使用内联规范。
示例 1:提供简单值¶
在 教程 1 中,您可以通过提供内联规范来创建服务。以下示例是该示例的修改版本,其中规范定义了两个变量:image_url
和 SERVER_PORT
。请注意,SERVER_PORT
变量在三个地方重复使用。这样可以实现使用变量的额外优势,即确保所有这些字段像预期一样具有相同的值。
CREATE SERVICE echo_service
IN COMPUTE POOL tutorial_compute_pool
MIN_INSTANCES=1
MAX_INSTANCES=1
FROM SPECIFICATION_TEMPLATE $$
spec:
containers:
- name: echo
image: {{ image_url }}
env:
SERVER_PORT: {{SERVER_PORT}}
CHARACTER_NAME: Bob
readinessProbe:
port: {{SERVER_PORT}}
path: /healthcheck
endpoints:
- name: echoendpoint
port: {{SERVER_PORT}}
public: true
$$
USING (image_url=>' "/tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest" ', SERVER_PORT=>8000 );
在此 CREATE SERVICE 命令中,USING 参数为两个规范变量提供值。image_url
值包括斜杠和冒号。这些不是字母数字字符。因此,该示例将值引在双引号中,使其成为有效的 JSON 字符串值。模板规范扩展了以下规范:
spec:
containers:
- name: echo
image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
env:
SERVER_PORT: 8000
CHARACTER_NAME: Bob
readinessProbe:
port: 8000
path: /healthcheck
endpoints:
- name: echoendpoint
port: 8000
public: true
示例 2:提供 JSON 值¶
在教程 1 中,规范定义了两个环境变量(SERVER_PORT
和 CHARACTER_NAME
),如下所示:
spec:
containers:
- name: echo
image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
env:
SERVER_PORT: 8000
CHARACTER_NAME: Bob
…
您可以为 env
字段使用变量,以此模板化此规范。这允许您创建多项服务,为环境变量使用不同的值。以下 CREATE SERVICE 命令为 env 字段使用变量 (env_values
)。
CREATE SERVICE echo_service
IN COMPUTE POOL tutorial_compute_pool
MIN_INSTANCES=1
MAX_INSTANCES=1
FROM SPECIFICATION_TEMPLATE $$
spec:
containers:
- name: echo
image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
env: {{env_values}}
readinessProbe:
port: {{SERVER_PORT}} #this and next tell SF to connect to port 8000
path: /healthcheck
endpoints:
- name: echoendpoint
port: {{SERVER_PORT}}
public: true
$$
USING (env_values=>'{"SERVER_PORT": 8000, "CHARACTER_NAME": "Bob"}' );
CREATE SERVICE 中的 USING 参数为 env_values
变量提供值。该值是 JSON 映射,为两个环境变量提供值。
示例 3:提供列表作为变量值¶
在 教程 2 中,该规范包括 args
字段,其中包含两个实参。
spec:
container:
- name: main
image: /tutorial_db/data_schema/tutorial_repository/my_job_image:latest
env:
SNOWFLAKE_WAREHOUSE: tutorial_warehouse
args:
- "--query=select current_time() as time,'hello'"
- "--result_table=results"
在规范的模板版本中,您可以以 JSON 列表的形式提供这些实参,如下所示:
spec:
container:
- name: main
image: /tutorial_db/data_schema/tutorial_repository/my_job_image:latest
env:
SNOWFLAKE_WAREHOUSE: tutorial_warehouse
args: {{ARGS}}
$$
USING (ARGS=$$["--query=select current_time() as time,'hello'", "--result_table=results"]$$ );
扩展服务¶
默认情况下,Snowflake 会在指定的计算池中运行一个服务实例。要管理繁重的工作负载,您可以通过设置 MIN_INSTANCES 和 MAX_INSTANCES 属性运行多个服务实例,这两个属性指定了服务启动时的最小实例数和需要时 Snowflake 可扩展到的最大实例数。
示例
CREATE SERVICE echo_service
IN COMPUTE POOL tutorial_compute_pool
FROM @tutorial_stage
SPECIFICATION_FILE='echo_spec.yaml'
MIN_INSTANCES=2
MAX_INSTANCES=4;
当多个服务实例正在运行时,Snowflake 会自动提供一个负载均衡器来分配传入请求。
Snowflake 不会将服务视为 READY,直到至少有两个实例可用。当服务尚未准备就绪时,Snowflake 会阻止对它的访问,这意味着在确认准备就绪之前,关联的服务函数或入口请求会遭据。
在某些情况下,您可能希望 Snowflake 将服务视为就绪(并转发传入请求),即使可用的实例数少于指定的最小实例数也是如此。您可以通过设置 MIN_READY_INSTANCES 属性来实现此目标。
考虑另一种情况:在维护或滚动服务升级期间,Snowflake 可能会终止一个或多个服务实例。这可能会导致可用实例少于指定的 MIN_INSTANCES,使得服务不处于 READY 状态。在这种情况下,您可能希望将 MIN_READY_INSTANCES 设置为小于 MIN_INSTANCES 的值,以确保服务可以继续接受请求。
示例
CREATE SERVICE echo_service
IN COMPUTE POOL tutorial_compute_pool
FROM @tutorial_stage
SPECIFICATION_FILE='echo_spec.yaml'
MIN_INSTANCES=2
MAX_INSTANCES=4
MIN_READY_INSTANCES=1;
有关更多信息,请参阅 CREATE SERVICE。
备注
您不能运行一项作业服务的多个实例。
启用自动扩缩¶
要配置 Snowflake 以自动扩缩正在运行的服务实例数量,请按照以下步骤操作:
在服务规范文件中指定服务实例的 CPU 和内存要求。有关详细信息,请参阅 container.resources 字段。
示例
resources: requests: cpu: <cpu-units>
运行 CREATE SERVICE 命令时,设置 MIN_INSTANCES 和 MAX_INSTANCES 参数。您还可以使用 ALTER SERVICE 更改这些值。当指定的 MAX_INSTANCES 大于 MIN_INSTANCES 时,会发生自动扩缩。
Snowflake 首先在指定的计算池上创建最小数量的服务实例。然后,Snowflake 根据 80% CPU 使用率阈值扩展或缩减服务实例的数量。Snowflake 持续监控计算池内的 CPU 利用率,汇总来自所有当前正在运行的服务实例的使用率数据。
当汇总的 CPU 使用率(跨所有服务实例)超过 80% 时,Snowflake 会在计算池中部署额外的服务实例。如果汇总的 CPU 使用率低于 80%,Snowflake 会通过移除正在运行的服务实例来缩减规模。Snowflake 使用五分钟的稳定窗口来防止频繁扩缩。
请注意以下扩缩行为:
服务实例的扩缩受限于为服务配置的 MIN_INSTANCES 和 MAX_INSTANCES 参数。
如果需要扩大规模,而计算池节点缺乏启动另一个服务实例所需的资源能力,则可以触发计算池自动扩缩。有关更多信息,请参阅 计算池节点的自动扩缩。
如果您在创建服务时指定 MAX_INSTANCES 和 MIN_INSTANCES 参数,但没有在服务规范文件中为服务实例指定 CPU 和内存要求,则不会发生自动扩缩;Snowflake 会以 MIN_INSTANCES 属性指定的实例数启动,不会自动扩缩。
修改和删除服务¶
创建服务后:
使用 DROP SERVICE 命令从架构中移除服务(Snowflake 终止所有服务容器)。
使用 ALTER SERVICE 命令修改服务(例如,暂停或恢复服务、更改正在运行的实例数,以及指示 Snowflake 使用新的服务规范来重新部署服务)。
备注
您不能更改作业服务。
服务终止¶
当您暂停服务 (ALTER SERVICE ...SUSPEND) 或删除服务 (DROP SERVICE) 时,Snowflake 会终止所有服务实例。同样,当您升级服务代码 (ALTER SERVICE ...<fromSpecification>) 时,Snowflake 会一次终止并重新部署一个服务实例,以应用 滚动升级。
在终止服务实例时,Snowflake 会首先将 SIGTERM 信号发送到每个服务容器。容器可以选择处理信号并在 30 秒的窗口内正常关闭。否则,宽限期过后,Snowflake 会终止容器中的所有进程。
更新服务代码并重新部署服务¶
创建服务后,使用 ALTER SERVICE … <fromSpecification> 命令更新服务代码并重新部署服务。
您首先要将修改后的应用程序代码上传到镜像仓库,然后调用 ALTER SERVICE,以提供内联服务规范或在 Snowflake 暂存区中指定规范文件的路径。例如:
ALTER SERVICE echo_service
FROM SPECIFICATION $$
spec:
…
…
$$;
收到请求后,Snowflake 会使用新代码重新部署服务。
当您运行 CREATE SERVICE ...<from-Specification> 命令时,Snowflake 会记录所提供镜像的特定版本。在以下情况下,Snowflake 会部署相同的镜像版本,即使仓库中的镜像已更新也是如此:
当恢复暂停的服务时(使用 ALTER SERVICE ...RESUME)。
当自动扩缩添加更多服务实例时。
当在集群维护期间重新启动服务实例时。
但是,如果您调用 ALTER SERVICE ...<fromSpecification>,则会触发 Snowflake 使用仓库中该镜像的最新版本。
如果您是服务所有者,则 DESCRIBE SERVICE 命令的输出包括服务规范,其中包括镜像摘要(规范中 sha256
字段的值),如下所示:
spec:
containers:
- name: "echo"
image: "/tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest"
sha256: "@sha256:8d912284f935ecf6c4753f42016777e09e3893eed61218b2960f782ef2b367af"
env:
SERVER_PORT: "8000"
CHARACTER_NAME: "Bob"
readinessProbe:
port: 8000
path: "/healthcheck"
endpoints:
- name: "echoendpoint"
port: 8000
public: true
ALTER SERVICE 可能会影响与服务的通信(请参阅 使用服务)。
如果 ALTER SERVICE ...<fromSpecification> 移除了一个端点或移除了使用端点时所需的相关权限(请参阅 规范参考中的 serviceRoles),则对服务的访问将失败。有关更多信息,请参阅 使用服务。
在升级过程中,新连接可能会路由到新版本。如果新服务版本不向后兼容,它将中断任何正在进行的服务使用。例如,使用服务函数的持续查询可能会失败。
备注
当更新的服务代码是带容器的原生应用程序的一部分时,您可以使用 SYSTEM$WAIT_FOR_SERVICES 系统函数暂停原生应用程序设置脚本,以允许服务完全升级。有关更多信息,请参阅 升级应用程序。
监控滚动升级¶
当多个服务实例运行时,Snowflake 会根据服务实例的 ID 降序执行滚动升级。使用以下命令监控服务升级:
DESCRIBE SERVICE 和 SHOW SERVICES:
如果服务正在升级,则输出中的
is_upgrading
列显示为 TRUE。输出中的
spec_digest
列表示当前服务规范的规范摘要。您可以定期执行此命令;spec_digest
值中的更改表示已触发服务升级。使用 SHOW SERVICE INSTANCES IN SERVICE 命令检查是否所有实例都已升级到最新版本,如下所述。
SHOW SERVICE INSTANCES IN SERVICE:
输出中的
status
列提供滚动升级过程中每个服务实例的状态。在升级过程中,您将观察每个服务实例的转换状态,例如 TERMINATING 至 PENDING,以及 PENDING 至 READY。在服务升级期间,SHOW SERVICE INSTANCES IN SERVICE 命令可能会在 SHOW SERVICES(始终返回最新的服务规范)的
spec_digest
输出中返回不同的值。它只是表示服务升级正在进行中,并且服务实例仍在运行旧版本的服务。
获取服务信息¶
您可以使用以下命令:
使用 DESCRIBE SERVICE 命令检索服务的属性和状态。
使用 SHOW SERVICES 命令列出您具有权限的当前服务(包括作业服务)。对于每项服务,输出提供服务的属性和状态。默认情况下,输出会列出当前数据库和架构中的服务。您还可以指定以下任何范围。例如:
列出账户、特定数据库或特定架构中的服务: 例如,使用 IN ACCOUNT 筛选器列出 Snowflake 账户中的服务,不管服务属于哪个数据库或架构。如果您在账户中的多个数据库和架构中创建了 Snowflake 服务,这将非常有用。与所有其他命令一样,SHOW SERVICES IN ACCOUNTS 也受权限限制,仅返回所使用角色有查看权限的服务。
您还可以指定 IN DATABASE 或 IN SCHEMA,以列出当前(或指定)数据库或架构中的服务。
列出在计算池中运行的服务: 例如,使用 IN COMPUTE POOL 筛选器列出计算池中运行的服务。
列出以前缀开头或与模式匹配的服务: 您可以应用 LIKE 和 STARTS WITH 筛选器,按名称筛选服务。
列出作业服务或从列表中排除作业服务: 您可以使用 SHOW JOB SERVICES 或 SHOW SERVICES EXCLUDE JOBS,仅列出作业服务或排除作业服务。
您还可以将这些选项组合起来,自定义 SHOW SERVICES 输出。
使用 SHOW SERVICE INSTANCES IN SERVICE 命令检索服务实例的属性。
使用 SHOW SERVICE CONTAINERS IN SERVICE 命令检索服务实例的属性和状态。
监控服务¶
Snowpark Container Services 提供一些工具,用于监控账户中的计算池及其上运行的服务。有关更多信息,请参阅 Snowpark Container Services:监控服务。
管理对服务端点的访问¶
服务 所有者 角色(您用来创建服务的角色)对服务本身和服务所公开的端点具有完全访问权限。其他角色需要对端点具有 USAGE 权限才能与服务通信。例如:
客户端的所有者角色需要对端点拥有 USAGE 权限。客户端 指的是向另一个服务的端点发出请求的服务函数或服务。
从 Snowflake 外部向公共端点发出 入口 请求的用户需要对端点具有 USAGE 权限。
服务角色 是一种机制,用于为其他角色授予对服务端点的权限。您有以下选项:
使用默认服务角色 Snowflake 定义了一个默认服务角色 (
ALL_ENDPOINTS_USAGE
),授予对服务公开的所有端点的 USAGE 权限,并向服务的所有者角色授予此默认服务角色。因此,所有者角色可以访问服务公开的所有端点。您可以向其他角色授予此默认服务角色。创建服务角色: 您可以在 服务规范 中定义一个或多个服务角色,而不是使用默认服务角色授予对所有端点的权限。在定义中,指明角色获得的 USAGE 权限所针对的特定端点。您可以使用 GRANT SERVICE ROLE 和 REVOKE SERVICE ROLE 命令,向其他角色授予(或撤销)服务角色。您还可以使用 SHOW ROLES IN SERVICE、SHOW GRANTS 命令,显示有关授权的信息。
在您创建服务时,Snowflake 会创建服务角色;在您删除服务时,会删除服务角色。
创建自定义服务角色,允许您针对不同的场景授予不同的访问权限。例如,您可以向服务角色授予对端点的权限,以用于服务函数。您可以创建另一个服务角色,并赋予其对用于 Web UI 的公共端点的权限。
请注意以下事项:
如果使用同一角色创建多项服务,由于所有者角色可以访问所有端点,因此这些服务之间可以无缝通信,无需任何额外配置更改。
如果一项服务有多个容器,这些容器可以通过本地主机相互通信,这些通信是每个服务实例内部的本地通信,不受基于角色的访问控制的限制。
以下各节提供了详细信息。您也可以尝试学习一个教程(配置和测试服务端点权限),其中提供了分步探索此功能的说明。
使用默认服务角色授予对所有端点的 USAGE 权限¶
创建服务(包括作业服务)时,Snowflake 还会创建默认服务角色,名为 ALL_ENDPOINTS_USAGE
。此角色对服务公开的所有端点都拥有 USAGE 权限。您可以使用 GRANT SERVICE ROLE 命令将此默认服务角色授予其他角色:
GRANT SERVICE ROLE my_echo_service_image!ALL_ENDPOINTS_USAGE TO ROLE some_other_role;
使用 some_other_role
的用户对所有服务端点都拥有 USAGE 权限。
删除服务时,Snowflake 会删除与服务相关联的所有服务角色(默认服务角色和服务规范中定义的服务角色),并取消所有服务角色授予。
使用规范中定义的服务角色授予对特定端点的 USAGE 权限¶
使用服务角色管理对服务端点的精细访问。您可以在服务规范中定义服务角色,以及授予其 USAGE 权限的端点列表。
向服务的特定端点授予权限分为两个步骤:
定义服务角色: 使用服务规范来定义服务角色,方法是提供角色名称,以及包含一个或多个您像向其授予 USAGE 权限的端点的列表。例如,在下面的规范片段中,顶级
serviceRoles
字段定义了两个服务角色,每个角色都对特定端点拥有 USAGE 权限。spec: ... serviceRoles: # Optional list of service roles - name: <svc_role_name1> endpoints: # endpoints that role can access - <endpoint_name1> - <endpoint_name2> - name: <svc_role_name2> endpoints: - <endpoint_name3> - <endpoint_name4>
将服务角色授予其他角色。 使用 GRANT SERVICE ROLE 命令,可将服务角色授予其他角色(账户角色、应用程序角色或数据库角色)。例如:
GRANT SERVICE ROLE <service-name>!<svc_role_name1> TO ROLE <another-role>
使用服务¶
创建服务后,同一账户(创建了服务)中的用户可以使用以下三种受支持方法中的任何一种来使用该服务。用户将需要访问具有必要权限的角色。
**通过 SQL 查询使用服务**(服务函数):您创建服务函数、与服务关联的用户定义的函数 (UDF),然后在 SQL 查询中使用函数,以与服务进行通信。有关示例,请参阅 教程 1。
**从 Snowflake 外部使用服务**(入口):您可以将一个或多个服务端点声明为公共端点,以允许对服务进行网络入口访问。有关示例,请参阅 教程 1。
**通过其他服务使用服务**(服务到服务通信):使用 Snowflake 针对服务到服务通信分配的服务 DNS 名称,服务可以相互进行通信。有关示例,请参阅 教程 3。
备注
作业服务像作业一样运行,并在完成后终止。不支持使用服务函数或入口与作业服务通信。
您不能将服务函数与作业服务的任何端点相关联。
您不能使用定义公共端点的规范来创建作业服务。
支持与作业服务进行服务到服务通信。也就是说,服务与作业服务可以相互通信。
以下各节提供了详细信息。
服务函数:使用 SQL 查询中的服务¶
服务函数是使用 CREATE FUNCTION (Snowpark Container Services) 创建的用户定义函数 (UDF)。不过,您不用直接编写 UDF 代码,而可将 UDF 与您的服务关联起来。请注意,您只能将服务函数与支持 HTTP 或 HTTPS 协议的服务端点关联。
例如,在 教程 1 中,您创建了一个名为 echo_service
的服务,它公开了服务规范中定义的一个端点 (echoendoint):
spec:
…
endpoints:
- name: echoendpoint
port: 8080
echoendpoint
是一个用户友好型端点名称,代表相应的端口 (8080)。要与此服务端点通信,需要提供 SERVICE 和ENDPOINT 参数,创建一个服务函数,如下所示:
CREATE FUNCTION my_echo_udf (text varchar)
RETURNS varchar
SERVICE=echo_service
ENDPOINT=echoendpoint
AS '/echo';
AS
参数提供服务代码的 HTTP 路径。您可以从服务代码中获取此路径值。例如,以下代码行来自 教程 1 中的 service.py
。
@app.post("/echo")
def echo():
...
调用服务函数时,Snowflake 会将请求定向到相关联的服务端点和路径。
备注
服务函数用于与服务通信,而不是与作业通信。换句话说,您只能将服务(而不是作业)与服务函数关联起来。
在向服务发送数据时指定批次大小以提高并发性¶
当您运行服务的多个实例时,可以通过指定可选的 MAX_BATCH_ROWS
参数来创建服务函数,以限制 批量大小,即 Snowflake 批量发送到服务的最大行数。例如,假设 MAX_BATCH_ROWS
为 10,您调用 my_echo_udf
服务函数时输入 100 行。Snowflake 会将输入的行分成多个批次,每个批次最多有 10 行,然后向服务发送一系列请求,请求正文中包含批次中的行。当处理耗时过长时,配置批次大小会有所帮助,将行分布在所有可用服务器上也会有所帮助。
您可以使用 ALTER FUNCTION 更改服务函数。以下 ALTER FUNCTION 命令更改了与之关联的服务端点和批次大小:
ALTER FUNCTION my_echo_udf(VARCHAR)
SET SERVICE=other_service
ENDPOINT=otherendpoint
MAX_BATCH_ROWS=100
数据交换格式¶
对于服务函数和应用程序容器之间的数据交换,Snowflake 遵循外部函数使用的相同格式(请参阅 数据格式)。例如,假设有数据行存储在表 (input_table
) 中:
"Alex", "2014-01-01 16:00:00"
"Steve", "2015-01-01 16:00:00"
…
要将这些数据发送到服务,您需要将这些行作为参数传递,从而调用服务函数:
SELECT service_func(col1, col2) FROM input_table;
Snowflake 会向容器发送一系列请求,请求正文中的数据行批次格式如下:
{
"data":[
[
0,
"Alex",
"2014-01-01 16:00:00"
],
[
1,
"Steve",
"2015-01-01 16:00:00"
],
…
[
<row_index>,
"<column1>",
"<column2>"
],
]
}
然后,容器会以以下格式返回输出结果:
{
"data":[
[0, "a"],
[1, "b"],
…
[ row_index, output_column1]
]
}
所示输出示例假定结果是一个单列表,包含行(“a”、“b”...)。
当运行多个服务实例时,可以使用 MAX_BATCH_ROWS
参数创建一个服务函数,将输入行分配到所有可用服务器进行处理。有关更多信息,请参阅 在向服务发送数据时指定批次大小以提高并发性。
创建和管理服务函数所需的权限¶
要创建和管理服务函数,角色需要具备以下权限:
创建服务函数: 当前角色必须对正在引用的服务具有 USAGE 权限。
更改服务函数: 您可以更改服务函数并将其与其他服务关联。当前角色必须对新服务具有 USAGE 权限。
使用服务函数: 当前角色必须对服务函数具有 USAGE 权限,服务函数所有者角色必须对相关服务具有 USAGE 权限。
以下示例脚本显示了如何授予使用服务函数的权限:
USE ROLE service_owner;
GRANT USAGE ON service service_db.my_schema.my_service TO ROLE func_owner;
USE ROLE func_owner;
CREATE OR REPLACE test_udf(v VARCHAR)
RETURNS VARCHAR
SERVICE=service_db.my_schema.my_service
ENDPOINT=endpointname1
AS '/run';
SELECT test_udf(col1) FROM some_table;
ALTER FUNCTION test_udf(VARCHAR) SET
SERVICE = service_db.other_schema.other_service
ENDPOINT=anotherendpoint;
GRANT USAGE ON FUNCTION test_udf(varchar) TO ROLE func_user;
USE ROLE func_user;
SELECT my_test_udf('abcd');
入口:使用来自 Snowflake 外部的服务¶
一项服务可以 公开 一个或多个端点,允许用户从公共网络使用该服务。 在这种情况下,Snowflake 会管理访问控制。请注意,仅允许通过 HTTP 或 HTTPS 端点使用入口。
在服务规范文件中将端点标记为公共端点:
spec
...
endpoints
- name: <endpoint name>
port: <port number>
public: true
来自 Snowflake 外部的公共端点访问及身份验证¶
不是每个人都能访问服务公开的公共端点。仅当用户与服务位于同一 Snowflake 账户,并且对公共端点具有 USAGE 权限时,才能访问公共端点。您可以使用 服务角色 授予此权限。
这些用户可以使用浏览器或以编程方式访问公共端点。Snowflake 使用 OAuth 对这些请求进行身份验证:
使用浏览器访问公共端点: 当用户使用浏览器访问公共端点时,Snowflake 会提供自动重定向以进行用户身份验证。用户需要登录,并且在后台,用户登录从 Snowflake 生成 OAuth 令牌。然后使用 OAuth 令牌向服务端点发送请求。
以编程方式访问公共端点: 应用程序可以使用 密钥对身份验证,对公有端点的请求进行身份验证。在代码中,您通过密钥对生成 JSON Web 令牌 (JWT)、与 Snowflake 交换 JWT 令牌以获得 OAuth 令牌,然后使用 OAuth 令牌对服务公共端点的请求进行身份验证。
教程 1 提供分步说明,供您测试公共端点访问。
教程 1 中所示的密钥对身份验证是推荐方式,用于在访问公共端点时对请求进行身份验证。以下代码可用于身份验证,作为使用密钥对的替代方法;但是,不能保证该代码将与 Snowflake Connector for Python 的未来版本结合使用。此 Python 代码使用 Python 连接器首先生成表示您的身份的会话令牌。然后,该代码使用会话令牌登录到公共端点。
import snowflake.connector import requests ctx = snowflake.connector.connect( user="<username>",# username password="<password>", # insert password here account="<orgname>-<acct-name>", session_parameters={ 'PYTHON_CONNECTOR_QUERY_RESULT_FORMAT': 'json' }) # Obtain a session token. token_data = ctx._rest._token_request('ISSUE') token_extract = token_data['data']['sessionToken'] # Create a request to the ingress endpoint with authz. token = f'\"{token_extract}\"' headers = {'Authorization': f'Snowflake Token={token}'} # Set this to the ingress endpoint URL for your service url = 'http://<ingress_url>' # Validate the connection. response = requests.get(f'{url}', headers=headers) print(response.text) # Insert your code to interact with the application here在代码中:
如果您不知道自己的账户信息 (
<orgname>-<acctname>
),请参阅教程 常用设置。您可以使用 SHOW ENDPOINTS 获取服务公开的公共端点的
ingress_url
。
入口请求中的用户特定标头¶
当入口端点的请求到达时,Snowflake 会自动将以下标头连同 HTTP 请求一起传递给容器。
Sf-Context-Current-User: <user_name>
您的容器代码可以选择读取标头信息,知道调用者是谁,并为不同用户应用特定于上下文的自定义。此外,Snowflake 还可以选择包含 Sf-Context-Current-User-Email
标头。要包含此标头,请联系 ` Snowflake 支持部门 `_。
服务到服务通信¶
服务可使用 Snowflake 自动分配给每个服务的 DNS 名称相互通信。有关示例,请参阅 教程 3。请注意,如果创建服务端点仅为了允许服务到服务的通信,则应该使用 TCP 协议。
DNS 名称格式为:
<service-name>.<schema-name>.<db-name>.snowflakecomputing.internal
使用 /sql-reference/sql/show-services`(或 :doc:/sql-reference/sql/desc-service`)获取服务的 DNS 名称。前面的 DNS 名称是全名。在同一架构下创建的服务可以只使用 <service-name>
进行通信。处于同一数据库但不同架构的服务必须提供架构名称,例如 <service-name>.<schema-name>
。
Snowflake 允许由同一角色创建的服务之间的网络通信,并阻止由不同角色创建的服务之间的网络通信。如果您想防止服务之间相互通信(出于安全等原因),请使用不同的 Snowflake 角色来创建这些服务。
DNS 名称有以下限制:
您的数据库、架构或服务名称必须是有效的 DNS 标签。(另请参阅 ` <https://www.ietf.org/rfc/rfc1035.html#section-2.3.1 (https://www.ietf.org/rfc/rfc1035.html#section-2.3.1)> `_ )。否则,创建服务将失败。
Snowflake 将名称(数据库、架构和服务名称)中的下划线 (_) 替换为 DNS 名称中的短划线 (-)。
创建服务后,请勿更改数据库或架构名称,因为 Snowflake 不会更新服务的 DNS 名称。
DNS 名称仅用于在同一账户中运行的服务之间的 Snowflake 内部通信。从互联网访问此名称。
权限¶
权限 |
用途 |
备注 |
---|---|---|
USAGE |
要与服务通信,您需要 对服务端点具有 USAGE 权限。创建服务函数、使用公共端点和从其他服务连接时需要。 |
|
MONITOR |
监控服务并获取运行时状态。 |
|
OPERATE |
暂停或恢复服务。 |
|
OWNERSHIP |
完全控制服务。同一时间只有一个角色可以在特定对象上拥有此权限。 |
|
ALL [ PRIVILEGES ] |
向服务授予所有权限,OWNERSHIP 除外。 |
准则和限制¶
有关更多信息,请参阅 准则和限制。