Trino 介绍及部署使用

之前我们提到项目上有一个跨库进行 MySQL join 操作的需求,当时选择使用了 MySQL 的 FEDERATED 存储引擎来解决这个问题,具体可以看 MySQL FEDERATED 存储引擎介绍及使用。但是 FEDERATED 本身只支持 MySQL 数据库,如果我们需要对多个不同种类的数据库进行关联操作,那么还是要依赖第三方组件来进行,比如这次要介绍的 Trino。

Trino 是基于 Java 开发的高性能的、分布式的大数据 SQL 查询引擎,支持基本上所有的常见数据源以及你所想象不到的中间件存储比如 Kafka,同时也支持在单个查询中使用多个数据源来进行关联查询。

官网:Trino

前世今生

Trino 的前身是 Facebook 的 Presto。2012 年, Martin Traverso、Dain Sundstrom 和 David Phillips 入职了 Facebook 的大数据基建部门,并和 Eric Hwang 一同开发了 Presto 来解决 Facebook 的海量 Hadoop 数据仓库的低延迟交互分析的问题,随后在 2013 年 11 月将 Presto 开源。但好景不长,在 2018 年 Facebook 的管理层想要对 Presto 项目及其未来拥有更多的控制,并让毫无 Presto 经验的开发者可以直接提交代码,而且这个决定是在没有 Presto 社区参与的情况下做出的。创始人们觉得这和拥有一个健康开放的社区相矛盾,所以为了使 Presto 的成长更加健康,他们决定离开了 Facebook。

2019 年 1 月,Presto 软件基金会成立了,创始人们决定在未来的 10 个月中不再受雇于任何企业来专门与全球的用户和开发者们接触以及和贡献者合作来扩大和加强社区。随着参与的人员越来越多,Presto 项目也比以前更拥有活力,这个分支叫做 PrestoSQL。

在 PrestoSQL 稳固几个月之后,Facebook 决定通过 Linux 基金会来创建一个具有竞争关系的社区,第一部就是为 Presto 申请了商标。2019 年 9 月,Facebook 在 Linux 基金会成立了 Presto 基金会,这边的分支叫做 PrestoDB。所以 PrestoSQL 不得不改名,最后将名称改为了 Trino。

最后引用官宣改名文章的最后一句话:If you love this project, you already love Trino. ❤️

server 节点安装

因为现阶段只是简单地进行试用,所以我们只安装 server 节点,而且 server 节点同时也可以作为 worker 节点使用。

Java 环境

为什么要单独强调 Java 环境,是因为 Trino 对 Java 环境很挑剔,官网文档要求 64 位的 Java 11 运行环境,且最低版本号为 11.0.11。如果是 Java 12 或者 13、17 等后续版本,官方说可能正常工作,并没有做过测试。同时推荐 Azul Zulu 的 JDK,官方说只针对 Azul Zulu 的发行版做了测试,可以说是很娇贵了。

所以为了避免因为 JDK 的问题使程序出现问题,我们还是老老实实按照要求使用 Azul Zulu 的 Open JDK,具体安装过程不再赘述,是用的版本为当前 Java 11 的最新版 11.0.14.1+1。

Python 环境

Python 环境的要求相对来说就很宽泛了,官方说 2.6.x、2.7.x、或者 3.x 的版本均可,因为 Python 环境只是给启动脚本使用的,并不会影响程序的正常运行。都 2022 年了,所以我们这里使用 Python 3 的最新版即可。

安装 Trino

从官网下载 server 节点压缩包并解压即可。Trino 需要一个目录来存储日志等数据,官方建议放在 Trino 安装目录外,因为这样可以很方便地在后续升级 Trino 版本,具体配置放下面再说。

Trino 配置

安装完 Trino 之后还需要对 Trino 进行一连串的配置才可以运行。首先在安装目录创建 etc 文件夹,用来放置配置信息,然后通过创建对应文件的方式对 Trino 进行配置。

Node 节点配置文件

创建 node.properties 文件配置节点信息:

1
2
3
4
5
6
# 集群的环境名称,同一集群下的节点必须具有相同的环境名
node.environment=test
# 节点的唯一 ID,集群内不能重复
node.id=b0e4c61a-a304-47d3-bfc7-88be4c6a22c1
# 数据存储路径
node.data-dir=/opt/trino-server-374/data

JVM 配置

创建 jvm.config 文件存储 JVM 启动参数,在官方样例中删掉了 OOM 相关的参数并调整了下内存需求:

1
2
3
4
5
6
7
8
9
10
11
12
-server
-Xmx4G
-XX:-UseBiasedLocking
-XX:+UseG1GC
-XX:G1HeapRegionSize=32M
-XX:+ExplicitGCInvokesConcurrent
-XX:-OmitStackTraceInFastThrow
-XX:ReservedCodeCacheSize=512M
-XX:PerMethodRecompilationCutoff=10000
-XX:PerBytecodeRecompilationCutoff=10000
-Djdk.attach.allowAttachSelf=true
-Djdk.nio.maxCachedBufferSize=2000000

Config 配置文件

创建 config.properties 文件,储存的是一些杂七杂八的配置。因为我们只有一个节点做测试,即当 server 又当 worker,所以使用下列配置,端口按需调整:

1
2
3
4
5
6
7
8
9
# 标识为协调员,可以接受客户端请求并管理查询
coordinator=true
# 作为协调员的同时可作为 worker 节点使用
node-scheduler.include-coordinator=true
http-server.http.port=8080
query.max-memory=2GB
query.max-memory-per-node=2GB
# 协调员的地址,注册发现使用
discovery.uri=http://127.0.0.1:8080

日志等级

创建 log.properties 文件调整日志等级,可选,默认为 INFO

1
io.trino=INFO

数据源配置

Trino 支持的数据源非常的多,具体可以看官方文档 Connectors,这里我们只配置一个 MySQL 和一个 PostgreSQL 作为测试。

首先创建 catalog 文件夹,然后创建 mysql.properties 文件,文件名的 mysql 前缀为 catalog 名称,可以自由指定。

1
2
3
4
5
6
# 指定为 MySQL
connector.name=mysql
# JDBC 连接地址,注意,MySQL 作为数据源时不能指定具体 database
connection-url=jdbc:mysql://192.168.1.202:3306?useSSL=false
connection-user=root
connection-password=root

然后再创建 postgresql.properties 文件:

1
2
3
4
connector.name=postgresql
connection-url=jdbc:postgresql://192.168.1.202:5432/test
connection-user=postgres
connection-password=postgres

启动 Trino

可以通过运行 bin 目录下的 launcher 文件启动:

1
2
3
4
# 后台运行
ubuntu@CRUCIAL:/opt/trino-server-374/bin$ ./launcher start
# 前台运行
ubuntu@CRUCIAL:/opt/trino-server-374/bin$ ./launcher run

看到显示 SERVER STARTED 后就说明 Trino 正常启动了,可以通过浏览器直接访问 HTTP 端口来查看集群状态,用户名随意输入:

Trino 使用

我们可以通过两种方式来使用 Trino,使用官方的 CLI 命令工具,或者通过 JDBC 驱动在 Java 程序中使用。

CLI 工具

CLI 工具需要 Java 8 或更高版本作为运行环境,我们只需要下载官方提供的 jar 包即可直接使用。

1
2
3
4
ubuntu@CRUCIAL:/opt/trino-server-374$ wget https://repo1.maven.org/maven2/io/trino/trino-cli/374/trino-cli-374-executable.jar
ubuntu@CRUCIAL:/opt/trino-server-374$ chmod +x trino-cli-374-executable.jar
ubuntu@CRUCIAL:/opt/trino-server-374$ ./trino-cli-374-executable.jar --server localhost:8080 --execute 'SHOW TABLES FROM mysql.test'
ubuntu@CRUCIAL:/opt/trino-server-374$ ./trino-cli-374-executable.jar --server localhost:8080 --execute 'SELECT * FROM mysql.test.user'

其中,mysql 指的是我们在 catlog 文件夹创建的文件名,test 为我们 MySQL 的数据库名称,user 为表名。

JDBC 驱动

CLI 工具的泛用性不强,真要产品化使用还是得采用 JDBC 方式。首先按照官方,添加 JDBC 驱动:

1
2
3
4
5
<dependency>
<groupId>io.trino</groupId>
<artifactId>trino-jdbc</artifactId>
<version>374</version>
</dependency>

然后配置 JDBC 连接地址。这里可以有多种方案来配置,其中 catalog 为文件名,schema 相当于 MySQL 的 database:

1
2
3
jdbc:trino://host:port
jdbc:trino://host:port/catalog
jdbc:trino://host:port/catalog/schema

用户名可以任意输入,然后就可以正常使用了。

高级配置

上面的流程是可以正常使用的,但是细节上处理的都不到位,比如默认是匿名访问的,用户名可以任意输入;默认没有权限控制,可以访问所有的 catalog 等等,所以我们需要进行一下高级配置。

配置认证方式

Trino 支持很多种的认证方式,基本上常见的都支持。为了减少应用配置复杂度,我们仍然选择通用的用户名/密码方式进行认证。

首先打开我们的 config.properties 文件,添加认证配置:

1
http-server.authentication.type=PASSWORD

然后仍然是在 etc 目录下创建 password-authenticator.properties 文件,指定密码来源:

1
2
3
4
# 采用文件的方式
password-authenticator.name=file
指定密码文件位置
file.password-file=/opt/trino-server-374/etc/password.db

然后创建密码文件,我们可以使用 Apache HTTP Serverhtpasswd 工具来生成密码文件:

1
2
touch password.db
htpasswd -B -C 10 password.db user

user 为我们想要创建的用户名,然后输入密码即可。

开启 TLS 支持

当采用用户名/密码的方式进行认证时,Trino 强制要求我们使用 TLS,所以我们需要对其进行配置。

首先我们需要创建 HTTPS 证书,由于是本地测试,所以我们直接自己签发一个。Trino 支持 PEM 文件和 JKS 文件,我们使用标准的 PEM 文件进行配置。

1
2
3
4
5
6
7
8
9
10
11
# 生成私钥
ubuntu@CRUCIAL:/opt/trino-server-374/etc/ssl$ openssl genrsa -out server.key 2048
# 生成 CSR
ubuntu@CRUCIAL:/opt/trino-server-374/etc/ssl$ openssl req -new -key server.key -out server.csr
# 自己派发证书
ubuntu@CRUCIAL:/opt/trino-server-374/etc/ssl$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
# 生成 PEM 格式文件
ubuntu@CRUCIAL:/opt/trino-server-374/etc/ssl$ cat server.key server.crt > server.pem
# 校验 PEM 文件
ubuntu@CRUCIAL:/opt/trino-server-374/etc/ssl$ openssl rsa -in server.pem -check -noout
ubuntu@CRUCIAL:/opt/trino-server-374/etc/ssl$ openssl x509 -in server.pem -text -noout

生成完证书后,在 config.properties 文件中添加如下配置即可开启 TLS 支持:

1
2
3
4
5
6
# 开启 https
http-server.https.enabled=true
# 指定 https 端口
http-server.https.port=8443
# 指定证书文件
http-server.https.keystore.path=/opt/trino-server-374/etc/ssl/server.pem

最后修改 JDBC 连接地址,由于是自签证书,所以我们需要关闭证书校验:

1
jdbc:trino://127.0.0.1:8443?SSL=true&SSLVerification=NONE

同理,CLI 命令修改为:

1
./trino-cli-374-executable.jar --server https://localhost:8443 --user user --password --execute 'SELECT * FROM mysql.test.user' --insecure

权限控制

默认在不开启权限控制的情况下,用户都拥有最大权限,这显示是很不安全的,所以需要配置权限控制。

创建 access-control.properties 文件,指定权限控制文件:

1
2
3
4
5
access-control.name=file
# 指定控制文件位置
security.config-file=/opt/trino-server-374/etc/rules.json
# 自动刷新间隔,不再需要重启 Trino 即可自动生效
security.refresh-period=1s

创建 group-provider.properties 文件,指定群组配置文件:

1
2
group-provider.name=file
file.group-file=/opt/trino-server-374/etc/group.txt

然后编辑群组映射关系 group.txt

1
admin:admin-user

然后创建 rules.json 文件编写规则,具体的权限控制比较复杂,可以参考 File-based access control,这里我们只写一个基础的权限控制规则,实现 admin 组的用户可以进行所有操作,任意用户可以访问 mysql,user 可以读取 postgresql 的数据,system 没有用户可以访问。权限匹配是从上到下的,如果没有匹配到,则默认拒绝权限。具体配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"catalogs":[
{
"group":"admin",
"allow":"all"
},
{
"catalog":"mysql",
"allow":"all"
},
{
"user":"user",
"catalog":"postgresql",
"allow":"read-only"
},
{
"catalog":"system",
"allow":"none"
}
]
}

再创建用户 user2 及 admin-user,来测试一下效果:

这是开启权限控制之前 user 可以看到的

这是开启权限控制之后 user 可以看到的

这是 user2 可以看到的

最后这是 admin-user 可以看到的