我有一个在 AWS Lambda 上运行的简单 FastAPI REST 服务器。它正在使用 AWS Kinesis Firehose 将日志写入 S3,批量为 20 个。
我有 2 个与后台任务相关的问题:
唯一可靠的选择是一次向 Firehose 发送 1 个事件,但这非常慢。我尝试了很多解决方法,但都遇到了问题。
我使用 Boto3 lib 将事件发送到 Firehose,这不是异步的。为了保持较低的延迟,我将事件放入事件队列中,并将 20 个事件批量写入 Firehose,每个批次都在 FastAPI 后台任务中运行。
也许BackgroundTasks 不是适合AWS Lambda 的工具?
为了防止在主线程中等待,我在普通函数中而不是异步中批量写入 Firehose。我可以看到批量写入正在与主线程分开的单独线程中运行。然而,在进行写入时,主线程中没有发生任何事情。
我还尝试让异步周期性后台任务每分钟唤醒一次,并刷新未达到批量写入 20 的事件。但是,除非端点有持续流量,否则此后台任务将关闭。此关闭还将阻止已启动的后台写入任务完成。
一个可能的问题是 FastAPI 的服务器 Uvicorn 默认情况下仅运行 1 个工作线程。我还尝试找到一个地方来更改 Terraform 或 AWS 控制台中的 Unicorn 工作人员数量,但我还没有找到有关如何执行此操作的文档。我什至将内存大小增加到 1.8 GB,为我的 microVM 获取 2 个核心。
我无法判断我的问题是否是一个小的配置错误,或者在静态 EC2 实例上运行 FastAPI 是否会更容易。 EC2 上的后台任务可能不会出现问题,但与 API Gateway 的集成可能会更困难。
我找到了一个低预算的解决方案,可能就足够了:
使用同步事件处理程序,一次将事件发送到 AWS Firehose 1,并避免 FastAPI 的后台任务。
@app.post("/event/")
def post_sync(
events: list[Event],
request: Request,
response: Response,
) -> None:
AWS Lambda 的平均持续时间约为 130 毫秒。
@app.post("/event_async/")
async def post_async(
background_tasks: BackgroundTasks,
events: list[Event],
request: Request,
response: Response,
) -> None:
AWS Lambda 的平均持续时间约为 20 毫秒。但尽管尝试了许多巧妙且复杂的策略,我还是找不到清理最后事件的方法,而且我还丢失了一些写入 Firehose 的后台任务。
FastAPI 是为异步代码编写的,我试图编写一个异步处理程序。也许我混合了同步代码,或者我以非预期的方式使用了后台任务。我的异步解决方案感觉如此接近......