Web架构基于一个已有20多年历史的技术:状态存储在数据库中,而计算是无状态的。
但是,我们缺少路由原语。
LLM 和AI代理正在悄然违反这一假设,使得这种架构越来越难以使用。这种违反并非一蹴而就,而是通过三种微妙的方式体现出来:
持久执行(Temporal、Ingest、Restate)是目前业界解决执行问题的方案。它使流程具有持久性和弹性。但我们仍然假装它底层是无状态的。这在执行方面有效,但并没有解决交互问题。
路由问题
HTTP + 负载均衡器 + 无状态服务器无法路由到特定进程,只能路由到数据库。
因此,一旦客户端想要与在持久执行框架中运行的进程通信,就会再次面临同样的路由问题。于是,大家都转而采用轮询方式。轮询查询节点,以获取持久执行进程写入数据库的最新更新。
这是一个通用的变通方法,但它仍然很糟糕,原因和轮询一样糟糕:轮询频率的延迟选择、数据库负载、浪费的请求、糟糕的流媒体用户体验。
归根结底,轮询将你的数据库视为消息总线。这正是在真正的消息总线出现之前人们所采用的方法。当你无法确定如何直接联系到想要通信的对象时,轮询就派上了用场。它是一种解决路由问题的变通方案。
我们构建 Web 服务的基本假设正在瓦解。我们长期以来一直使用这种架构进行设计,以至于忘记了它本身也是一种选择。但我们缺少一个基本的路由原语,而 HTTP、负载均衡器和无状态服务器设计都无法解决这个问题。
路由原语
一个可路由的传输名称,但它不是服务器。
我们希望能够这样说:“将此消息发送给正在为工作流 X 生成输出的任何人”,而无需知道是哪台机器、哪个服务器副本或哪个进程。
从上图可以看出,WebSocket 可以很轻松地放入标有“路由原语”的框中。它们是一种支持长时间双向连接的传输协议,用于连接服务器进程和客户端。
但 WebSocket 存在一个问题:它们建立的是连接,而不是地址。它们通过在客户端和服务器之间建立直接连接,一次性地解决了路由问题。但如果连接断开,“地址”就丢失了。你无法重新连接到同一个进程,因为你没有地址可以路由。
发布/订阅通道颠倒了所有权。服务器进程和客户端都不可寻址,但传输层是可寻址的。客户端和服务器都通过名称连接到发布/订阅通道,并进行双向、有状态的通信。通道本身就是地址,与 WebSocket 不同,它并非连接。它是一个持久通道,您可以断开连接并重新连接,而不会丢失数据或无法将数据路由到同一进程。
回到时间示例,持久工作流活动(或步骤)会连接到一个以工作流 ID 命名的发布/订阅通道。客户端会连接到同一通道以获取更新,并发送中断或引导消息。工作流和通道都是持久的,因此即使工作流进程或客户端连接断开,它们也可以重新连接到同一通道并继续通信。
您无需将数据通过数据库传递,无需轮询,也无需担心无法访问实际执行工作的持久进程。
LLM 只是让这个问题更加显而易见。以前,如果连接断开,重试请求的成本很低,而且你很可能会得到确定性的响应。当你可以预期对同一个请求得到相同的响应时,重试就变得简单多了。
但对于LLM来说并非如此。LLM的响应并不确定,而且成本不低。如果你付费购买令牌,肯定不希望因为客户端进入隧道导致连接中断而浪费掉这些令牌。你也不希望为了应对客户端连接问题而将每个令牌都重新写入数据库。
由于 LLM 具有不确定性和高昂的成本,因此它使我们当前架构的局限性更加明显,并使 HTTP + 无状态服务器 + 负载均衡器 + 数据库之间的权衡更加痛苦。
无状态 Web 本身并没有错,只是它并不适合需要长时间运行、有状态且交互式进程的代理型应用程序。我们需要一种新的架构,其中包含能够处理进程(而不仅仅是数据库)的路由原语。
持久执行 + 发布/订阅 + 无状态 HTTP,它们各司其职。
作者:场长
参考:
https://zknill.io/posts/llms-are-breaking-20-year-old-system-design/
本篇文章为 @ 场长 创作并授权 21CTO 发布,未经许可,请勿转载。
内容授权事宜请您联系 webmaster@21cto.com或关注 21CTO 微信公众号。
该文观点仅代表作者本人,21CTO 平台仅提供信息存储空间服务。
请扫描二维码,使用微信支付哦。