postgresql 提高Hasura订阅性能

sqserrrh  于 2023-06-05  发布在  PostgreSQL
关注(0)|答案(1)|浏览(232)

我们开发了一个网络应用程序,它依赖于我们用户之间的实时交互。我们使用Angular作为前端,Hasura和Postgres上的GraphQL作为后端。我们注意到,当同时有超过300个用户处于活动状态时,我们会遇到严重的性能损失。
因此,我们希望改进我们的订阅设置。
我们认为可能的问题可能是:
1.订阅过多
1.订阅太大且太复杂,订阅中的分叉太多
关于1.每个用户在使用web应用程序时具有大约5-10个活动的订阅。关于第2项。我们有复杂的订阅,因为我们将多达6个表连接在一起。
我们想到的解决方案:
1.使用更多的查询,并限制对完全需要实时的字段使用订阅。
1.将复杂的查询/订阅拆分为多个较小的查询/订阅。
我们是否遗漏了另一个可能的原因?我们还可以使用什么来提高整体性能?
感谢您的评分

l7mqbcuq

l7mqbcuq1#

前言

OP问题非常广泛,不可能在一般情况下回答。
因此,我在这里描述的内容反映了我在优化订阅方面的经验--这是OP的决定,它反映了他们的情况。

系统简短描述

系统用户:上传文档,提取信息,准备新文档,在过程中进行匡威(类似IM的功能),有AI机器人试图减少重复性任务的负担,与外部系统交换数据的服务。
有很多实体,人类和机器人参与者之间有很多互动。加上相当复杂的授权规则:数据的可见性取决于组织、部门和文件的内容。

What was on start

一开始是:

  • 程序员为应用程序所需的全部数据编写了一个图形查询
  • query更改为subscription
  • 完成

前2-3个月还可以,然后:

  • 查询变得越来越复杂
  • 订阅量增长
  • UI变得滞后
  • 数据库示例始终接近100%负载。即使在晚上和周末。因为有人没有关闭申请

首先,我们对查询本身进行了优化,但这还不够:

  • 有些东西的代价是合理的JOIN、存在 predicate 、数据本身显著增长
  • 网络部分:你可以优化数据库,但只是传输所有需要的数据是有成本的

订阅优化

第一步:订阅拆分:订阅更改日期,查询更改

代替将整个数据拆分为多个部分的复杂订阅:
A.指示实体已更改的单个字段的订阅
例如
而不是:

subscription{
  document{
    id
    title
    # other fields
    pages{  # array relation
    ...
    } 
    tasks{ # array relation
    ...
    } 
    # multiple other array/object relations
    # pagination and ordering
  }

它返回数千行。
创建一个函数:

  • 接受hasura_session -以便每个用户的结果都是单独的
  • 只返回一个字段:最大更改日期

于是就变成了:

subscription{
  doc_change_date{
    max_change_date
  }
}

始终为一行和一个字段
B.应用逻辑的改变

  • 查询全部数据
  • 订阅doc_change_date
  • 记忆max_change_date
  • 如果max_change_date已更改-重新查询数据

注意事项

如果订阅函数有时返回误报,这是完全可以的。
不需要将所有 predicate 从源查询复制到订阅函数。
例如
在我们的案例中:数据的可见性取决于组织和部门(甚至更多)。
因此,如果一个部门的用户创建/修改了文档,则其他部门的用户无法看到此更改。
但这些变化就像每个组织在一分钟内发生一次/两次。
因此,对于订阅功能,我们可以忽略这些粒度,并为整个组织计算max_change_date
拥有更快更粗糙的订阅功能是有益的:它将更频繁地触发数据刷新,但是整体成本将更低。

第二步。多路订阅

第一步至关重要。
Hasura有一个多路复用的订阅:https://hasura.io/docs/latest/graphql/core/databases/postgres/subscriptions/execution-and-performance.html#subscription-multiplexing
所以理论上Hasura可以足够聪明并解决你的问题。
但如果你认为“显性比隐性好”,你还可以做另一个步骤。
在我们的案例中:

  • 用户上载文档
  • 将它们合并到档案中
  • 创建新文档类型
  • 与他人匡威

因此,订阅变为:doc_change_date、dossier_change_date、msg_change_date等。
但实际上,只有一个订阅可能是有益的:“嘿!你有变化了!“
因此,而不是多个订阅应用程序使只有一个。

注意事项

我们考虑了2种多路复用订阅格式:

  • A.订阅仅返回一个字段{max_change_date},该字段对所有实体都是累积的
  • B.订阅返回更精细的结果:{doc_change_date, dossier_change_date, msg_change_date}

现在A为我们工作但也许我们以后会改成B

第三步。我们在hasura2.0中会有什么不同

这是我们还没有尝试过的。
Hasura 2.0允许为查询注册VOLATILE函数。
这允许在DB中创建具有记忆功能的函数:

  • 你为函数调用定义了一个缓存,大概是在一个表中
  • 然后在函数调用时,首先在缓存中查找
  • 如果不存在:将值添加到缓存
  • 从缓存返回结果

这允许进一步优化订阅函数和查询函数。

注意事项

实际上,不需要等待hasura 2.0就可以做到这一点,但这需要在postgresql端使用技巧:

  • 你创建了一个真正有效的可变函数
  • 另一个定义为STABLE的函数调用VOLATILE函数。此函数可以在hasura中注册

它的工作,但这一招是很难推荐.
谁知道呢,也许未来的postgresql版本或更新将使它成为不可能。

总结

这就是我现在能说的关于这个主题的一切。
事实上,我很高兴在一年前读到类似的东西。
如果有人看到一些陷阱-请发表评论,我很乐意听取意见,也许替代方法。
我希望这个解释能帮助一些人,或者至少能启发人们思考如何以其他方式处理订阅。

相关问题