计算 API 服务中的 API 调用的有效方法

Effective way to count the API calls in an API service

我是在 DRF 的背景下问这个问题的,但这也可以推广。我们正在维护一项 API 服务,我们正在为 1K+ 实时请求提供服务。在当前情况下,我们正在实时计算 API 次调用,即我们正在更新数据库列 API 次调用针对每个 API 次调用的用户计数。

但是有什么有效的方法吗?例如,在其他地方记录 API 调用,然后在几分钟后更新数据库?还是我们现在正在做的很好?多大规模的 API 服务可能会处理这个问题?网络上没有针对此问题的具体内容。

Redis 是内存中的键值数据存储,因此可以非常快速地检索数据。使用 Redis 实现 速率限制并验证 API 调用的数量 也非常简单。即

  1. 像用户的 IP 地址一样存储密钥
  2. 增加从该 IP 发出的调用次数

Redis Link

Redis 实验室 Link

如果您的应用程序正在将其日志写入 stdout,您可以轻松地将其连接到日志数据库,例如 Elasticsearch,然后计算请求数。您还可以创建非常详细的仪表板,显示您的用户正在使用您的 API.

如果您使用像 NGINX 这样的 Web 服务器来为您的 API 提供服务,您甚至不需要读取应用程序服务器的输出。您可以将其 stdout 日志通过管道传输到数据库中。无论来源如何,让外部进程直接从 stdout 读取都比您在应用程序层上执行的任何写入操作的性能更高。

将您的日志视为事件流是“十二因素应用程序”方法论中描述的 12 个因素之一。您可以在其网站上找到有关此方法的更多信息:

https://12factor.net/

我不建议您在应用程序级别实现此功能,而是使用网络中间件来执行此操作。

正如@guzmonne 所说,您可以直接读取 Nginx 日志,也可以借助一些工具,例如 Filebeat/Logstash

在我的公司,我们使用 Filebeat 从容器(多个 Kubernetes 集群中的 300 多个节点)和其他独立服务收集日志(不仅是 API 调用),所有这些都转到 Elasticsearch 分析日志的集群。

我们不计算 API 次调用,但我们确实关心失败率,当有太多非 200 HTTP 请求时,有一些 Prometheus 规则发送警报。

您似乎在使用 Django,所以我的建议是在此处利用 Memcached:https://docs.djangoproject.com/en/3.2/topics/cache/

Memcached 是一种内存存储,与 Django 配合得很好,并且比 Redis 更简单(但功能也更少)。 Memcached 确保您的计数器在所有 Python 进程中同步,这对于 Django 服务器至关重要。

您可以使用 cache.incr() 增加跟踪 API 调用的计数器,并针对每个用户请求使用 cache.get() 检查计数器。

由于 Memcached 是“内存中的”,数据不会永远保留,因此您还可以在数据库中增加一个计数器 异步(您不想阻塞您的用户要求)。为了使数据库计数器递增更有效,您应该使用 F() 表达式 (https://docs.djangoproject.com/en/3.2/ref/models/expressions/#f-expressions).

除了有用的答案,我发现更好的解决方案是使用 API 网关。我们选择了 Kong。如果您要在 API 服务上收到大量请求,那么将授权、日志记录和其他任务移交给 API 网关是更好的方法。除了自托管 API 网关解决方案,您还可以找到来自 Google、AWS 和其他提供商的托管服务。它是这样工作的:

  1. 您的 API 服务应该只做它们应该做的事情
  2. 将 Kong 或任何其他 API 网关放在您的 API 服务前面
  3. 使用 API 网关处理授权、日志记录等
  4. 将请求日志从网关发送到仪表板等外部服务,或者用它们做任何您想做的事情

我们选择了这种设计,现在我们可以很容易地扩展。这种设计使我们能够保持服务清洁,并帮助我们避免单体架构。我仍然不确定更大的参与者是如何构建他们的 APIs 以及他们如何处理授权、日志记录等,但经过大量试验和错误后我发现工作得很好的是分发跨软件的责任,这些责任被设计为以最好的方式完成一项任务。

除了授权和限速功能,Kong(可能还有其他 API 网关)也可以进行负载均衡。这将使您可以扩展 API 服务,而不必担心破坏事物。