为什么我应该用 asynchronous/non-blocking 框架构建一个 API?

Why should I build an API with an asynchronous/non-blocking framework?

我一直在研究 Play Framework as a possible candidate for helping me to build a simple API. However, the Django Rest Framework (DRF) 似乎也是一个非常强大的内容。

据我所知,DRF 并没有像 Play Framework 那样宣传自己是一个异步(或非阻塞)框架,但我对这是否重要感兴趣。我一直在想的情况是通过 Mandrill 向用户发送电子邮件——我不希望我的 API 陷入困境,等待 Mandrill API 告诉它是否发送电子邮件已发送。

因此,我认为问题可以这样总结:从客户的角度来看,我构建一个 API 和 asynchronous/non-blocking 框架(如 Play over the DRF)是否有好处,还是我没抓住要点?

我是 Django REST 框架贡献者(和用户),所以我的观点偏向于此。

Django REST 框架建立在 Django 之上,Django 是一个用于 Web 应用程序的同步框架。如果您已经在使用像 Django 这样的同步框架,那么使用同步 API 就 不是问题

现在,仅仅因为它是同步的,并不意味着一次只能处理一个请求。大多数处理 Django 应用程序的 Web 服务器 can handle multiple requests, some of theme even do it somewhat asynchronously across multiple threads. Usually this isn't actually an issue, as your web server can typically handle many concurrent requests, even if some of them are blocking. And when you have long, blocking calls you usually don't want that done within the API - you should be delegating that to background workers like Celery or Resque.

这不仅适用于 Django,许多相同的原则也适用于其他同步框架,例如 Rails 和 ASP.NET MVC。如果您有 运行 长的请求,您通常应该将工作委派给其他流程,而不是搁置该请求。通常使用 202 响应代码 for these cases.

现在,这并不一定意味着异步框架没有用。在 Node.js 等运行时,大多数框架 handle requests asynchronously。在这些语言中使用同步框架没有意义,因此大多数库都是异步构建的。

您的选择在很大程度上取决于您已经在使用的工具。

关于连接到您的应用程序的客户端,您的服务器是否使用 asynchronous/non-blocking (ANB) 技术应该没有任何区别。但这可能会对您的应用程序可以处理的请求数量产生很大影响。

假设以下场景:检查 FB/Google/etc 访问令牌是否有效的请求,然后使用它来获取用户的社交资料,然后 returns 返回一些内容。

如果您在服务器中使用阻塞式 HTTP 客户端,则在 2 个 HTTP 请求中的每一个期间,为该请求提供服务的线程可能会被阻塞很多时间而无所事事。 如果您在发出 HTTP 请求并且响应返回时使用非阻塞 http 客户端(例如 Play 带来的客户端),则线程可用于执行其他操作(例如:处理另一个请求的一部分)。

请注意,要解决这个问题 "problem",您不需要 ANB 框架,只需要一个 ANB http 客户端。因此,您应该更多地关注您的应用程序中的操作类型,并检查您选择的框架将如何处理它们。例如:如果您的应用程序几乎由数据库 CRUD 操作组成,并且数据库驱动程序处于阻塞状态(例如 Java 中的 JDBC 并且可能是 Django 使用的那些),那么框架是否异步并不重要无论是否,您大部分时间都会在该特定组件上阻塞。

在您的电子邮件示例中,Django+Celery 可能与 Play/Akka 一样好。

非异步框架通常执行长 运行 任务,将它们传递给某些外部进程(例如 Resque/DelayedJob/sidekiq 用于 Rails 开发)

只是想补充一点,Mandrill API 支持发送电子邮件的异步参数。 这是他们的文档所说的:

enable a background sending mode that is optimized for bulk sending. In async mode, messages/send will immediately return a status of "queued" for every recipient. To handle rejections when sending in async mode, set up a webhook for the 'reject' event.

因此,如果使用 async 设置为 true,您将在执行对 API 的调用后立即获得句柄,而无需等待所有电子邮件发送完毕。

https://mandrillapp.com/api/docs/messages.JSON.html#method-send

(我以 API 的 JSON 版本为例)

Django 社区目前正在处理这个问题,如果您愿意,可以使用 sync_to_async() 适配器。 它有一些限制和性能损失,但社区仍在努力。

下面的 link 将帮助您使用 sync_to_async() 适配器

https://docs.djangoproject.com/en/3.2/topics/async/