写点什么

Trino 多租户最佳实践

  • 2022 年 4 月 13 日
  • 本文字数:3037 字

    阅读完需:约 10 分钟

Trino 是一款优秀的 OLAP 查询引擎,Trino 哲学理念是 SQL on Everything,即对于存储在任何地方数据都可以标准 SQL 的方式进行读取。Trino 本身不存储数据,是典型的存算分离的 MPP 框架,非常适合多源异构的联合查询场景。

在大规模 Trino 生产集群中,有很多用户同时提交 sql 查询作业,经常会出现部分不合理的 sql 占用了集群所有资源,导致其他用户的 sql 提交超时失败;同时,线上的查询数据基本是 Hive 数据,且线上仍然存在大量的 HiveServer2 查询作业,当前 HiveServer2 通过 Ranger 进行库表的权限管理,如果使用 Trino 查询 Hive 数据需要考虑同步 HiveServer2 的权限策略,保持多引擎对同一份 Hive 数据源的权限一致。

所以,在大规模 Trino 集群中,需要重点解决用户间的资源隔离以及用户对库表的权限控制问题,以此满足 Trino 多租户

Trino 用户资源隔离

为解决多用户的资源分配问题,Trino 社区提供了 Resource Group(本文简称 RG)功能

(https://trino.io/docs/current/admin/resource-groups.html)。RG 有两种使用方式,一种是基于 File 静态文件配置,一种是基于动态 DB 的方式,为了不影响集群服务,我们最终选择基于 DB 的方式进行 RG 配置。

 基于 DB 的 RG 配置中有两个核心概念:一是资源组,可以类比于 Hadoop Yarn 的队列,每个资源组中定义了最大并发、调度权重等参数,每个资源组还可以配置子资源组;二是选择器,选择器用来映射用户与资源组的关系,符合条件的用户才可以提交 sql 至某个资源组。

Trino 基于 DB 的 RG 功能在业内使用案例很少,我们深入调研了 RG 的实现原理,并且对 RG 做了一些优化,简要阐述如下:

1、增加 RG 的 Rest API 操作方式

Trino 代码中并未实现操作 RG 的接口,为了方便上层管理服务分配 Trino 计算资源,我们在 Trino 服务上增加了 RG 的 Rest Api 接口,管理员只需要发送资源的增删改查请求,即可完成对 Trino 计算资源的分配。

2、提供基于用户组的资源分配

基于 File 的 RG 提供了基于用户组的资源分配,也就是同一个用户组的用户可以分配到同一个队列,这种分配方案在实际生成中非常有用。我们调研代码,发现基于 DB 的 RG 并没有实现基于用户组的分配,通过在 RG 的选择器 selectors 元数据表中增加 user_group_regex 字段,并同步修改部分资源组初始化模块,完成用户组的支持。

Trino 中的用户组信息由 File group provider

https://trino.io/docs/current/security/group-file.html)提供,用户需要手动配置文件去映射用户与用户组的关系,由于我们生产环境的用户与用户组信息都是由 Ldap 维护,需要实现基于 Ldap 的 group provider,保持用户组信息与其他计算组件如 Spark、HiveServer2、Ranger 等一致。Trino 预留了获取用户组信息的接口,我们只需要实现 Ldap 的获取用户组接口即可。操作 Ldap 可以使用 JDK 的 Api,并不复杂,但是后来我们参考了部分 Hadoop 中关于获取 Ldap 用户组信息的代码,这样有一个直接好处就是可以复用 Hadoop 集群中存在的 Ldap 参数。

下面是一个基于 DB 的 RG 使用示例,可以看到用户 trino1 没有任何匹配的队列可以提交 SQL 查询,客户端抛出异常同时 Trino UI 也会有 QUERY_REJECT 的提示:


由于 hive 用户对资源组 resourcegrouptest 有使用权限,所以查询成功:



Trino 权限控制

当前我们处理的数据主要来自 Hive 数据源,所以 Trino 的权限问题就是如何控制 Hive 的库表权限。我们深入调研了 Trino 的几种权限控制方案,如下:

(1)Trino 在改名之前(PrestoSQL),Ranger2.0 中集成了 Presto 权限插件(https://issues.apache.org/jira/browse/RANGER-2395),但该插件在 PrestoSQL 改名之后出现兼容问题,Ranger 社区暂未提供合理解决方案。而且这种方案是在 Trino 侧实现 Ranger 鉴权,控制 Hive 数据源的策略也只是针对 Trino 引擎,而 Trino 的策略并不会和 HiveServer2 的策略同步,这会导致 Trino-hive 数据源和 HiveServer2 的策略不同步。

(2)在 Trino 的 Hive connector 模块中,移植 HiveServer2 的 Ranger 权限代码至 Trino-Hive 模块,实现 Trino-Hive 中拉取和 HiveServer2 同样的策略,做到 Trino-Hive 和 HiveServer2 访问权限一致。但是这种方案对 Trino 代码侵入比较多,不利于 Trino 后续版本升级、维护。

(3)在 Hive MetaStore 服务端增加 Ranger 鉴权能力,把 Hive 数据鉴权的过程下沉至元数据服务端,Trino 侧不需要提供鉴权能力,代码侵入性较少。这种方案同样适用于 Spark、Flink 访问 Hive 数据权限控制的场景,满足以后更多引擎的 Hive 数据策略同步需求。

综上三个方案,考虑多引擎间的 Hive 数据权限同步需求,我们最终选择了第三个方案。这个方案需要 Trino 访问 MetaStore 时传递正确的客户端用户,然后 MetaStore 服务接收 Trino 调用请求,同时向 Ranger 发送鉴权请求,如下示意图:

上三个方案,考虑多引擎间的 Hive 数据权限同步需求,我们最终选择了第三个方案。这个方案需要 Trino 访问 MetaStore 时传递正确的客户端用户,然后 MetaStore 服务接收 Trino 调用请求,同时向 Ranger 发送鉴权请求,如下示意图:


实现这种方案需要完成几个主要功能点开发:

1、完善 Trino-Hive 数据源的 impersonation 功能

Trino 作为 MetaStore 的客户端,调用 MetaStore 接口时需要传递正确的客户端用户,才能达到 impersonation 效果。当前 Trino 大多数接口已经具备 impersonation 的能力,但是部分接口如 listSchemaNames 以及 getAllTables 并没有做 impersonation,导致这两个接口调用 MetaStore 时一直使用 hive 用户,MetaStore 服务端无法识别真正的用户,所有用户调用这两个接口的返回内容均一样。我们基于 Trino 现有的 impersonation 接口,做了最小化代码改动完成所有接口的 impersonation 化。

2、Ranger-MetaStore 鉴权插件

最初我们考虑开发一个全新的 Ranger-MetaSore 插件,但在调研后发现可以复用现有的 Ranger-HiveServer2 插件,而且对现有的 Ranger 代码没有任何侵入性。我们 Ranger-HiveServer2 插件中实现了 MetaStorePreEventListener 接口,该接口监听了 MetaStore 所有接口的 Action,对库表的增删改查操作都会封装成 RangerHiveResource 对象,最终实现对 MetaStore 操作的鉴权。

3、MetaStore 服务端过滤库表能力

这里之所以强调服务端的库表过滤能力,是因为客户端已经有了过滤库表机制。但是 Trino 没有使用 MetaStore Java 客户端(HiveMetaStoreClient),Trino 做了一层 metasore shade,shade 中实现了兼容多个 Hive 版本的 thrift 客户端,所以 HiveMetaStoreClient 的库表过滤对于 Trino 是无效的。我们后来在 HMSHandler 中增加了服务端过滤库表能力,复用 HiveMetaStoreClient 库表过滤代码,完成了 MetaStore 服务端过滤库表功能实现。



通过上述的改造,我们完成了 Trino 访问 MetaStore 的库表鉴权。如上图 spark 用户没有访问 testdb.test1 表的策略,Trino 客户端提交查询时会出现权限异常。当前只是实现了较为粗粒度的库表鉴权效果,下一步会考虑实现字段级别鉴权以及行过滤列掩码的细粒度鉴权。

Trino 大规模集群的多租户形态优化探索

我们通过对 Trino、Hive、Ragner 的改造,初步完成了 Trino 集群多租户功能的实现。当前能够对 Trino 资源动态分配以及 Trino-Hive 数据源的权限同步与管控,后续我们还会通过以下两点继续探索优化 Trino 大规模集群的多租户形态:

(1)Trino 计算资源细粒度管控

虽然基于 DB 的 RG 方案已经有效控制用户的资源使用情况,但是目前 Trino 框架无法控制已经运行的查询任务资源,还是可能会出现一条 bad sql 占用集群大量资源情况。需要考虑 RG 的细粒度控制功能。

(2)Trino-Hive 细粒度权限管控

由于目前方案是在 MetaStore 端鉴权,MetaStore 没有解析 SQL 的能力,所以细粒度的权限暂时无法控制。我们接下来考虑增强 MetaStore 功能,把 MetaStore 做成统一元数据服务,具备权限细粒度、多种元数据存储能力。

用户头像

还未添加个人签名 2019.02.13 加入

还未添加个人简介

评论

发布
暂无评论
Trino多租户最佳实践_多租户_移动云大数据_InfoQ写作平台