更新头像图片服务 - 移除代理方法

考虑到 Discourse 的 1RTT(一次往返时间)理念,我认为是时候重写头像图片服务代码了。

头像图片应与其他图片上传一样处理。在上传时调整大小、存储,并直接从文件系统/S3/CDN 提供服务。

当前的 Discourse 方法使用代理方法来提供头像图片。这种方法会产生不必要的 HTTP 往返和 IP 地址挑战。

以下是头像请求的概述:

  • 初始 Discourse HTML 被渲染。
  • 浏览器检测到头像图片,并向 Discourse 服务器请求图片。
  • Discourse 服务器充当代理,并从本地文件存储/S3/CDN 请求图片。
  • Discourse 服务器接收图片。
  • Discourse 服务器将图片发送到浏览器。

每个自定义头像都有 1 次额外的 HTTP 往返和相关的服务器处理时间。一个典型的帖子或帖子列表可能包含 30 多个自定义头像图片。在我的网站上,这会导致每天额外产生 10K 到 20K 的往返次数和相关的服务器负载,而这些是可以避免的。

此外,头像图片是从服务器直接调用的。要实现任何 CDN 级别的保护,需要将 IP 地址列入白名单。这需要将网关 IP 地址列入白名单,而不是服务器 IP 地址。托管公司会定期更改以平衡网络流量。我的网关 IP 地址会发生变化/演变。软件不应依赖于更新 IP 地址来使基本的头像图片正常工作。这是基于支持中的以下事件:头像代理和 CDN 热链接保护

从性能和简洁性的角度来看,能否让头像图片直接从 Discourse 指定的文件存储中提供服务?

5 个赞

这是应用程序中一个非常复杂的部分,@LotusJeff

为了解决它的一些不足之处,我们最近开发了一种方法来减少我们托管中的那些往返次数,但我认为我们从未在此处记录过。@david,是否有任何公开文档?

4 个赞

是的,我们有这个 GlobalSetting,您可以通过设置环境变量 DISCOURSE_REDIRECT_AVATAR_REQUESTS=true 来启用它。

然后,头像请求将通过 302 重定向到文件存储,而不是代理。

它本身……并不是一个好主意。这意味着浏览器每次获取头像都需要进行两次完整的 HTTP 往返。所以,虽然它可能解决了您的“防盗链”问题……但我不会建议您启用它。它会让您的用户体验变得更糟。

我们在 discourse.org 托管上使用了该设置。但我们通过运行在 Cloudfront CDN 上的 Lambda 函数对其进行了补充。它会检测到 302 并自行执行代理。本质上:我们将代理从我们的应用程序服务器转移到了 CDN。

至于“能否更改头像以直接链接到资源”这个更普遍的问题。这很棘手,因为头像 URL 会被烘焙到所有历史帖子中(例如,引用)。动态的 /user-avatar/ URL 使我们能够在用户更改头像时保持这些 URL 的工作。恐怕我们没有计划更改该系统。

如果我们能找到一种简单、低风险的方法来使现有的代理适用于您的用例(例如,添加一个 GlobalSetting,在任何头像代理请求中插入特定的 HTTP 标头),那么我们可以考虑接受一个 PR 来进行更改。

3 个赞

我上面提到的选项都在我目前的环境下不可行或不被偏好。我很想帮忙解决这个应用程序中复杂的部分,但我对这套技术堆栈还非常新。

我现在能提供的唯一帮助是利用我之前的 BA 和 Dev 管理技能。所以,本着觉得自己在帮忙的心情,这里是我的一些想法。

当我面对任何技术难题时,我首先会考虑可能会让解决方案变得更困难的假设。

一个假设是将更新后的头像图片保存为一个新的文件名。这个人只有一个头像。我们不保存头像的文件名记录。我建议当用户更新头像图片时,用与现有头像相同的文件名保存。这基本就是 /user-avatar/ 链接正在做的事情。与其采用变通方案,不如在创建/更新头像时执行这个逻辑。这可以解决历史帖子未来在烘焙帖子中的头像问题。

这会是一个大规模的变革吗?不,这个变革可以在几个月内逐步实施,优化网站性能。我们的开发团队通常会为每段代码维护一份“ opportunistic code list”,想在合适时机进行改进,但不会把所有改动都集中在一起。当代码因为其他原因被打开进行开发时,开发者也会顺便做一些 opportunistic 改动。这减少了测试和出错的频率,也降低了代码反复打开和修改的次数。

我会把这个项目分为以下几个阶段:

  1. 更新头像图片保存逻辑,用现有文件名覆盖任何头像的更新。
  2. 用一个标准函数取代所有头像图片的使用,该函数利用 discourse 的首选文件存储/交付系统。这些改动可以在几个月内逐步推进,慢慢迁移到新的头像展示逻辑。
  3. 当前两个阶段完成后,为社区提供步骤和代码片段,用于更换和重建历史头像图片到他们偏好的文件系统中的烘焙 HTML。这取决于每个 discourse 站点所有者的选择执行(这段代码指令和片段也可以用来做原始 HTML 变更)。

我相信你们已经考虑过这些。我也知道,修复旧代码通常不在优先事项之列。

如果我能在这个工作中提供任何帮助,请告诉我。

附言:我感谢你提供全局标题设置的 PR。让我做一些额外的调研,再跟你确认具体需求。感谢你的帮助。

不幸的是,如果文件是可变的,我们将无法再在 CDN 和最终用户浏览器中启用资产的无限缓存。

有一些策略可以使类似的操作在不太影响性能的情况下运行……例如,“stale-while-revalidate”指令。但这会带来其自身的成本和用户体验方面的影响。

1 个赞