当我们在一个全新的堆栈中构建graphqlapi时,我们想看看它如何在实际生产负载下与我们以前的restapi相比较,并且我们希望这样做不会对用户体验产生负面影响。

为此,我们发布了我们称之为影子请求. 在我们的目标页面上,用户正常地从restapi加载页面数据并显示页面。然后,用户从GraphQL加载相同的数据,测量调用的时间,并丢弃数据。

我们没有想到这个想法,但它改变了我们的游戏规则:我们发现我们的第一个graphqlapi版本花了大约加倍的时间-1200毫秒对600毫秒-其余的API。如果我们把这个版本展示给真正的用户看,会给他们带来非常糟糕的体验。

要了解这个测试如何适合我们在OkCupid发布graphqlapi的整个过程,请查看我之前的文章188bet金宝搏官网118金博宝娱乐城 . 但是在这里,我将讨论我们在Docker和Node环境中发现的改进,GraphQL解析器如何处理实体列表,以及CORS请求。所以,让我们看看!

码头和节点低挂水果

我们意识到的第一件事是我不小心发布了一个带有节点环境设置为发展. 您总是听说不要这样做,因为开发模式在包中启用了更多的日志记录和较慢的代码路径。但现在我有了经验证据为什么?不是:改变节点环境生产平均每个请求节省34毫秒。

我们还使用了一个未优化的Docker base映像进行初始部署。正在从切换节点节点拉伸纤细将我们的映像大小减少了600mb(850mb到250mb);虽然这并没有加快应用程序的响应时间,但通过加快构建和部署过程,确实加快了开发周期。

这不是最大的胜利,但他们是最容易的两个!

幼稚的GraphQL解析器可以是slooow

如果您有一个返回实体列表的字段(在我们的例子中是OkCupid用户),您可能会得到每个用户的信息,比如他们的姓名或年龄。188bet金宝搏官网

我们要为这个部署转换为GraphQL的页面是OkCupid消息页面。在创建模式时,我们定义了188bet金宝搏官网对话有一个来自上一次发送的消息的文本片段用户代表你谈话对象的实体。然后我们在顶层添加了一个字段用户实体来获取该用户的对话。以下是模式和解析器的相关部分:

简化版的对话架构

成功了;我们部署并庆祝了!但是当我们查看一个请求的堆栈跟踪时,我们看到如下内容:

呃,好吧…那瀑布绝对不是我们要找的。但是仔细想想,它是有意义的:我们刚刚告诉解析器如何获取单个用户的信息,所以它会做它所知道的所有事情,并向后端发出20个级联请求。

但是,我们可以做得更好。我们碰巧已经有一种方法可以同时从后端获取多个用户的信息,因此解决方案是用一个包更新解析器,以批处理同一实体类型的多个请求。很多人用数据加载器,但在这个例子中我发现GraphQL解析批处理更符合人体工程学。以下是我们更新的解析器:

注意更新的数据源调用-获取用户而不是获取用户

所以在这里,我们向包传递一个函数,它看起来像一个普通的解析器,但是没有得到起源作为第一个参数,包提供父母(我们的对话列表)。然后我们提取用户ID并调用批处理API端点,获取用户. 这一变化使通话时间缩短了275毫秒,时间线看起来相当流畅:

在这种情况下,追逐瀑布是明智的

子域+COR对我们不起作用

这两个变化使我们大部分时间都达到了目标,但是我们的graphqlapi仍然比restapi慢300毫秒。因为我们已经尽可能减少了服务器端的工作,所以我们开始从客户机的角度来考虑。

在项目的早期,我们决定从graphql.188bet金宝搏官网okcupid.com,并看到来自www.188bet金宝搏官网okcupid.com正在触发CORS飞行前测试。这是正常的,但他们采取了什么感觉像一个永恒的:300米(时间响了吗?)。我们和我们的行动小组从多个角度进行了调查(是cloudflare吗?我们的负载均衡器HAProxy?),但没有找到任何合理的线索。所以,我们决定试着从www.188bet金宝搏官网okcupid.com/graphql,300米消失了。真是个骗局!

嘿,成功了

在发布了对设置的这一系列更改之后,我们与旧的restapi达到了奇偶校验。我们发现并修复了节点环境、GraphQL解析器和cor的问题,所有这些都不会影响站点性能。然后我们就可以发布一个实验,比较从GraphQL和restapi加载数据的真实用户。

如果您正在考虑向堆栈中添加新技术,那么希望您考虑使用影子请求来验证它。如果这个堆栈碰巧创建了一个graphqlapi,希望您能够避免我们遇到的一些陷阱。祝你好运!


感谢雷蒙德·孙以及OkCupi188bet金宝搏官网d网络团队阅读本文草稿。