Snowpark Container Services:使用服务

Snowpark Container Services 使您能够轻松部署、管理和扩展容器化应用程序。创建应用程序并将应用程序映像上传到 Snowflake 账户中的存储库后,您就可以将应用程序容器作为服务运行。

服务表示 Snowflake 在 计算池 上运行您的容器化应用程序,计算池是虚拟机 (VM) 节点的集合。服务分为两类:

  • 长期运行的服务。 长期运行的服务就像不会自动结束的 Web 服务。创建服务后,Snowflake 会管理正在运行的服务。例如,如果某个服务容器出于某种原因停止,Snowflake 会重新启动该容器,以便服务不间断地运行。

  • 作业服务。 作业服务会在代码退出时终止,与存储过程类似。当所有容器都退出时,作业服务便已完成。

Snowpark Container Services 提供了一组 SQL 命令,您可以使用这些命令创建并管理服务。这些对象包括:

启动服务

启动服务所需的最低限度信息包括:

  • 名称: 服务的名称。

  • 服务规范:规范 为 Snowflake 提供运行服务所需的信息。规范是一个 YAML 文件。

  • 计算池: Snowflake 在指定的 计算池 中运行您的服务。

创建长期服务

使用 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
       $$;
    
    Copy
  • 使用暂存区信息创建服务。在生产环境中部署服务时,建议应用关注点分离设计原则,并将规范上传到一个暂存区,提供暂存区信息 CREATE SERVICE 命令,如下所示:

    CREATE SERVICE echo_service
      IN COMPUTE POOL tutorial_compute_pool
      FROM @tutorial_stage
      SPECIFICATION_FILE='echo_spec.yaml';
    
    Copy

执行作业服务

使用 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"
       $$;
    
    Copy
  • 使用暂存区信息执行作业服务:

    EXECUTE JOB SERVICE
      IN COMPUTE POOL tutorial_compute_pool
      NAME = example_job_service
      FROM @tutorial_stage
      SPECIFICATION_FILE='my_job_spec.yaml';
    
    Copy

使用规范模板

有时,您可能希望使用相同的规范创建多项服务,但采用不同的配置。例如,假设您以一种服务规范定义了一个 环境变量,并且您希望使用相同的规范创建多项服务,但环境变量的值不同。

借助规范模板,您可以为规范中的字段值定义变量。在创建服务时,您需要为这些变量提供值。

使用规范模板的流程分为两个步骤:

  1. 使用变量作为各种规范字段的值来创建规范。使用 {{ 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:
      
    
    Copy
  2. 在 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');
    
    Copy

在规范中定义变量的准则

  • 使用 {{ variable_name }} 语法将变量定义为规范中的字段值。

  • 这些变量可以具有默认值。要指定默认值,请在变量声明中使用 default 函数。例如,以下规范定义具有默认值的两个变量(character_nameendpoint_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
    
    Copy

    此外,您还可以为 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
    
    Copy

    在规范中:

    • 对于 character_name 变量,布尔参数设置为 false。因此,如果变量设置为此参数的空字符串值 (''),则该值将保留空值;不使用默认值(“Bob”)。

    • 对于 echo_endpoint 变量,布尔参数设置为 true。因此,如果向此参数传递空值,则使用默认值(“echo-endpoint”)。

    默认情况下,default 函数的布尔参数为 false

为规范变量传递值的准则

在 CREATE SERVICE 命令中指定 USING 参数,为变量提供值。USING 的一般语法是:

USING( var_name=>var_value, [var_name=>var_value, ... ] );
Copy

其中

  • 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]' );
    
    Copy
  • CREATE SERVICE 中的 USING 参数必须为规范变量提供值(规范为其提供默认值的变量除外)。否则,返回错误。

示例

以下示例显示如何使用规范模板创建服务。这些示例中的 CREATE SERVICE 命令使用内联规范。

示例 1:提供简单值

教程 1 中,您可以通过提供内联规范来创建服务。以下示例是该示例的修改版本,其中规范定义了两个变量:image_urlSERVER_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 );
Copy

在此 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
Copy

示例 2:提供 JSON 值

在教程 1 中,规范定义了两个环境变量(SERVER_PORTCHARACTER_NAME),如下所示:

spec:
 containers:
 - name: echo
   image: /tutorial_db/data_schema/tutorial_repository/my_echo_service_image:latest
   env:
     SERVER_PORT: 8000
     CHARACTER_NAME: Bob
   
Copy

您可以为 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"}' );
Copy

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"
Copy

在规范的模板版本中,您可以以 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"]$$ );
Copy

扩展服务

默认情况下,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;
Copy

当多个服务实例正在运行时,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;
Copy

有关更多信息,请参阅 CREATE SERVICE

备注

您不能运行一项作业服务的多个实例。

启用自动扩缩

要配置 Snowflake 以自动扩缩正在运行的服务实例数量,请按照以下步骤操作:

  1. 在服务规范文件中指定服务实例的 CPU 和内存要求。有关详细信息,请参阅 container.resources 字段。

    示例

    resources:
      requests:
       cpu: <cpu-units>
    
    Copy
  2. 运行 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:
  
  
$$;
Copy

收到请求后,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
Copy

ALTER SERVICE 可能会影响与服务的通信(请参阅 使用服务)。

  • 如果 ALTER SERVICE ...<fromSpecification> 移除了一个端点或移除了使用端点时所需的相关权限(请参阅 规范参考中的 serviceRoles),则对服务的访问将失败。有关更多信息,请参阅 使用服务

  • 在升级过程中,新连接可能会路由到新版本。如果新服务版本不向后兼容,它将中断任何正在进行的服务使用。例如,使用服务函数的持续查询可能会失败。

备注

当更新的服务代码是带容器的原生应用程序的一部分时,您可以使用 SYSTEM$WAIT_FOR_SERVICES 系统函数暂停原生应用程序设置脚本,以允许服务完全升级。有关更多信息,请参阅 升级应用程序

监控滚动升级

当多个服务实例运行时,Snowflake 会根据服务实例的 ID 降序执行滚动升级。使用以下命令监控服务升级:

  • DESCRIBE SERVICESHOW 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 权限。客户端 指的是向另一个服务的端点发出请求的服务函数或服务。

    • 要创建引用端点的 服务函数,用户需要对端点具有访问权限。也就是说,服务函数的所有者角色需要对在 CREATE FUNCTION 中引用的端点具有 USAGE 权限。

    • 服务到服务通信 中,客户端服务的所有者角色(即调用其他服务的端点)需要对端点具有 USAGE 权限。

  • 从 Snowflake 外部向公共端点发出 入口 请求的用户需要对端点具有 USAGE 权限。

服务角色 是一种机制,用于为其他角色授予对服务端点的权限。您有以下选项:

  • 使用默认服务角色 Snowflake 定义了一个默认服务角色 (ALL_ENDPOINTS_USAGE),授予对服务公开的所有端点的 USAGE 权限,并向服务的所有者角色授予此默认服务角色。因此,所有者角色可以访问服务公开的所有端点。您可以向其他角色授予此默认服务角色。

  • 创建服务角色: 您可以在 服务规范 中定义一个或多个服务角色,而不是使用默认服务角色授予对所有端点的权限。在定义中,指明角色获得的 USAGE 权限所针对的特定端点。您可以使用 GRANT SERVICE ROLEREVOKE SERVICE ROLE 命令,向其他角色授予(或撤销)服务角色。您还可以使用 SHOW ROLES IN SERVICESHOW 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;
Copy

使用 some_other_role 的用户对所有服务端点都拥有 USAGE 权限。

删除服务时,Snowflake 会删除与服务相关联的所有服务角色(默认服务角色和服务规范中定义的服务角色),并取消所有服务角色授予。

使用规范中定义的服务角色授予对特定端点的 USAGE 权限

使用服务角色管理对服务端点的精细访问。您可以在服务规范中定义服务角色,以及授予其 USAGE 权限的端点列表。

向服务的特定端点授予权限分为两个步骤:

  1. 定义服务角色: 使用服务规范来定义服务角色,方法是提供角色名称,以及包含一个或多个您像向其授予 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>
    
    Copy
  2. 将服务角色授予其他角色。 使用 GRANT SERVICE ROLE 命令,可将服务角色授予其他角色(账户角色、应用程序角色或数据库角色)。例如:

    GRANT SERVICE ROLE <service-name>!<svc_role_name1> TO ROLE <another-role>
    
    Copy

使用服务

创建服务后,同一账户(创建了服务)中的用户可以使用以下三种受支持方法中的任何一种来使用该服务。用户将需要访问具有必要权限的角色。

  • **通过 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
Copy

echoendpoint 是一个用户友好型端点名称,代表相应的端口 (8080)。要与此服务端点通信,需要提供 SERVICE 和ENDPOINT 参数,创建一个服务函数,如下所示:

CREATE FUNCTION my_echo_udf (text varchar)
   RETURNS varchar
   SERVICE=echo_service
   ENDPOINT=echoendpoint
   AS '/echo';
Copy

AS 参数提供服务代码的 HTTP 路径。您可以从服务代码中获取此路径值。例如,以下代码行来自 教程 1 中的 service.py

@app.post("/echo")
def echo():
...
Copy

调用服务函数时,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
Copy

数据交换格式

对于服务函数和应用程序容器之间的数据交换,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;
Copy

Snowflake 会向容器发送一系列请求,请求正文中的数据行批次格式如下:

{
   "data":[
      [
         0,
         "Alex",
         "2014-01-01 16:00:00"
      ],
      [
         1,
         "Steve",
         "2015-01-01 16:00:00"
      ],
      …
      [
         <row_index>,
         "<column1>",
         "<column2>"
      ],
   ]
}
Copy

然后,容器会以以下格式返回输出结果:

{
   "data":[
      [0, "a"],
      [1, "b"],
      …
      [ row_index,  output_column1]
   ]
}
Copy

所示输出示例假定结果是一个单列表,包含行(“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');
Copy

入口:使用来自 Snowflake 外部的服务

一项服务可以 公开 一个或多个端点,允许用户从公共网络使用该服务。 在这种情况下,Snowflake 会管理访问控制。请注意,仅允许通过 HTTP 或 HTTPS 端点使用入口。

在服务规范文件中将端点标记为公共端点:

spec
  ...
  endpoints
  - name: <endpoint name>
    port: <port number>
    public: true
Copy

来自 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
Copy

在代码中:

  • 如果您不知道自己的账户信息 (<orgname>-<acctname>),请参阅教程 常用设置

  • 您可以使用 SHOW ENDPOINTS 获取服务公开的公共端点的 ingress_url

入口请求中的用户特定标头

当入口端点的请求到达时,Snowflake 会自动将以下标头连同 HTTP 请求一起传递给容器。

Sf-Context-Current-User: <user_name>
Copy

您的容器代码可以选择读取标头信息,知道调用者是谁,并为不同用户应用特定于上下文的自定义。此外,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 除外。

准则和限制

有关更多信息,请参阅 准则和限制

语言: 中文