Iceberg Rest Catalog
在介绍 Polaris 之前,先介绍下 Iceberg 的 Rest catalog。
Iceberg 支持众多 catalog,比如 Hive、Glue、Hadoop、REST 等等。这里面最为开放的就是 REST catalog。你只需要按照官方的 rest api spec 编写一个服务端处理 rest 请求,就可以完美对接众多计算引擎。Polaris 只是众多开源 rest catalog 实现中的一个。
官方 rest spec 地址:https://editor-next.swagger.io/?url=https://raw.githubusercontent.com/apache/iceberg/main/open-api/rest-catalog-open-api.yaml
知名的 Rest catalog 有哪些?
- Apache Polaris:https://github.com/apache/polaris/
- Unity Catalog:https://github.com/unitycatalog/unitycatalog
- LakeKeeper:https://github.com/lakekeeper/lakekeeper
- Tabular:https://www.tabular.io/
Polaris 是什么
Polaris 基于 Iceberg REST API 实现的开源 catalog 管理系统,使用 Java 实现。所有计算引擎只要正确支持了 Iceberg REST catalog,就能无缝连接 Polaris。
目前 Polaris 提供了两个主要特性:
- Access control:提供基于 RBAC 的权限控制。
- Vended-credentials:能够给接入的引擎颁发临时的云存储 credential,确保 ak/sk 密钥不被泄露。AWS Temporary Credentials。
Vended-credentials 这个是在 rest api 标准里面有的,只是说 Polaris 实现了这个标准。至于 RBAC 的 access control 是 Polaris 自己实现的。
Vended-credentials 需要接入的引擎在 header 头里面添加 X-Iceberg-Access-Delegation=vended-credentials
,Polaris 就会返回 Temporary Credentials。
Polaris 整体架构
Catalog(Warehouse)
Polaris 支持管理多个 catalog,每一个 catalog 管理自己的 namespace 和 table。
所有 catalog 都会关联一个存储,目前支持 S3
,Azure
,GCS
。FILE
则是用于本地测试,即把数据写在本地。
其实叫 warehouse 更为准确,因为在 Iceberg sdk 或 tabular 中,都以 warehouse 代称这里的 catalog。
Namespace
Namespace 是用于组织数据的逻辑单元。在 Polaris 中,namespace 可以进行嵌套。比如 a.b.c.d.e.f.g
就是一个嵌套的 namespace。
在 Iceberg 中,其实是没有传统的 database/schema 概念,所有的层级关系均由 namespace 来表达。只是说在 HiveCatalog/GlueCatalog 中,Iceberg 为了兼容其 Hive/Glue 的 database 概念,其会把第一层 namespace 当做 database 的名称。但是在 rest catalog 中,就没必要兼容 database 这种概念,所以它也就可以不断嵌套,这能让数据的组织更为灵活。
Table
Polaris tables 对应 Apache Iceberg tables。
View
Polaris views 对应 Apache Iceberg views。
API
Polaris 提供一个 management API 用于管理 Polaris,比如创建 catalog,管理 role 等等,本质上 CLI 工具就是通过构造 rest 请求操控 Polaris。
Access Control
Polaris 基于 role-based access control(RBAC) 模型管理数据权限。
关键概念
Securable object
Polaris 的权限控制细粒度可以到如下级别:
- Catalog
- Namespace
- Iceberg table
- View
Principal(Service Principal)
等同于 RBAC 中的 user。一个 principal 可以同时指定多个 principal role。
也可以叫 Service Principal
Principal role
等同于 RBAC 中的 role。Principal role 不会直接和 privilege 绑定,它是与 catalog role 和 principal 绑定。
Catalog role
所有 privilege 只能附加在 catalog role 上。
一个 catalog 上可以存在多个 catalog role。
Catalog role 和 principal role 是多对多模型。即一个 catalog role 可以赋予多个 principal role,一个 principal role 也可以同时被赋予多个 catalog role。
Privilege
指具体的权限,比如 CATALOG_MANAGE_CONTENT、LIST_NAMESPACES 等等。
具体参考:https://polaris.apache.org/in-dev/unreleased/access-control/#access-control-privileges
权限传递关系
整一个权限传递关系如下图所示:
Principal 关联 principal role,principal role 关联 catalog role,catalog role 关联一个具体的 catalog。Privilege 是赋予在 catalog role 之上。
下面这个图进一步阐释了这种关联关系:
比如 Data_engineer 这个 principal role 被赋予了三个 catalog role,分别是 Catalog contributor、Data administrator[Silver zone catalog] 和 Data administrator[Gold zone catalog]。
Principal role[Data_engineer] 被两个 principal[Streaming data loader、Spark ETL User] 关联。
Catalog[Glod zone catalog] 上同时创建了两个 catalog role(Data administrator、Catalog reader) 。
RBAC model
下图是 Polaris 使用的 RBAC 模型。对于每个 catalog,Polaris 管理员将 privilege 分配给 catalog role,然后通过将 catalog role 分配给 principal role 来授予 service principal 对 catalog 下资源的访问权限。
Metastore
Polaris 默认启动使用 in-memory
管理元信息,重启数据就没了。in-memory
仅为了方便测试使用,不推荐在生产环境上使用。
生成环境行你可以通过 Postgres 或 H2 持久化元信息,具体配置见:https://polaris.apache.org/in-dev/unreleased/metastores/
Usage
为了方便管理,Polaris 提供了基于 CLI 的管理工具。
CLI 语法如下:
polaris [options] COMMAND ...
options:
--host
--port
--client-id
--client-secret
COMMAND
必须是如下几种:
- catalogs
- principals
- principal-roles
- catalog-roles
- namespaces
- privileges
具体用法见:https://polaris.apache.org/in-dev/unreleased/command-line-interface/
实战演练
假设如下场景:公司为了测试数据库性能,需要频繁跑 tpch benchmark。为了防止 tpch 这个库被误操作,比如 DROP DB 这种,只会给员工们 read-only 权限。同时为了防止 AK/SK 密钥的泄露,不会告诉员工们任何云存储敏感信息。
接下来用 Polaris 来完成该需求:
启动 polaris,得到 root 用户的 client id 和 client secret。
./gradlew runApp
INFO [2024-10-26 15:33:09,242 - 1203 ] [main] [] i.d.c.s.DefaultServerFactory: Registering admin handler with root path prefix: /
INFO [2024-10-26 15:33:09,323 - 1284 ] [main] [] o.a.p.s.PolarisApplication: Initializing PolarisCallContextCatalogFactory for metaStoreManagerType org.apache.polaris.service.persistence.InMemoryPolarisMetaSt
oreManagerFactory@4715ae33
realm: default-realm root principal credentials: 379bdc7c7bde5bbb:955e67c0f6f290082697859617a7c589
INFO [2024-10-26 15:33:09,464 - 1425 ] [main] [] o.a.p.s.PolarisApplication: Server started successfully.
INFO [2024-10-26 15:33:09,464 - 1425 ] [main] [] i.d.core.server.ServerFactory: Starting PolarisApplication
注入 CLIENT_ID 和 CLIENT_SECRET 环境变量,这样后面 CLI 工具不需要每次指定 --client-id
和 --client-secret
了。
export CLIENT_ID=379bdc7c7bde5bbb
export CLIENT_SECRET=955e67c0f6f290082697859617a7c589
创建一个名为 starrocks_catalog
的 catalog,并且设置 S3 存储路径和 role-arn 信息。
./polaris catalogs create \
--storage-type s3 \
--default-base-location s3://smith-us-west-2/polaris \
--role-arn arn:aws:iam::181976408565:role/smith_role_s3 \
starrocks_catalog
➜ polaris git:(main) ✗ ./polaris catalogs list
{"type": "INTERNAL", "name": "starrocks_catalog", "properties": {"default-base-location": "s3://smith-us-west-2/polaris"}, "createTimestamp": 1729929740901, "lastUpdateTimestamp": 1729929740901, "entityVersion": 1, "storageConfigInfo": {"storageType": "S3", "allowedLocations": ["s3://smith-us-west-2/polaris"], "roleArn": "arn:aws:iam::181976408565:role/smith_role_s3"}}
在 starrocks_catalog
下面创建一个 tpch_namespace
,你可以认为就是一个叫 tpch_namespace
的 database。
./polaris namespaces create --catalog starrocks_catalog tpch_namespace
➜ polaris git:(main) ✗ ./polaris namespaces list --catalog starrocks_catalog
{"namespace": "tpch_namespace"}
接下来创建一个 principal role,不过我偷懒了,直接复用系统自带的 principal【service_admin】。
➜ polaris git:(main) ✗ ./polaris principal-roles list
{"name": "service_admin", "properties": {}, "createTimestamp": 1729929555085, "lastUpdateTimestamp": 1729929555085, "entityVersion": 1}
在 starrocks_catalog catalog 上创建一个 catalog role 名字叫 starrocks_catalog_role 并赋予 service_admin 这个 principal role。
./polaris \
catalog-roles \
create \
--catalog starrocks_catalog \
starrocks_catalog_role
➜ polaris git:(main) ✗ ./polaris catalog-roles list starrocks_catalog
{"name": "catalog_admin", "properties": {}, "createTimestamp": 1729929741255, "lastUpdateTimestamp": 1729929741255, "entityVersion": 1}
{"name": "starrocks_catalog_role", "properties": {}, "createTimestamp": 1729946138659, "lastUpdateTimestamp": 1729946138659, "entityVersion": 1}
./polaris \
catalog-roles \
grant \
--catalog starrocks_catalog \
--principal-role service_admin \
starrocks_catalog_role
最后给 starrocks_catalog_role 赋予读写权限(因为我要 insert,就没有只赋予 read-only 权限了):
./polaris privileges \
catalog \
grant \
--catalog starrocks_catalog \
--catalog-role starrocks_catalog_role \
CATALOG_MANAGE_CONTENT
➜ polaris git:(main) ✗ ./polaris privileges list --catalog starrocks_catalog --catalog-role starrocks_catalog_role
{"type": "catalog", "privilege": "CATALOG_MANAGE_CONTENT"}
接下来用 StarRocks 的 Iceberg rest catalog 连接即可:
drop catalog iceberg_rest;
CREATE EXTERNAL CATALOG iceberg_rest
PROPERTIES (
"iceberg.catalog.uri" = "http://localhost:8181/api/catalog",
"type" = "iceberg",
"iceberg.catalog.type" = "rest",
"iceberg.catalog.warehouse" = "starrocks_catalog",
# 直接把 client-id 和 client-secret 用 : 拼起来
"iceberg.catalog.credential" = "379bdc7c7bde5bbb:955e67c0f6f290082697859617a7c589",
# 需要指定下 scope,直接这么写就行了
"iceberg.catalog.scope"='PRINCIPAL_ROLE:ALL',
# 指定 s3 所在 region
"iceberg.catalog.client.region" = "us-west-2"
);
mysql> set catalog iceberg_rest;
Query OK, 0 rows affected (0.01 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| tpch_namespace |
+--------------------+
2 rows in set (0.01 sec)
mysql> use tpch_namespace;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
mysql> create table hello(c1 string);
Query OK, 0 rows affected (4.26 sec)
Database changed
mysql> show tables;
+--------------------------+
| Tables_in_tpch_namespace |
+--------------------------+
| hello |
+--------------------------+
1 row in set (0.01 sec)
mysql> insert into hello values (1);
Query OK, 1 row affected (13.04 sec)
mysql> select * from hello;
+------+
| c1 |
+------+
| 1 |
+------+
1 row in set (1.90 sec)
Polaris 不足点
- 相比于商业化的 Tabular,polaris 目前缺乏可视化的 UI 管理和 iceberg compaction 能力。
- 彻底的和 Iceberg format 绑死,导致查询性能的上限取决于 Iceberg 的设计(比如元数据 avro 解析慢?)。
原创文章,作者:Smith,如若转载,请注明出处:https://www.inlighting.org/archives/what-is-apache-polaris