本文基于lyft开源的1.6.6版源码:GitHub - lyft/presto-gateway: A load balancer / proxy / gateway for prestodbA load balancer / proxy / gateway for prestodb. Contribute to lyft/presto-gateway development by creating an account on GitHub.https://github.com/lyft/presto-gateway
Presto Gateway构建在Dropwizard框架(Getting Started — Dropwizard)之上,在启动时,在由继承BaseAPP.java(它继承Dropwizard的Application.java)的HaGatewayLauncher.main()中进行服务的启动流程,如下图所示:
在Dropwizard的Application.java中会调用initialize()方法注册一些bundle,会通过cli.run()调用EnvironmentCommand.run()的方式,最终调用Gateway中的子类BaseAPP.run(),利用Guice注入各种Module和需要的类实例,如下图所示:
注入完成后,继续利用Dropwizard中的register机制,通过Jersey等注入各种Task(后台调度任务)、HealthCheck、Provider、Resource(Jersey中的REST url响应服务类)组件,如下图所示:
可以看到是通过扫描packge下的各个类是否符合Task或HealthCheck类型、是否带有Provider和Path注解的方式,来找到应该register哪些类的。
而上面注入的各个Guice Module会用到一些配置信息,各个配置都以POJO类的形式,最终继承Dropwizard的Configuration.java来实现,如下图所示:
该Configuration类会去解析YAML配置文件来生成启动服务时用到的各项配置。
在添加Module的过程中,比较核心的Module是HaGatewayProviderModule,其中会注入ProxyServer、ResourceGroupsManager等重要的路由功能类,如下图所示:
其中ProxyServer里面包含了Jetty框架中的Server.java,最终是在Server.start()中启动Presto Gateway服务的,如下图所示:
在注入且启动的子组件中,可以看到HaResourceGroupsManager的作用是把Trino的Resource Group配置更新操作通过jdbc写入到数据库中,如下图所示:
类似的,HaGatewayManager的作用是通过jdbc读取数据库,获取和操作Trino连接信息,这里的Backend指的就是要被路由的Trino,如下图所示:
历史查询记录也会被写入到数据库中,通过HaQueryHistoryManager来读写,如下图所示:
RoutingManager负责将Trino QueryId和后端Trino关联起来,存储在Guava内存缓存中,如下图所示:
它的子类HaRoutingManager被HaGatewayProviderModule所注入,重写了findBackendForUnknownQueryId()方法,优先从JDBC数据库中查找backend,找不到才从父类中找。
在Presto客户端发送请求到Gateway服务时,基于Jetty的Proxy Servlet机制,会通过ProxyServer中包含的ProxyServletImpl类来调用QueryIdCachingProxyHandler中的多种Jetty重写方法来拦截、过滤、重定向网络请求,关系结构和部分实现如下图所示:
Presto Gateway也支持HTTP请求调用,根据Jersey的JAX-RS规范都在名为XxxResource的类中,例如GatewayViewResource提供HTML UI展示、sql查询历史、后端Trino信息等,如下图所示:
EntityEditorResource提供后端Trino、Resource Group、Selector等信息的修改和读取,如下图所示:
GatewayResource提供后端Trino的激活与停用等操作,如下图所示:
HaGatewayResource负责后端Trino连接信息的更新操作,需在GatewayResource操作之后,如下图所示:
PrestoResource负责Presto计算引擎中Resource Group、Selector、全局配置等的维护更新,部分操作和EntityEditorResource有所重复,只是请求URL不一样,如下图所示:
可以看到,Presto Gateway在部分配置的更新上还是比较灵活的。
从主体结构部分可以看到,Presto Gateway支持Resource Group、Selector、Trino后端等信息在HTTP接口(本质也是更新db)、Web UI、数据库层面的热更新,使用教程可以参考:https://www.jianshu.com/p/b5c0fc47275dhttps://www.jianshu.com/p/b5c0fc47275d
由于底座Dropwizards框架的Configuration机制,而无法热更新只能在.yml文件中写死的配置信息主要有:
(1)gateway-ha-config.yml中的路由规则路径配置、启动url端口、jdbc连接信息、告警邮箱联系人、启动时需要Guice注入的Module、日志配置等。
(2)actions.yml中的打包相关配置。
(3)routing_rules_xxx.yml中的细节路由规则,例如当遇到怎样的请求应该路由到哪个Resource Group中等等,该文件的路径要写到gateway-ha-config.yml中。
Presto Gateway支持多个后端Trino集群的激活与停用、增加与删除、负载均衡等,在客户端第一次http请求时可以根据负载均衡选择一个Trino Backend,后续的多个同一查询请求都能找到第一次时发往的那个Trino Backend。
但是Presto Gateway把每个Backend都当成是一个新的Trino集群,如果Trino改造了双Coordinator功能,可能Gateway也需要做适当改造。
关于Gateway自身的HA和无状态化的横向扩展则需要进行源码改造,增加redis等外部状态存储来实现。
Presto用户可以像直连Trino Coordinator一样,通过cli客户端jar或JDBC的方式连接Gateway,只需要修改server连接信息、properties等即可。如果需要根据client-tags等其他条件来进行路由判断,则需要进行源码改造。
Presto Gateway在启用了细节路由规则后,默认会读取X-Trino-Routing-Group请求头来路由请求。如果没有指定这个报头,请求会被发送到默认路由组adhoc。路由规则的定义可以参考:使用presto-gateway在多个presto集群负载_qq_2368521029的博客-CSDN博客prestogateway在多个presto集群负载流量,减轻presto集群压力https://blog.csdn.net/qq_40616823/article/details/125790002
Presto Gateway也支持邮箱告警,可以在gateway-ha-config.yml中配置。