当前位置 博文首页 > weixin_ccjz9527的博客:高性能体系结构graphql到sql

    weixin_ccjz9527的博客:高性能体系结构graphql到sql

    作者:[db:作者] 时间:2021-07-05 21:56

    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白蛋白12track2
    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的比较。

    数据库实时同步

    cs