Language:Chinese VersionEnglish Version

当我开始运行 NovVista 时,架构很简单:弗吉尼亚州的一台服务器、一个域名,以及一个乐观的假设——一个区域就足够了。有一段时间确实如此。后来流量模式发生了变化,一个数据中心在最糟糕的时间进行了长时间的维护,我开始认真考虑多区域部署的问题。

传统观点认为多区域部署既昂贵又复杂,只有拥有专门平台团队和雄厚资金的公司才能采用。这在一定程度上是正确的。但在过去两年里,我为 NovVista 建立了一个多区域设置,在不让这个自筹资金项目破产的情况下,提供了有意义的弹性和全球性能。以下是我学到的东西,包括我犯的错误和我接受的权衡。

为什么选择多区域,为什么不选择

在深入探讨如何实现之前,让我们诚实地思考一下你是否真的需要多区域架构。问题不在于它在系统设计图上听起来是否令人印象深刻。问题在于,对于你的具体情况,收益是否值得付出成本和复杂性。

采用多区域的合理理由

为全球受众降低延迟。如果你的用户分布在各大洲,单区域部署意味着有些用户总是离你的服务器很远。东京的用户访问弗吉尼亚州的服务器,在应用程序开始处理请求之前,就会增加大约 150-200 毫秒的往返延迟。对于交互式应用来说,这是明显的。对于实时功能来说,这可能是致命的。

可用性要求。单区域部署在区域级别存在单点故障。云服务提供商偶尔会出现区域范围的故障。如果你的业务无法容忍此类事件中数小时的停机时间,多区域可以提供你所需的冗余。

数据驻留合规性。GDPR、数据本地化法规或行业特定要求等法规可能要求用户数据保持在特定的地理边界内。多区域架构可以让你的数据保持在法律上需要的位置附近。

什么时候不应该采用多区域

你的流量集中在某个地理区域。如果你的 90% 用户在北美,在欧洲增加第二个区域只会带来微小的收益,却增加了成本和复杂性。在你的单区域部署前使用 CDN,可以以更低的复杂性处理国际用户的静态资源和可缓存响应。

你没有运营能力。多区域会使你的基础设施覆盖面翻倍。每次部署、每个监控警报、每个事件响应程序现在都需要跨越多个区域。如果你的团队已经疲于奔命地维持一个区域的平稳运行,增加第二个区域只会让一切变得更糟。

你的数据库无法处理这种情况。多区域部署的效果取决于你的数据层。如果你的应用需要强一致性,而你的数据库不支持良好的多区域复制,那你就是在自找分布式系统的麻烦。关于这一点,稍后会详细说明。

对于 NovVista 来说,这个决定是由延迟和可用性共同驱动的。我们在北美和欧洲都有大量受众,如果在高峰发布时段出现服务中断,将会造成严重影响。但我也知道需要控制成本,因此每个架构选择都经过了预算约束的筛选。

CDN 策略:影响最大、成本最低的胜利

如果多区域部署是目的地,那么配置良好的 CDN 就是第一段路程。对于许多项目来说,这可能是你唯一需要的一段路程。

CDN 实际为你提供了什么

CDN 在全球各地的边缘位置缓存你的内容。对于像 NovVista 这样内容丰富的网站,这意味着文章页面、图片、CSS 和 JavaScript 都从附近的边缘节点提供服务,而不是返回到源服务器。性能提升是显著的,通常能为远距离用户减少 50% 或更多的页面加载时间。

但 CDN 也充当了读取流量的实际多区域层。当你的边缘缓存命中率很高时,源服务器几乎不需要参与为国际用户提供服务。这让你获得了多区域的大部分延迟优势,而无需任何数据复制的复杂性。

在预算有限的情况下选择 CDN

Cloudflare 的免费版和专业版对于独立项目来说确实非常出色。你获得了一个全球任播网络、自动 TLS、DDoS 保护以及具有精细缓存规则的边缘缓存。对于 NovVista 来说,每月 20 美元的 Cloudflare 专业版提供了我所需的所有 CDN 功能,外加他们的 Web 应用防火墙和性能优化。

最大化 CDN 价值的关键是积极缓存。对于发布网站,文章页面可以在边缘进行长时间 TTL 缓存,并在内容更新时清除。我使用缓存标签在文章编辑时有选择地清除相关内容,而不是清除整个缓存。这使缓存命中率保持在 90% 以上,同时确保内容新鲜度。

对于动态 API 端点,你显然不能以相同方式进行边缘缓存。但即使在这里,几秒的短 TTL 也能显著减少读取密集型且可容忍轻微陈旧数据的端点的源服务器负载。分析仪表板、热门内容列表和与用户无关的推荐都是很好的候选。

DNS 故障转移:无需复杂性的弹性

一旦你有多个能够提供服务的区域,就需要一种方法将用户路由到正确的区域,并在某个区域故障时进行故障转移。DNS 是实现这一目的的最简单机制,对于许多应用来说,这已经足够了。

DNS故障转移如何工作

基本设置包括健康检查和加权或故障转移DNS记录。您的DNS提供商监控每个区域端点的健康状况。当某个区域通过健康检查时,其IP地址会包含在DNS响应中。当检查失败时,该IP地址会被移除,流量会转移到健康的区域。

对于NovVista,我使用Cloudflare的负载均衡和健康检查功能。主要区域是美国东部,次要区域是西欧。在正常情况下,用户基于Cloudflare的anycast网络被路由到最近的健康区域。如果一个区域宕机,所有流量会在健康检查间隔内转移到幸存区域,我已将该间隔设置为三十秒。

TTL的权衡

DNS故障转移速度受DNS TTL限制。三百秒的TTL意味着即使在DNS更改传播后,某些客户端仍会尝试访问故障区域长达五分钟。较低的TTL能提供更快的故障转移,但会增加DNS查询量,并可能略微增加每个TTL周期初始请求的延迟。

我使用六十秒的TTL,这是一个合理的折中方案。通过Cloudflare代理,实际的DNS解析在其边缘处理,而基于健康检查的路由比传统DNS故障转移响应更快。

超越简单故障转移

更复杂的DNS策略包括基于延迟的路由,用户被发送到从其位置延迟最低的区域,以及基于地理位置的路由,用户根据其国家或大陆被发送到特定区域。AWS Route 53、Cloudflare Load Balancing和NS1都支持这些策略。

对于NovVista,基于地理位置的路由是主要策略,故障转移是次要策略。欧洲用户前往欧盟区域,其他所有人前往美国东部。如果任一区域故障,所有流量会汇聚到幸存区域。这种方式简单、可预测,并且在事件发生时易于理解。

数据库复制:真正的复杂性所在

多区域架构中最困难的部分是数据层。其他一切,您的应用服务器、缓存、负载均衡器,都可以相对容易地在区域间复制,因为它们是无状态或接近无状态的。您的数据库是状态所在的地方,而将状态分布在地理区域会带来根本性的权衡。

CAP定理的实际应用

您可能听说过CAP定理,当您尝试在网络延迟为五十到一百毫秒的区域间复制数据库时,这一定理最为真实。您无法同时实现跨区域强一致性和高可用性。您必须做出选择。

对于 NovVista,我选择了最终一致性作为内容数据库的方案。在一个区域发布的内容会在几秒内传播到另一个区域。在此期间,欧洲的用户可能看不到刚刚从美国区域发布的内容。对于发布平台来说,这是一个可接受的权衡。但对于银行应用来说,则不可行。

经济高效的数据库复制

像 CockroachDB、PlanetScale 或 AWS Aurora Global Database 这样的全托管多区域数据库使复制变得更容易,但可能很昂贵。PlanetScale 的方法对小型项目特别有吸引力,因为它透明地处理复制,并根据使用量收费,而不需要大量前期承诺。

对于 NovVista,我采用了一种更简单的方法:在美国东部设置一个主 PostgreSQL 数据库,在西欧设置一个只读副本。主数据库处理所有写入操作。欧洲的读取流量访问本地副本。这不是真正的多区域写入能力,但它覆盖了主要用例:为全球用户提供快速读取,同时写入操作全部发送到单个主数据库。

成本差异显著。一个托管的多区域数据库每月可能需要花费两百到五百美元。而在 Hetzner 或 DigitalOcean 这样的服务提供商上,主数据库加只读副本的方案每月只需三十到六十美元。对于一个自筹资金的项目来说,这种差异很重要。

处理单主设置中的写入操作

单主设置的明显弱点是来自非主区域的写入操作会产生跨区域延迟。欧洲用户提交评论时,会访问欧洲的应用服务器,该服务器将数据写入美国东部数据库,增加了大约八十毫秒的往返时间。

对于 NovVista 来说,这是可接受的,因为与读取操作相比,写入操作并不频繁。评论、账户注册和内容管理操作只占总流量的一小部分。对于执行这些操作的用户来说,八十毫秒的延迟几乎无法察觉。

如果你的应用写入密集且对写入延迟敏感,你需要多区域写入能力,但这会显著增加复杂性和成本。在采用这种方案之前,请仔细测量写入延迟是否真的对你的用户构成问题,还是仅仅一个在真实用户体验中并未体现的架构问题。

应用层:必要时的无状态设计

多区域应用服务器必须是无状态的。任何存储在特定服务器实例上的状态、会话数据、文件上传、缓存计算,都必须外部化到一个两个区域都可以访问的共享存储中。

会话管理

存储在服务器内存中的 HTTP 会话是多区域部署最常见的障碍。解决方案是使用共享的会话存储(如 Redis)或切换到使用 JWT 的无状态会话管理。

对于 NovVista,我使用 JWT 进行身份验证。令牌是自包含的,可以被任何区域的应用服务器验证,无需集中式会话存储。这完全消除了跨区域会话同步的需求。代价是令牌撤销需要维护一个小型拒绝列表,我将其存储在跨区域复制的 Redis 实例中。

文件存储

在多区域设置中,用户上传的文件不能存储在本地磁盘上。像 S3、R2 或类似的对象存储是标准解决方案。Cloudflare R2 特别具有成本效益,因为它没有出口费用,这对于向全球受众提供媒体文件是一个重要考虑因素。

对于图像和媒体,我使用 Cloudflare R2 并启用自动复制。在任何区域上传的文件都会通过 R2 的内置分发立即在全球范围内可用。结合边缘的图像转换,这实现了媒体交付,无需任何按区域存储管理。

跨区域的监控和可观测性

没有多区域可观测性的多区域部署就像是盲目飞行。你需要独立了解每个区域发生的情况,并在诊断问题时能够跨区域关联事件。

监控什么

至少,你需要按区域进行健康检查、延迟指标、错误率和数据库复制延迟。复制延迟尤其关键,因为它直接影响用户的一致性体验。如果你的只读副本落后主数据库几分钟,该区域的用户就会看到过时的数据,这可能导致混乱和支持工单。

我使用 Uptime Kuma 进行健康监控,它是自托管且免费的。对于应用级可观测性,Grafana Cloud 的免费层为 NovVista 规模的项目提供了足够的容量。关键是拥有并排显示各区域指标的仪表板,这样你可以快速识别出一个区域相对于其他区域性能下降的情况。

事件响应

你的事件响应流程必须考虑多区域场景。你可以手动故障转移到单个区域吗?需要多长时间?你练习过吗?在故障转移过程中,正在进行的请求会发生什么情况?

我每季度进行一次故障转移演练,故意将所有流量路由到一个区域并验证一切是否正常工作。这会在真实事件发生之前捕获配置漂移、容量规划差距和流程问题。演练通常需要三十分钟,并且不止一次发现了重要问题。

成本分解:实际成本

对于独立项目来说,多区域最常见的反对意见之一是成本。以下是 NovVista 多区域设置每月的大致成本。

  • 美国东部应用服务器: Hetzner CX32,每月约十五欧元
  • 欧洲西部应用服务器: Hetzner CX32,每月约十五欧元
  • PostgreSQL 主节点(美国东部): 托管实例,每月约二十欧元
  • PostgreSQL 副本(欧洲西部): 托管实例,每月约十五欧元
  • Cloudflare Pro: 每月二十美元(CDN、DNS、WAF)
  • Cloudflare 负载均衡: 每月五美元,用于健康检查和故障转移
  • Redis(复制): Upstash 免费层级覆盖了我们的用量
  • 对象存储: Cloudflare R2,当前用量下每月约五美元
  • 监控: 自托管 Uptime Kuma(免费),Grafana Cloud 免费层级

总计:每月约一百美元。对于一个自筹资金的项目来说,这并非小数目,但远低于人们通常认为的多区域部署所需的每月数千美元成本。关键在于使用 Hetzner 这样的性价比高的提供商来提供计算资源,利用免费层级进行监控和缓存,并保持架构足够简单,以至于不需要为每个组件都使用昂贵的托管服务。

经验教训与诚实的权衡

为 NovVista 运行多区域设置让我学到了一些从架构博客文章中无法学到的东西。

真正的成本是复杂性,而不是金钱。 每月账单是可以管理的。在每次部署、调试和基础设施变更时都需要考虑两个区域的认知开销才是真正的开销。每个运行手册都更长。每个事故都有更多变量。每个配置变更都必须在所有区域中一致应用。

在添加第二个应用区域之前,先使用 CDN 和故障转移 DNS。 对于 NovVista,仅 Cloudflare 的 CDN 就消除了欧洲用户的大部分延迟投诉。第二个应用区域更多是出于可用性考虑而非延迟。如果你的主要目标是性能,一个配置良好的 CDN 可能就足够了。

对于大多数应用来说,单主数据库是可行的。 行业关于多区域数据库的讨论主要集中在多主设置上,但对于绝大多数应用来说,带有只读副本的主节点提供了简单性和性能之间的正确平衡。不要过度设计数据层。

故障转移演练是不可协商的。 未经测试的故障转移不是真正的故障转移,而是一种希望。定期进行演练,记录结果,并修复出现的问题。

结论

对于独立开发者和小型团队来说,多区域架构如今比以往任何时候都更容易实现。价格合理的云服务提供商、支持服务的慷慨免费套餐以及处理全球内容分发重担的CDN相结合,意味着你每月只需大约一百美元,就能构建有意义的地域弹性。

但易于实现并不意味着每个项目都需要它。诚实地评估多区域架构是否能解决用户的实际问题,还是仅仅满足了一种架构冲动。如果决定继续,先从CDN开始,添加DNS故障转移,并尽可能保持数据层的简单,以满足你的一致性要求。你总是可以稍后增加复杂性,但要移除它就困难多了。

By

Leave a Reply

Your email address will not be published. Required fields are marked *

You missed