Presto初体验
Presto是一个facebook开源的分布式SQL查询引擎,适用于交互式分析查询,数据量支持GB到PB字节。Presto 可扩展到任何数据源,它的设计采用了存储抽象化,以便于轻松地构建可插入的连接器。因此,Presto 拥有大量连接器,既可用于非关系数据源,例如 Hadoop 分布式文件系统 (HDFS)、Amazon S3、Cassandra、MongoDB 和 HBase,又可用于关系源,例如 MySQL、PostgreSQL、Amazon Redshift、Microsoft SQL Server 和 Teradata。数据在其存储位置接受查询,无需将其移动到独立的分析系统中。
1.用Presto干什么
Presto能干的事情非常多,搞大数据的应该使用过Hive,它们都是基于SQL引擎来做一些数据的分析和计算,我们今天用Presto来进行多数据源查询sql,数据源使用mysql。
2.部署Presto
Presto采用典型的master-slave模型,我们为了部署方便,就使用单机单节点部署,让它即是主节点也是工作节点,写这篇文章的时候,Presto的最新版本是0.261,我们就使用这个版本来部署。
2.1 下载二进制包
在linux节点机上执行以下命令
wget https://repo1.maven.org/maven2/com/facebook/presto/presto-server/0.261/presto-server-0.261.tar.gz
下载好之后解压文件
tar -zxvf presto-server-0.261.tar.gz
2.2 编辑配置文件
解压之后我们进入presto-server-0.261 目录下(/opt/app/presto-server-0.261)
创建一个etc目录用来放置配置文件
创建一个data目录放置presto产生的数据文件
mkdir etc
mkdir data
在etc(/opt/app/presto-server-0.261/etc)目录下我们要创建几个presto需要的配置文件
2.2.1 node.properties
vi node.properties
执行完上边命令 cp以下内容, node.data-dir属性按照自己的物理路径
node.environment=production
node.id=ffffffff-ffff-ffff-ffff-ffffffffffff
node.data-dir=/opt/app/presto-server-0.261/data
2.2.2 jvm.config
vi jvm.config
执行完上边命令 cp以下内容, 内存按需设置,16G是官方给的参考配置
-server
-Xmx16G
-XX:+UseG1GC
-XX:G1HeapRegionSize=32M
-XX:+UseGCOverheadLimit
-XX:+ExplicitGCInvokesConcurrent
-XX:+HeapDumpOnOutOfMemoryError
-XX:+ExitOnOutOfMemoryError
2.2.3 config.properties
vi config.properties
执行完上边命令 cp以下内容, 这里我们是按照单机单节点配置的,如果需要集群主从配置的话,参考文末的官方文档即可,端口号自己配置,不要与自身服务冲突即可
coordinator=true
node-scheduler.include-coordinator=true
http-server.http.port=20000
query.max-memory=5GB
query.max-memory-per-node=1GB
query.max-total-memory-per-node=2GB
discovery-server.enabled=true
discovery.uri=http://localhost:20000
2.2.4 log.properties
vi config.properties
执行完上边命令 cp以下内容,默认的最低级别是INFO 共有四个级别:DEBUG,INFO,WARN和ERROR
com.facebook.presto=INFO
2.3 启动Presto
回到我们安装presto的bin(/opt/app/presto-server-0.261/bin)目录下
我们可以先前台启动看下日志
./launcher run
我这里出现了一点问题,启动的时候报出了以下的错误
/usr/bin/env: ‘python’: No such file or directory
我们看一下启动脚本的内容,可以看到最后一行执行了同目录下的launcher.py脚本。。。。我先去装个py先
#!/bin/sh -eu
#
# Launcher for Airlift applications
...
...
...
#
# Run with --help to see options.
#
exec "$(dirname "$0")/launcher.py" "$@"
OK,我现在已经安装好了python,我们再次执行启动命令,又出问题了~
2021-09-20T00:55:33.044+0800 ERROR main com.facebook.presto.server.PrestoServer Unable to create injector, see the following errors:
1) Error injecting constructor, java.io.IOException: java.io.IOException: Can not attach to current VM (try adding '-Djdk.attach.allowAttachSelf=true' to the JVM config)
...
...
...
2) Error injecting constructor, java.io.IOException: java.io.IOException: Can not attach to current VM (try adding '-Djdk.attach.allowAttachSelf=true' to the JVM config)
at com.facebook.airlift.jmx.JmxAgent9.<init>(JmxAgent9.java:47)
看样子是jvm出了问题,让我尝试修改配置,果断去github上搜索一下
https://github.com/prestodb/presto/issues/13216
看了下我的jdk版本.嗯 是jdk11的. 但。。这是19年的bug啊, 算了,先修改下jvm的配置看看吧
进入到我们的etc(/opt/app/presto-server-0.261/etc)目录下
vi jvm.config
执行上边命令 修改jvm的配置
-server
...
...
...
-Djdk.attach.allowAttachSelf=true
再次执行启动命令 当你看到SERVER STARTED 的日志时,就代表presto服务端已经启动完毕了
2021-09-20T01:09:14.892+0800 INFO main com.facebook.presto.server.PluginManager
...
...
...
com.facebook.presto.storage.TempStorageManager -- Loaded temp storage local --
2021-09-20T01:09:15.082+0800 INFO main com.facebook.presto.server.PrestoServer ======== SERVER STARTED ========
访问你在config.properties中设置的端口号,即可看到presto服务提供的dashboar界面。
如果你无法访问,请看下后台是不是进程断掉了,要保证内存足够。
这个时候我们就可以后台启动presto了
回到我们安装presto的bin(/opt/app/presto-server-0.261/bin)目录下
./launcher start
3.简单使用
presto本身不存储数据,只是用来对数据进行查询计算,所以我们使用之前先确定好数据源,我们这里就启动两个mysql数据源来提供数据.
3.1 数据源配置
我们在etc(/opt/app/presto-server-0.261/etc)目录下创建catalog目录
mkdir catalog
catalog目录是存储连接器的目录,你可以理解为是存储数据源配置信息的目录
在catalog目录下创建两个mysql的配置(其它数据源可参考文末的链接)
vi mysql1.properties
执行完上边的命令后,cp下边的配置,对应的配置信息改为自己的
connector.name=mysql
connection-url=jdbc:mysql://192.168.73.128:3306
connection-user=root
connection-password=123456
我们再创建第二个配置文件
vi mysql2.properties
执行完上边的命令后,cp下边的配置,对应的配置信息改为自己的
connector.name=mysql
connection-url=jdbc:mysql://192.168.73.128:3307
connection-user=root
connection-password=123456
完事之后,我们回到bin(/opt/app/presto-server-0.261/bin)目录下
刚刚我们为了验证是否能启动成功已经把presto启动了,我们执行以下命令先停止再启动
./launcher stop
./launcher start
3.2 使用presto-cli连接服务端
presto提供多种连接服务端的方式,我们先用官方制作的cli客户端来与服务端进行交互
3.2.1 下载presto-cli.jar
wget https://repo1.maven.org/maven2/com/facebook/presto/presto-cli/0.261/presto-cli-0.261-executable.jar
3.2.2 启动连接
先给下载的jar包授权
chmod +x presto-cli-0.261-executable.jar
然后执行jar包的启动命令,--server参数 填写自己设置的服务端端口,我是在本机部署本机启动 所以就填localhost了。
./presto-cli-0.261-executable.jar --server localhost:20000
启动之后就会进入一个可交互的界面
输入 show catalogs 命令就会发现可以看到我们刚刚配置的两个mysql数据源和一个系统system数据源
presto> show catalogs;
Catalog
---------
mysql1
mysql2
system
(3 rows)
Query 20210920_084311_00002_hb89m, FINISHED, 1 node
Splits: 19 total, 19 done (100.00%)
298ms [0 rows, 0B] [0 rows/s, 0B/s]
3.2.3 进行sql查询
我们知道mysql的sys系统库下有一个sys_config表,我们来执行sql查看下里边的内容
presto> select * from mysql1.sys.sys_config;
variable | value | set_time | set_by
--------------------------------------+-------+-------------------------+--------
diagnostics.allow_i_s_tables | OFF | 2021-09-19 16:09:44.000 | NULL
diagnostics.include_raw | OFF | 2021-09-19 16:09:44.000 | NULL
ps_thread_trx_info.max_length | 65535 | 2021-09-19 16:09:44.000 | NULL
statement_performance_analyzer.limit | 100 | 2021-09-19 16:09:44.000 | NULL
statement_performance_analyzer.view | NULL | 2021-09-19 16:09:44.000 | NULL
statement_truncate_len | 64 | 2021-09-19 16:09:44.000 | NULL
(6 rows)
Query 20210920_084658_00004_hb89m, FINISHED, 1 node
Splits: 17 total, 17 done (100.00%)
323ms [6 rows, 0B] [18 rows/s, 0B/s]
我们在Dashboard上其实也可以看到整个系统的状态,包括执行过的语句
3.3 使用presto-jdbc连接服务端
cli一般适合运维人员上去操作,搞开发的一般还是使用驱动器在代码中进行操作,这里我就主要用presto-jdbc演示连接server端并进行多mysql数据源的sql查询。
3.3.1 准备数据
在创建java项目之前,我们先给两个mysql数据源创建好数据
这里用很简单的例子来举例,并不对真实业务场景进行测试
第一个数据源创建user库,在user库中创建USER_INFO数据表,里边很简单,id和name;
第二个数据源创建cost库,在cost库中创建USER_COST数据表,很简单,只有userID和cost;
当我把上边的数据准备好,在presto-cli执行sql语句时,出问题了。。
3.3.2 presto对mysql的BUG??
当我执行以下sql语句的时候,可以很清晰的看到,user_info变成小写了
presto> show tables from mysql1.user;
Table
-----------
user_info
(1 row)
我本以为小写是presto处理了,但是当我执行以下语句
presto> select * from mysql1.user.USER_INFO;
Query 20210920_100117_00028_hb89m failed: line 1:15: Table mysql1.user.user_info does not exist
很明显,它去mysql中查询的时候按照小写来执行了,但我mysql数据库中是大写的表名
再次去github绕一圈
https://github.com/prestodb/presto/issues/14930
不知道是我操作有问题还是什么的,这好像也是很久之前的一个问题了,但是现在还是没有解决.
那现在只能把表名都改成小写了.还可以参考文末的链接把mysql的表名修改成不区分大小写。
再次查询
presto> select * from mysql1.user.USER_INFO;
id | name
----+--------
1 | 张三
2 | 李四
3 | 王五
4 | 哈哈
5 | 你好
6 | Jack
7 | Mary
8 | 方鹏博
9 | Root
(9 rows)
3.3.3 jdbc进行操作
我创建了一个web的脚手架
首先在pom文件中引入presto的依赖
pom.xml
...
<dependency>
<groupId>com.facebook.presto</groupId>
<artifactId>presto-jdbc</artifactId>
<version>0.261</version>
</dependency>
...
然后编写配置文件
application.properties
# 应用名称
spring.application.name=presto-java
server.port=20001
presto.jdbc.url=jdbc:presto://192.168.73.128:20000
创建DBUtil工具类
@Component
public class DBUtil {
@Value("${presto.jdbc.url}")
public String url;
public Connection getConnection() throws Exception {
Class.forName("com.facebook.presto.jdbc.PrestoDriver");
Connection conn = DriverManager.getConnection(url,"root","");
conn.setCatalog("mysql");
return conn;
}
}
编写Controller层
@RestController
public class UserController {
@Autowired
PrestoDao prestoDao;
//查询未缴学费的学生姓名列表
@GetMapping("notPayUser")
public List<String> notPayUser (){
try {
return prestoDao.notPayUser();
} catch (Exception e) {
return null;
}
}
}
编写接口实现层
注意这里我们的sql语句是同时查询两个不同数据源的不同数据库
String sql = "select name from mysql1.user.user_info where id not in (select userId from mysql2.cost.user_cost)";
@Service
public class PrestoDao {
@Autowired
DBUtil dbUtil;
public List<String> notPayUser() throws Exception {
List<String> result = new ArrayList<>();
String sql = "select name from mysql1.user.user_info where id not in (select userId from mysql2.cost.user_cost)";
Connection connection = dbUtil.getConnection();
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
result.add(resultSet.getString("name"));
}
return result;
}
}
RUN起来
请求我们写的接口
可以看到是不是这几个同学的名单没有在cost表中
当然,真实的业务场景肯定不是这么简单,有的时候可能我们的sql要跑几十分钟甚至几个小时。
presto和类似的hive等对比还是有很大优势的,详细参考文末的链接
上边只是对presto的简单使用,多数据源联合查询只是其中的小小部,presto的功能远远不止这些。希望在后边能有机会去了解它。只是简单的部署就遇到了两个BUG,且都是挺久了,不知道是没修复还是怎么回事,是有点尴尬,那个mysql表名区分大小写的没修复是真的有问题啊。。。
4.引用
Name | Link |
---|---|
Presto 0.261 文档 | https://prestodb.io/docs/current/index.html |
Presto连接器(数据源)配置 | https://prestodb.io/docs/current/connector.html |
MySQL修改lower_case_table_names参数 | https://www.cnblogs.com/jyzhao/p/13218753.html |
如何比较Hive,Spark,Impala和Presto? | https://zhuanlan.zhihu.com/p/161000135 |