严格来说,bucket 命名空间必须是全局的,这并没有技术原因。事实上,它在技术上并不像大多数人想象的那样完全是全局的,因为 S3 具有三个不同的分区,它们彼此完全隔离,并且不跨分区边界共享相同的全局存储桶命名空间 - - 分区是aws(大多数人称为“AWS”的全球区域集合)、aws-us-gov(美国 GovCloud)和aws-cn(北京和宁夏隔离区域)。
所以事情本来可以不同的设计,每个区域都是独立的,但现在这无关紧要,因为全局命名空间是根深蒂固的。
但是为什么呢?
全局命名空间的具体原因并未公开说明,但几乎可以肯定与服务的发展、向后兼容性以及新区域采用的便利性有关。
S3 是最古老的 AWS 服务之一,甚至比 EC2 还要古老。他们几乎可以肯定没有预见到它会变得如此之大。
最初,命名空间必须是全局的,因为没有多个区域。 S3 有一个逻辑区域(长期以来称为“美国标准”),实际上由至少两个物理区域组成,在 us-east-1 和 us-west-2 中或附近。您不知道也不关心每次上传到哪个物理区域,因为它们透明地来回复制,并且基于延迟的 DNS 解析会自动为您提供延迟最低的端点。许多用户从来不知道这个细节。
您甚至可以使用 s3-external-1.amazonaws.com 端点显式覆盖 DNS 和上传到东部的自动地理路由,或使用 s3-external-2.amazonaws.com 端点上传到西部的自动地理路由,但您的对象很快就可以从任一端点访问。
到目前为止,S3 还没有为新对象提供立即的读写一致性,因为这在早期存在的主要/主要循环复制环境中是不切实际的。
最终,S3 在其他 AWS 区域上线时启动,但他们对其进行了设计,以便任何区域中的存储桶都可以作为 ${bucket}.s3.amazonaws.com 访问。
这使用 DNS 根据主机名中的存储桶名称将请求路由到正确的区域,并且 S3 维护 DNS 映射。 *.s3.amazonaws.com 曾经(现在仍然是)一条通配符记录,它将所有内容都指向“S3 US Standard”,但 S3 会为您的存储桶创建一个 CNAME,该 CNAME 会在存储桶创建几分钟后自动覆盖通配符并指向正确的区域。在那之前,S3 会返回一个临时的 HTTP 重定向。显然,这需要一个全局存储桶命名空间。它仍然适用于除最新地区之外的所有地区。
但他们为什么要那样做呢?毕竟,在同一时间,S3 还引入了${bucket}.s3-${region}.amazonaws.com ¹ 风格的端点,它们实际上是通配符 DNS 记录:*.s3-${region}.amazonaws.com 直接路由到每个 S3 区域的区域 S3 端点,并且是一个响应式(但不可用)端点,即使对于不存在的桶。如果您在 us-east-2 中创建一个存储桶并向 eu-west-1 端点发送对该存储桶的请求,则 eu-west-1 中的 S3 将抛出错误,告诉您需要将请求发送给我们-east-2。
此外,大约在这个时候,他们悄悄地放弃了整个东西方复制的东西,后来将美国标准重命名为当时的真正含义 - us-east-1。 (支持“向后兼容性”论点,s3-external-1 和 s3-external-2 仍然是有效的端点,但它们都指向完全相同的位置,在 us-east-1 中。)
那么为什么存储桶命名空间仍然是全局的?局外人能给出的唯一真正正确的答案是“因为这是决定要做的”。
但也许一个因素是 AWS 希望保持与使用 ${bucket}.s3.amazonaws.com 的现有软件的兼容性,以便客户无需更改代码即可在其他区域部署存储桶。在签名版本 2(及更早版本)的旧时代,签署请求的代码不需要知道 API 端点区域。签名版本 4 需要了解端点区域才能生成有效签名,因为签名密钥是根据日期、区域和服务派生的……但以前不是那样的,所以你可以直接扔掉名称和客户端代码不需要区域意识——甚至不需要意识到 S3 甚至有区域——就可以在任何区域中使用存储桶。
AWS 以其保持向后兼容性的做法而闻名。他们始终如一地这样做,以至于偶尔会出现一些令人尴尬的设计错误并保持未修复,因为修复它们会破坏正在运行的代码。²
另一个问题是存储桶的虚拟托管。在 HTTPS 被接受为非可选之前,通常通过将 CNAME 指向 S3 端点来托管 ststic 内容。如果您将 www.example.com 指向 S3,它将提供来自具有确切名称 www.example.com 的存储桶的内容。您仍然可以这样做,但它不再有用,因为它不支持 HTTPS。要使用 HTTPS 托管静态 S3 内容,您可以在存储桶前面使用 CloudFront。由于 CloudFront 会重写 Host 标头,因此存储桶名称可以是任何名称。您可能会问,为什么不能只将 www.example.com CNAME 指向您存储桶的端点主机名,但 HTTP 和 DNS 在非常不同的层上运行,它根本无法以这种方式工作。 (如果您怀疑此断言,请尝试将您控制的域中的 CNAME 指向 www.google.com。您不会发现您的域服务于 Google 主页;相反,您会收到一个错误,因为 Google服务器只会看到它收到了对 www.example.com 的请求,而不会注意到有一个中间 CNAME 指向它。)存储桶的虚拟托管需要 either 全局存储桶命名空间(所以 Host 标头与存储桶完全匹配)或完全独立的主机名映射数据库到存储桶名称......当您已经建立了存储桶的全局命名空间时,为什么要这样做?
¹ 请注意,这些端点中 s3 之后的 - 最终被更符合逻辑的 . 取代,但这些旧端点仍然有效。
² 想到的两个例子:(1) 当非 CORS 请求到达启用 CORS 的存储桶时,S3 错误地省略了 Vary: Origin 响应标头(我曾争论过这个问题可以在不中断的情况下修复,但没有成功任何事情,无济于事); (2) S3 在 API 上对对象键中符号 + 的处理明显不正确,其中服务将 + 解释为意味着 %20(空格),因此如果您希望浏览器从指向 @ 的链接下载987654343@你必须上传为/foo{space}bar。