高性能体系结构graphql到sql

Hasura GraphQL引擎提供了一个超文本传输协议应用编程接口,以一种权限安全的方式使用GraphQL查询Postgres。

您可以利用Postgres中的外键约束在单个请求中查询分层数据。 例如,您可以运行此查询来获取“唱片集”及其所有“曲目”(前提是“曲目”表具有指向“唱片集”表的外键):


正如您可能已经猜到的,查询可以遍历表到任意深度。 这个与权限相结合的查询接口允许前端应用程序查询Postgres,而无需编写任何后端代码。

该应用编程接口旨在快速(响应时间)和处理大吞吐量(每秒请求数),同时节省资源(低CPU和内存使用率)。 我们讨论了使我们能够实现这一目标的架构决策。

对数据微服务的查询经历以下几个阶段:

  1. 会话决议: 请求到达网关,网关解析授权密钥(如果有),添加用户id和角色头,然后将请求代理到数据服务。
  2. 查询解析: 数据服务接收一个请求,解析标题以获得用户id和角色,解析主体为一个GraphQL AST。
  3. 查询验证: 检查查询是否语义正确,然后强制执行为角色定义的权限。
  4. 查询执行: 经过验证的查询被转换为一条SQL语句,并在Postgres上执行。
  5. 响应生成: Postgres的结果被处理并发送到客户端(如果需要,网关会添加gzip压缩)。

要求大致如下:

  1. 超文本传输协议堆栈应该增加很少的开销,并且应该能够处理大量的并发请求以获得高吞吐量。
  2. 快速查询翻译(GraphQL到SQL)
  3. 编译后的SQL查询在Postgres上应该是高效的。
  4. 波斯特格里斯的结果必须被有效地发回。

以下是获取GraphQL查询所需数据的各种方法:

GraphQL查询执行通常包括为每个字段执行一个解析器。 在示例查询中,我们将调用一个函数来获取2018年发行的专辑,然后对于这些专辑中的每一张,我们将调用一个函数来获取曲目,这是经典的N+1查询问题。 查询的数量随着查询的深度呈指数增长。

在Postgres上执行的查询如下:

这将是获取所有所需数据的N + 1个查询的总和。

像数据加载器这样的项目旨在通过批处理查询来解决N + 1查询问题。 请求的数量不再依赖于结果集的大小,而是依赖于GraphQL查询中的节点数量。 在这种情况下,示例查询需要对Postgres进行两次查询来获取所需的数据。

在Postgres上执行的查询如下:

这给了我们所有的专辑。 要获取所有所需专辑的曲目:

这总共是2个查询。 我们避免了发出查询来获取每个专辑的曲目信息,而是使用where子句在一个查询中获取所有所需专辑的曲目。

数据加载器旨在跨不同数据源工作,不能利用单个数据源的功能。 在我们的例子中,我们唯一的数据源是Postgres,Postgres像所有关系数据库一样,提供了一种在单个查询中从几个表中收集数据的方法k.a连接。 我们可以确定一个GraphQL查询所需要的表,并使用连接生成一个单独的查询来获取所有的数据。 因此,任何GraphQL查询所需的数据都可以从单个查询中获取。 在发送给客户端之前,必须对这些数据进行适当的转换。

查询如下:


这将为我们提供如下数据:

相册id(_ d)

相册标题(_ t)

轨道id

轨道标题(_ t)

1

白蛋白1

1

track1

1 白蛋白1 2 track2
2 白蛋白m2

该数据必须转换为具有以下结构的JSON响应:


我们发现处理请求的大部分时间都花在了转换函数上(它将SQL结果转换成JSON响应)。 在尝试了一些优化转换函数的方法后,我们决定通过将转换推入Postgres来删除这个函数。 Postgres 9。4(大约在第一个数据微服务发布时发布)添加了JSON聚合函数,这帮助我们将转换推进到Postgres。 生成的SQL将变成类似于:


该查询的结果将有一列和一行,并且该值被发送到客户端,无需任何进一步的转换。 从我们的基准测试来看,这种方法大约比哈斯克尔的转换函数快3-6倍。

根据查询的嵌套级别和使用的条件,生成的SQL语句可能非常大而且复杂。 通常,任何前端应用程序都有一组用不同参数重复的查询。 例如,上述查询可以针对2017年而不是2018年执行。 准备好的语句最适合这些用例。当你有复杂的SQL语句时,这些语句会随着一些参数的改变而重复。

因此,第一次执行这个GraphQL查询时:


我们准备了SQL语句,而不是直接执行它,所以生成的SQL将是(注意$1):

接下来执行这个准备好的语句:

当GraphQL查询更改为2017年时,我们只需直接执行准备好的语句:

根据GraphQL查询的复杂程度,这大致可以使我们提高10-20% .

Haskell非常适合各种原因:

  • 具有出色性能的编译语言(本)
  • 高效能的HTTP堆栈(warp,warp的体系结构)
  • 我们之前使用该语言的经验

高效能的HTTP堆栈(翘曲,翘曲的体系结构(
这是Hasura的建筑与Prisma和Postgraphile的比较。

数据库实时同步

我们之前使用该语言的经验

  1. 8GB RAM,i7笔记本电脑
  2. Postgres在同一台机器上运行
  3. wrk被用作基准测试工具,并且针对不同类型的查询,我们尝试“每秒”最大化请求
  4. 查询Hasura GraphQL引擎的单个实例
  5. 连接池大小:50
  6. 数据集:chinook

查询1:tracks_media_some


  • 每秒请求数:1375 req / s
  • 5毫秒
  • 30%
  • 30MB(Hasura)+ 90MB(Postgres)

查询2:tracks_media_all


  • 每秒请求数:410 req / s
  • 延迟时间:59毫秒
  • 查询1:轨道_媒体_部分100%
  • 每秒请求数:1375次请求/秒每秒请求数:410次请求/秒

查询3:album_tracks_genre_some


  • 每秒请求数:1029 req / s
  • 延迟时间:24ms
  • 30%
  • 30%30MB(Hasura)+ 90MB(Postgres)

查询4:album_tracks_genre_all


  • 每秒请求数:328 req / s
  • CPU:100%
  • 30MB(Hasura)+ 130MB(Postgres)

猜你喜欢

转载自blog.csdn.net/weixin_49470452/article/details/107506394