影子请求:OkCupid的第一个GraphQL版本的故障排除188bet金宝搏官网

当我们在一个全新的堆栈中构建我们的GraphQL API时,我们想看看在实际的生产负载下,它如何与我们之前的REST API相媲美,并且我们希望在不影响用户体验的情况下做到这一点。
为此,我们发布了我们称之为影子请求.在我们的目标页面上,用户像往常一样从REST API加载页面的数据并显示页面。然后,用户从GraphQL加载相同的数据,测量调用的时间,并丢弃数据。
这个想法不是我们想出来的,但它改变了我们的游戏规则:我们发现我们的第一个GraphQL API发布两倍的时间- 1200ms vs 600ms - REST API。如果我们将这个版本呈现给真正的用户,他们将会获得非常糟糕的体验。
要了解这个测试如何适应我们在OkCupid发布GraphQL API的整个过程,请查看我之前的文章188bet金宝搏官网关于过渡的帖子.但在这里,我将讨论我们在Docker和Node环境中发现的改进,GraphQL解析器如何处理实体列表和CORS请求。所以,让我们来看看!
Docker和Node低挂水果
我们意识到的第一件事是我不小心发布了一个带有NODE_ENV
设置为发展
.您总是听到不要这样做,因为开发模式支持更多的日志记录和包中较慢的代码路径。但现在我有经验证据可以证明为什么不是:改变NODE_ENV
来生产
平均每个请求为我们节省了34ms。
我们还在这个初始部署中使用了一个未优化的Docker基础映像。从节点
来node-stretch-slim
将图像大小减少600mb (850mb至250mb);虽然这并没有加快应用程序的响应时间,但通过加快构建和部署过程,确实加快了我们的开发周期。
这不是最大的胜利,但这是两个最容易的胜利!
Naive GraphQL解析器可能会很慢
如果你有一个字段返回一个实体列表(在我们的例子中,OkCupid用户),你可能会得到这些用户的每个信息,如他们的名字或年龄。188bet金宝搏官网
我们将此部署转换为GraphQL的页面是OkCupid消息页面。188bet金宝搏官网在创建模式时,我们定义了一个谈话
作为具有最后发送的消息的文本片段,以及用户
代表与你谈话的人的实体。然后我们在顶层添加了一个字段用户
获取该用户对话的实体。以下是模式和解析器的相关部分:

谈话
模式这工作;我们部署并庆祝!但是当我们查看一个请求的堆栈跟踪时,我们看到的是这样的:

好吧,那个瀑布绝对不是我们要找的。但仔细想想,这是有意义的:我们只是告诉解析器如何获取单个用户的信息,所以它会做它知道的一切,并向后端发出20个级联请求。
但是,我们可以做得更好。我们碰巧已经有一种方法可以同时从后台获取多个用户的信息,所以解决方案是用一个包更新我们的解析器,以批量处理相同实体类型的多个请求。很多人使用DataLoader,但在这个特殊的例子中,我发现GraphQL解决批量更符合人体工程学。这里是我们更新的解析器:

getuser
而不是getUser
这里,我们传递给包一个函数它看起来像一个普通的解析器,但不是得到父
作为第一个参数,包提供了父母
(我们的对话列表)。然后我们取出用户id并调用我们的批处理API端点,getuser
.这一变化将通话时间缩短了近275毫秒,时间线看起来相当流畅:

子域名+ CORS不适合我们
这两个变化使我们达到了目标,但是我们的GraphQL API仍然比我们的REST API慢300ms。因为我们已经尽可能地减少了服务器端,所以我们开始从客户端的角度考虑问题。
在项目早期,我们决定将API服务于graphql.188bet金宝搏官网okcupid.com
,并看到用户请求www.188bet金宝搏官网okcupid.com
在飞行前触发了CORS。这是正常的,但他们所花的时间却让人觉得很漫长:300毫秒(你对这个时间有印象吗?)我们和我们的行动小组从多个角度进行了调查(是cloudflare吗?我们的负载均衡器HAProxy?),但没有找到任何合理的线索。所以,我们决定试着从www.188bet金宝搏官网okcupid.com/graphql
, 300毫秒消失了。什么把戏!
嘿,这工作
在对我们的设置发布这一系列更改之后,我们达到了与旧的REST API持平的水平。我们发现并修复了Node环境、GraphQL解析器和CORS的问题,所有这些都不会影响站点性能。然后,我们发布了一个实验,比较真实用户从GraphQL加载数据与REST API加载数据的不同。
如果您正在考虑向堆栈中添加新技术,希望您会考虑一个影子请求来验证它。如果这个堆栈碰巧创建了一个GraphQL API,希望您可以避免我们遇到的一些陷阱。好运!
多亏了雷蒙德孙和OkCupid188bet金宝搏官网网站团队阅读本文草稿。