跳到主要内容

ARC Deep Dive:从一个网址到应用呈现

Robert
AFSArchitectureDID

点开 www.arcblock.io,应用很快就出现在浏览器里。这个网址怎样找到应用,应用的数据又从哪里来?下面是这次打开官网时看到的页面。我们沿着一次访问,分阶段拆开它背后的 ARC。

在浏览器打开 www.arcblock.io,ARC 呈现官网的首页、导航和文章入口。

官网中文版实拍,2026 年 10 月 18 日。

我们的官网是 ARC 承载的一个应用。ARC 的全称是 Agentic Realm Computer,同一套运行时架构可以通过不同域名承载不同应用。每个应用有自己的定义和资源;用户登录以后,还会带进来另外一部分环境:自己的身份,以及能够跨越一次次应用访问而持续保存的个人数据。

上一篇《Beyond Serverless》解释了我们为什么要在 Cloudflare 上构建虚拟计算机。这一篇把它打开,跟着一次请求往里走:Cloudflare 在哪里把控制权交给 ARC?一个域名怎样变成一个应用?个人数据什么时候加入进来,又怎样与其他访问者的数据分开?

可以先记住一个画面:用户带着自己的盘来使用应用。应用提供软件,用户授权它访问盘上的一部分内容。换一个应用,盘还跟着用户走。

第一阶段:从域名到运行 ARC 的 Worker

前面一小段路很熟悉。DNS 帮浏览器找到服务,TLS 保护连接,Cloudflare 接住 HTTP 请求。自定义域名可以通过 CNAME 指向服务入口,同时配好相应的域名与证书。对接下来的过程,重要的是请求仍然带着用户访问的那个 hostname。

Cloudflare 的路由配置把请求送到运行 ARC 的 Worker。平台在这里交出一个 HTTP 请求;接下来的页面选择、身份判断与资源访问,由 ARC 组织。

第二阶段:让 ARC 的计算环境就绪

请求已经进入 ARC 的入口。接下来需要准备多少运行环境,取决于这次访问要做什么。

ARC 先判断请求携带的身份信息,并检查能否使用公共页面缓存。没有登录凭证的公开文章访问,可以直接返回缓存中的 HTML,跳过完整运行环境的初始化与个人数据接入。带有身份的请求,要先完成相应调用者判断,再决定哪些页面可以复用。

没有命中这条捷径,请求才继续进入页面路由。代码在这里区分了两种就绪状态:getRouter() 先准备注册表和域名路由,让页面内容可以被找到;getHost() 则等待完整计算环境,供需要会话、RPC 等能力的路径使用。公开页面有时由页面路由直接给出响应,完整环境按后续工作需要再就绪。

这就是虚拟计算机的启动阶段在云端的样子:运行时按需初始化 AFS、连接宿主适配器、准备 AOS 服务。Cloudflare 决定何时启动新的执行实例,ARC 则复用已经准备好的注册表、应用与服务。一次浏览器访问,可能进入新启动的环境,也可能使用一台已经就绪的计算机。

接下来,ARC 根据配置好的完整域名别名或部署域名规则,找到对应的 Blocklet,再解析应用实例。官网这样的品牌域名,使用明确登记的域名关联;开发环境也可以配置根域名下的子域名规则。Blocklet 描述软件本身,实例代表这一次安装的上下文。同一份软件可以用于不同安装,域名负责把访问带到其中一个确定的目的地。

这也是一道入口边界。要让一个域名打开指定应用,运营者需要配置相应的路由与应用关联。运行时按部署规则选择已经提供的应用,DNS 指向本身不会替它安装新的 Blocklet。

公开缓存可直接返回页面;需要继续处理的请求进入注册表和域名路由,再按工作需要建立应用与用户视图。

同一套 ARC 部署可以处理许多这样的绑定。官网、社区和另一个站点,可以经过共同的运行时入口,再被分配到不同应用实例。Cloudflare 负责调度执行,ARC 负责选择应用,并组织这次访问所需的资源环境。

同一个 Worker 实例可以处理多个请求,包括并发请求;下一次访问也可能落到另一个实例。Cloudflare 的执行模型文档说明了这种调度方式。应用与用户的数据边界,需要在这种调度下持续成立。

第三阶段:加载 Blocklet,挂载实例数据

找到 Blocklet 之后,ARC 要把运行应用所需的资源组织起来。这里有我们很在意的一层分离:软件本身、这次安装共享的数据,以及当前用户的个人数据,来自三类不同的挂载。

资源在应用视图中的位置它负责什么
Blocklet 软件内容/packages应用的页面、布局、脚本和声明,以只读方式提供
实例数据/instance这次安装的配置、共享内容,以及应用实例运行中产生的持久数据
当前用户的数据/user经过认证的用户在这个应用实例里的个人记录和偏好

同一份 Blocklet 可以被多次安装,使用不同的实例配置与数据。同一个实例可以服务多位用户,每位用户又有自己的个人数据。实例的“共享”指的是这次安装共用的资源,具体哪些内容向访客公开,仍由应用的接口和权限决定。

只读的 Blocklet 软件、安装实例的共享数据和当前用户的个人数据,通过三个挂载组合进同一应用视图。

这次应用加载先把软件接进来。运行时解析 Blocklet 定义,把页面、脚本和声明的软件资源挂到只读的 /packages 视图,知道这个应用可以提供什么内容、怎样呈现、有哪些执行入口。

接下来是安装实例的数据。相同软件装在两个地方,可以有不同的设置与共享内容;软件升级时,这些运行数据也需要保留下来。运行时因此为当前实例解析对应的数据后端,接到 /instance。Blocklet 可以把初始内容放在 /packages/seed/,运行时尝试将缺少的文件补到 /instance/,已有文件保留。版本标记帮助后续启动判断是否需要再检查种子内容。

软件和实例资源组成应用的基础视图,并可以在后续请求中复用。当前用户进入时,再接上属于这位调用者的数据视图。由此形成的文件系统,同时表达了“运行什么软件”“使用哪一次安装的数据”和“现在是谁在使用”。

这棵树通过 AFS,也就是 Agentic File System,提供访问接口。ARC 能够沿路径定位页面、读取相关内容,再根据应用定义生成响应。

“文件系统”提供的是一种容易理解的资源访问方式:沿路径找到东西,进行允许的操作。它背后的实现比本地硬盘上的目录更丰富。AFS Provider 可以把存储、远程服务或其他实现提供的资源接进来。调用者遵循挂载资源的接口和权限,具体怎样访问底层服务,则由 Provider 处理。

以刚才那篇公开文章为例,运行时可能只需要找到文章、读取正文、根据 AUP 定义的呈现方式完成渲染,再把页面交给浏览器。另一个应用则可能读取结构化记录,或者调用某个 Provider 暴露的能力。同一套环境可以承载这些不同的工作;实际响应取决于应用定义,以及调用者有权访问什么。

AFS 是这套结构的共同基础。应用的软件、运行数据、用户资源和可调用能力,都可以进入同一套寻址与操作体系。运行时由挂载和投影组织它们,应用通过自己的视图使用它们,底层 Provider 负责对接不同实现。界面也沿用这个基础,后面会看到它怎样变成网页。

这也是 AFS、AOS 和 ARC 的关系。AFS 提供资源接口;AOS,也就是 Agentic Operating System,围绕这些资源组织会话、身份和访问等操作系统行为;ARC 把它们放进具体运行环境,组成一台虚拟计算机。Blocklet 是这台计算机里的应用。

这样划分以后,资源从哪里来,就可以与应用怎样使用资源分开。挂载的来源可以在运行时本地,可以来自已部署的 Blocklet,也可以通过远程 AFS 接口访问。HTTP 是远程访问的一种传输方式;远端需要提供相应的 AFS 操作、资源结构与授权机制,应用才能正确使用它。部署来源的接入有明确的协议约定。

Provider 也为应用提供了扩展入口。一个专门的后端,可以把能力整理成具有明确路径与访问规则的接口,再接入 AFS。它继续保留自己的实现方式,应用则通过 AFS 使用它。统一的是访问资源的方式,每种资源的语义和要求仍然由相应 Provider 定义。

公开访客所需的资源,到这里就可能已经齐备,可以进入最后的页面呈现。我们先沿着另一条分支,看看需要登录的应用怎样接入个人数据。

第四阶段:接入用户空间,建立隔离的会话视图

假设用户接下来打开一份私人文档,或者保存一个偏好设置。ARC 此时需要确认谁在发起请求。域名说明访问的是哪个应用,用户身份则回答正在使用它的是谁。

基于 DID 的认证,为这个人提供可验证的身份。身份服务验证请求携带的登录凭证,运行时据此建立调用者上下文,再把授权和数据访问关联到这个身份。浏览器传来的任意 DID 字符串,不能自行决定要挂载谁的数据。在一次访问里,应用身份、安装实例身份和调用者身份,承担的是不同角色。把这些角色分清,后面的数据边界才有依据。

到这里,软件与实例数据已经有了位置。下一次挂载由用户身份决定:运行时为这位调用者找到其个人数据后端,按当前应用实例选出相应片段。已有个人数据通过这个片段继续访问。初次使用所需的偏好或记录,由应用的默认值与写入逻辑处理。

随后,ARC 为当前调用者提供一份专属的 AFS 视图。应用的公共资源仍然可用,个人资源部分则根据已经认证的用户,以及相关应用实例来解析。匿名访问没有可以浏览的个人 /user 挂载;用户登录后,/user 指向的是这个人在当前应用实例中的数据。

Cloudflare 运行时里,这个区别是明确的。/instance 表示这次安装范围内共享的资源;/user 的作用域结合调用者 DID 和实例 DID 确定。需要访问更广的个人 Space 时,要显式配置用户作用域的视图,并遵循跨应用访问限制。文件系统的形状,直接表达了资源归谁、当前上下文可以使用哪些资源。

用户的 Arc Space 与个人身份相连,不同应用获得各自被授权的资源视图。

用户身份放在应用之外还有一个意义:笔记应用和社区不必各自定义一个互不相干的“我”。DID 为个人数据的归属与授权提供共同依据,域名和应用实例则确定这次访问的目的地。换掉一个界面,用户与数据的关系仍然能够被识别。

这就是我用“个人盘”来解释 Arc Space 的原因。你换一个应用使用,过去积累的工作应该仍然与你相连。应用获得你允许它使用的那部分资源视图。笔记应用可以处理你的笔记,另一个应用可以在授权范围内使用个人环境中的特定记录。

这个画面里包含几道不同的边界。应用范围内的用户数据、安装实例的数据,以及更广的个人 Space,各有用途。权限决定应用能看见盘上的哪一部分、能做什么操作,以及写入是以谁的身份发生的。

持久数据也有自己的存储位置,不依附于眼下处理请求的 Worker 实例。在 Cloudflare 实现里,结构化记录和存储元数据使用 D1 支撑的设施,对象内容可以使用 R2。AFS Provider 把路径层面的操作连接到底层服务。Worker 执行操作,存储服务保存结果。

例如,Alice 与 Bob 都让同一个应用读取 /user/app/preferences.json。应用代码里的路径一样,运行时为两人选择的用户数据 Provider 不同,读取的是各自的偏好。Alice 换到另一个应用实例,同样的 /user 又会指向她在那个实例中的数据片段。这里连接的是同一位用户拥有的数据空间,每个应用拿到其中对应的视图。

这相当于同一块盘上的不同应用目录。新应用默认打开自己的目录,旧文档仍保存在原来的位置。要让新应用继续处理某份旧记录,需要把选定记录明确交给它,例如导入到新应用的数据片段;共享资源也需要明确的接口和授权。用户保留数据,应用获得具体的访问范围。

拿保存文档来说,应用通过当前调用者的 AFS 视图访问允许操作的资源,运行时带上身份与权限上下文,底层 Provider 完成实际写入。用户下次再来,请求即使落到另一个执行实例,也能找到保存的结果,因为文档的身份与存储作用域一直存在于持久层。

这里的分工很重要:应用定义工作,运行时执行工作,用户的持久上下文有自己的身份和访问边界。执行实例可以被基础设施随时替换;当个人记录能够独立寻址,应用之间的衔接也就有了更稳定的基础。

同一个网站里的 Alice、Bob 和 Tom

看到许多人同时访问一个服务,很容易想到传统共享主机的画面:大家都进了同一台机器,一个用户能不能顺着自己的入口,摸到另一个用户的文件?应用里的一个操作,会不会变成整台宿主机的控制权?这正是我们要在架构上明确划出的边界。

对 Alice、Bob 和 Tom 来说,浏览器地址栏里可以是同一个网站。ARC 为他们各自建立调用者与会话专属的资源视图。从使用模型看,每个人进入一份自己的逻辑计算环境:身份决定个人 /user 指向哪里,会话保有自己的资源与权限上下文,允许执行的操作受相应权限约束。

实现这一点的关键,是会话专属的 AFS overlay。它把当前用户的资源覆盖到可复用的应用基础视图上,不把 Alice 的个人挂载写进所有人共享的基础对象。Bob 的会话没有一个可以枚举所有用户目录的 /users 入口;他在自己的 /user 里看到的是自己的应用数据。持久存储继续按调用者与应用实例确定作用域,让这道边界延伸到实际读写的位置。

Alice、Bob 和 Tom 访问同一应用,各自拥有身份、个人数据挂载和会话权限上下文;共同使用的软件与实例资源另有明确边界。Cloudflare 调度 Worker,ARC 隔离调用者视图。

这也体现了 AFS 的 Small World 设计。应用先获得自己的资源世界,会话再叠加当前调用者的个人视图。它拿到的是工作所需的局部命名空间,系统其余资源不会默认出现在这棵树里。有限披露从可见的路径开始:例如 Bob 的视图只接上 Bob 的个人数据,不提供遍历所有用户空间的入口。视图之内,再由访问模式和操作权限控制能够怎样使用这些资源。收窄可见范围与限制操作相互配合,让隔离落实到 AFS 这一层。

这张图里的三个框,表示三个独立的逻辑会话环境。Cloudflare 在底层用 V8 isolates 隔离执行环境,并调度请求;ARC 在其上建立会话视图与数据访问边界。一个 Worker isolate 可以处理多个会话的请求,这些请求也可能由不同执行实例、不同位置处理。我们把隔离绑定在身份、会话与资源作用域上,使它在这些调度方式下都能成立。Cloudflare 的执行模型与 ARC 的会话模型,在这里承担互补的职责。

用户之间当然可以交换数据。例如 Alice 在社区发出一篇公开帖子,Bob 通过社区提供的读取接口看到它。应用决定共享哪些资源、允许什么操作;Bob 仍然使用自己的会话视图。共享一条内容,并不需要把作者的个人工作空间交给读者。

这里的权限也沿操作继续生效。应用看到的是挂载给它的资源接口,能够执行的是声明和授权允许的操作。一个普通的应用请求不会因此得到宿主机的管理权限。Cloudflare 的执行边界、ARC 的会话资源视图,以及 Provider 对实际访问的处理,共同减少了从一个用户入口横向访问其他用户资源的机会。

DID 在这里解决的是一个基础问题:系统怎样获得稳定、可验证的“谁在行动”的依据。认证与授权围绕同一个身份引用工作;TLS 保护网络连接;哪些资源和操作可以使用,则由权限规则决定。每个机制有自己的职责。

托管运行时本身也处于信任边界之内。服务处理一份获准访问的文档,就需要正确处理文档内容。用户数据的安全,取决于凭证验证、权限执行、资源隔离和基础设施的共同作用。身份标识为这些控制提供依据,具体控制仍然要在访问过程中落实。

第五阶段:把资源变成浏览器里的应用

回到开头那张官网截图。公开访问可以沿缓存或页面路由分支走到这里;需要个人数据的应用,则先准备好相应调用者视图。

AFS-UI 是建立在 AFS 上的界面系统:界面结构、相关状态和支持的操作,也能够进入可寻址的资源空间。AUP,也就是 Agentic UI Protocol,为界面结构与交互提供描述约定。资源访问和界面因此能够围绕同一批对象衔接起来,人通过画面操作,agent 则可以通过受支持的路径检查和操作它们。

本例走的是 Web Device 的网站呈现链路。运行时找到页面定义,读取当前视图允许访问的内容,再由 Web 呈现链路把布局与内容生成 HTML,连同样式、脚本和图片交给浏览器。浏览器解析并绘制这些资源,网址才变成眼前可以阅读、点击的网站。开头看到的导航、文章卡片和链接,都是这条链路的结果。

同一次官网访问的最终呈现:浏览器将 ARC 返回的页面与静态资源绘制成可阅读和操作的网站。

AFS-UI 的呈现方式还可以超出网页。Swift 与 Kotlin 实现中也有原生界面渲染器,能够把受支持的界面描述呈现为原生控件;设备支持哪些元素与交互,由对应实现决定。今天沿着官网走到的是浏览器,同一资源与操作模型也为其他设备入口提供基础。

进入实时界面会话以后,AUP 描述界面和交互方式。用户的一个动作,可以重新进入会话的执行上下文,读取允许访问的资源、更新状态,再产生下一次界面呈现。在 Cloudflare 上,Durable Objects 为有状态会话提供了适合的协调基础,其身份与协调模型可以参见官方文档。

会话负责保持交互的连续性,个人记录则保存在持久存储里。一次点击、一次界面更新和一次数据写入彼此关联,但它们的生命周期不同。把这些关系组织起来,才有可能在执行实例不断被调度和替换的基础设施上,构建一台持续可用的虚拟计算机。

这台计算机可以有不同的住所

沿着请求走出来,用户看到的结果又很简单:页面出现了,保存的文档下次还能打开。背后,Cloudflare 接住并调度请求;ARC 找到应用,建立调用者视图,再协调对相应资源的访问。

不同托管需求,可以沿着这套分工选择部署边界。共享托管让许多登记的应用使用一套受管理的 ARC 部署;专用环境把运行时和资源配置独立管理;自行部署则由运营者承担相应责任。每种方式都要明确配置域名绑定、存储和身份边界。

Cloudflare 为这些选择提供了不同积木。Cloudflare for SaaS处理客户域名的接入与交付;Workers for Platforms提供用户 Worker 与动态分派机制,适合平台承载可执行工作负载的场景。部署设计要先回答需要哪一种边界:客户域名、独立应用环境,还是单独分派的代码;相应集成与运维方式再随之确定。

虚拟计算机的模型也可以落在 Cloudflare 之外。ARC 有面向常规计算环境的 Node 运行时,以及 Swift 和 Kotlin 原生实现。Linux 服务器、容器和移动设备提供不同资源,也有不同的执行条件。具体 Provider 决定 AFS 暴露什么、这台计算机能够做什么。设备侧的部署,需要相应运行时实现,以及符合设备条件的资源接口。

对我们的托管实现,Cloudflare 是一个很合适的住所:执行、协调与存储服务,分别承接这台计算机的不同部分;ARC 则把这些部分连接到应用和使用它的人。

这就是一个网址背后的过程。域名打开应用,应用运行在虚拟计算机里,用户带着身份和获准访问的个人空间进入其中。页面会换,执行请求的 Worker 实例会变,用户仍然能够回到自己的数据,授权另一个应用,继续工作。这种连续性,是我们构建这台计算机时最在意的事情。