中国卓越技术团队访谈录读者调查,2022年采访嘉宾由你决定! 了解详情
写点什么

Fastly 全球规模边缘云计算实践

  • 2021 年 12 月 01 日
  • 本文字数:4755 字

    阅读完需:约 16 分钟

Fastly 全球规模边缘云计算实践

GIPHY 提供大量的 GIF 媒体内容。事实上,每天有超过 100 亿条内容。除代表 GIF 实际下载的媒体请求外,我们还提供了公共 API 和 SDK 服务,让开发者可以在他们的产品中使用,从而使他们的用户能够访问我们庞大的库。


和很多每天都有大量流量的科技公司一样,我们面临着可扩展性的挑战。系统必须能够处理大量的请求 (在每秒 10000 个请求之内),并且响应延迟很小。最糟糕的事莫过于等待加载,特别是 GIF!


这就是边缘云平台(edge cloud platform)发挥作用的地方:边缘云平台并不是让我们的 AWS 服务器处理每个请求,而是尽可能多地缓存媒体内容和搜索结果 JSON 负载。这样做是非常有效的,因为媒体内容和 API 响应都不会频繁改变。边缘云平台服务器还将请求负载分配给不同的区域。我们使用 Fastly 驱动边缘云平台,为用户提供了数十亿条内容。

Fastly 解决方案


Fastly 提供多种功能,使我们能够大规模地交付内容。这些特性可以大致归类为:


  • 缓存分层

  • 缓存管理

  • 边缘计算

缓存分层


基本边缘云平台的设置是将内容缓存在边缘。这些服务器节点分布在全球,向在其区域内发送请求的用户提供缓存内容。如果边缘节点没有任何内容,则会向原始服务器(origin server)发送请求,以便检索内容。



这样的单层设置存在缺陷。每一个边缘节点都根据其区域的请求维护自己的缓存。所以,一个新的内容片段可能不会在任何一个边缘节点上被缓存,这可能会导致当每个边缘节点都重复相同的内容请求时,到我们的原始服务器的流量会激增。由于病毒式内容的流行程度越来越高,这种行为常会出现。

Fastly 提供名为 Origin Shield 的第二层缓存服务。现在,可以从 Origin Shield 层检索缓存中没有请求内容的边缘节点,请求只需要到达我们的原始服务器。


缓存管理


既然内容被缓存在边缘和 Origin Shield,我们需要设法管理其缓存策略。并不是所有的内容都应该保持相同的缓存时间,或者说 TTL(Time to Live,生存时间)。例如,单个 GIF 的信息不会有太大的变化,所以它的 API 响应可以在一个相当长的一段时间内被缓存。而 Trending Endpoint 的 API 响应则返回当前趋势 GIF 的持续更新列表,由于趋势的性质,它需要在一个较短的 TTL 上。

Fastly 是由 Varnish 驱动的,所以所有的配置都采用 Varnish 配置语言(VCL)代码的形式执行。边缘和 Origin Shield 都运行 VCL 代码,因此我们能够通过一些简单的 VCL 代码,基于 API 端点路径设置各种缓存 TTL:

# in vcl_fetchif (req.url ~ "^/v1/gifs/trending") { # set 5 minute ttl for trending responses set beresp.ttl = 600s; return(deliver);}
复制代码


并不总是用 VCL 代码来设置缓存 TTL。发送到 Origin 的 API 请求,可以在 Origin 的响应中对缓存控制指令进行编码。仅需设置 VCL 代码即可使其被重写。在 Origin 中,我们可以通过在 API 响应中设置缓存控制头,将这一决定传递给 Fastly 的 Origin Shield 和边缘节点。尤其是 Surrogate-Control 头,因为这个头将仅用于 Fastly 节点。所以我们可以更新上述 VCL,使 Surrogate-Control 优先于端点缓存策略,如下所示:

# in vcl_fetchif (beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {  # upstream set some cache control headers, so Fastly will use its cache TTL  return(deliver);} else {  # no cache headers, so use cache policies for endpoints  if (req.url ~ "^/v1/gifs/trending") {   # set 10 minute ttl for trending responses   set beresp.ttl = 600s;   return(deliver);  }}
复制代码


通过这样的设置,我们可以让缓存内容通过动态 TTL 策略自动失效,从而满足我们的需求,但是如果我们不希望等待缓存自然过期,也需要显式地让缓存失效。只需通过缓存键(URL)就可以让缓存失效。对于媒体来说,这很有效,但是对 API 的响应有点复杂。

例如,我们的 API 搜索端点可以为不同的查询返回相同的 GIF,但是如果我们希望使其失效,则无法知道每个可能生成 GIF 的 URL:

# same GIF can appear in the response of all of these API callshttps://api.giphy.com/v1/gifs/search?api_key=__KEY1__&q=hahahttps://api.giphy.com/v1/gifs/search?api_key=__KEY1__&q=hehehttps://api.giphy.com/v1/gifs/search?api_key=__KEY2__&q=lolhttps://api.giphy.com/v1/gifs/search?api_key=__KEY3__&q=laugh
复制代码


对于这种情况,我们利用了 Fastly 的代理键(Surrogate Key)!顾名思义,代理键能够唯一地识别缓存的内容,与缓存键的方式基本相同。与缓存键不同,每个存储结果可以有多个代理键,我们可以设置代理键。通过在每个 API 响应中显示的 GIF ID,使我们可以确定包含特定 GIF 的多个缓存内容:

# same GIF (gif_id_abc) can appear in the response of all of these API callshttps://api.giphy.com/v1/gifs/search?api_key=__KEY1__&q=haha    Assign Surrogate Key: gif_id_abchttps://api.giphy.com/v1/gifs/search?api_key=__KEY1__&q=hehe    Assign Surrogate Key: gif_id_abchttps://api.giphy.com/v1/gifs/search?api_key=__KEY2__&q=lol    Assign Surrogate Key: gif_id_abchttps://api.giphy.com/v1/gifs/search?api_key=__KEY3__&q=laugh    Assign Surrogate Key: gif_id_abc
复制代码


还可以为同一内容添加多个代理键:

https://api.giphy.com/v1/gifs/search?api_key=__KEY1__&q=haha    Assign Surrogate Key: gif_id_abc gif_id_def key_KEY1 q_hahahttps://api.giphy.com/v1/gifs/search?api_key=__KEY1__&q=hehe    Assign Surrogate Key: gif_id_abc gif_id_123 key_KEY1 q_hehehttps://api.giphy.com/v1/gifs/search?api_key=__KEY2__q=lol    Assign Surrogate Key: gif_id_abc, gif_id_321 gif_id_456 key_KEY2 q_lolhttps://api.giphy.com/v1/gifs/search?api_key=__KEY3__&q=laugh    Assign Surrogate Key: gif_id_abc key_KEY3 q_laugh
复制代码


代理键是一个强大的特性,可以让我们选择合适的缓存,非常精确而简单地使其失效。通过这种设置,我们可以在下列情况使缓存失效:

  • 使所有包含特定 GIF 的缓存 API 响应失效;

  • 使针对特定 API 键的所有缓存 API 响应无效;

  • 使查询某些单词的所有缓存 API 响应无效。

在边缘运行代码


VCL 为我们在边缘云平台的配置方面提供了大量功能。我们之前展示了配置如何为边缘和 Origin Shield 节点设置各种缓存 TTL 策略,但是我们还可以使用 VCL 设置请求信息。

我们可以用代码来重写传入的请求 URL。如果我们需要修改我们的 API 端点,那么这样做会更方便,而不用麻烦我们的消费者来更新他们的调用。

# in vcl_recvif (req.url ~ “^/some-old-endpoint”) {    # rewrite to the new endpointset req.url = regsub(req.url, “/some-old-endpoint”, “/new-and-improved-endpoint”);}
复制代码


还可以选择一定比例的传入请求来测试实验特性。利用 Fastly 的随机性库,我们可以为某些请求中添加一个特殊的头,以实现原始服务器上的新行为。

# in vcl_recvset req.http.new_feature = 0if (randombool(1,10000)) {    # .01% of the traffic gets to see the new featureset req.http.new_feature = 1;}
复制代码


它结合了 Fastly 的边缘字典,使得我们可以用最少的代码建立不同的行为。

# API keys that will have a percentage of their request use the new featuretable new_feature_access {    “__API_KEY1__”: “1”,    “__API_KEY2__”: “5”,    “__API_KEY3__”: “1000”,}sub vcl_recv {set req.http.new_feature = 0# check if request has an api key that is setup to have a percentage of its requests use the new featureif (randombool(std.atoi(table.lookup(new_feature_access, subfield(req.url.qs, "api_key", "&"), "0")),10000)) {set req.http.new_feature = 1;}return(lookup);}
复制代码


这只是触及了 VCL 实现的功能的皮毛。如果你想知道还有什么可以做的,可以在这里找到 Fastly 的文档!

技巧提示


我们使用 Fastly 的很多特性来为世界提供 GIF 动画内容。但是,当你可以使用如此多的特性时,配置边缘云平台可能会变得非常复杂,因此,下面是一些我们推荐的技巧提示可以帮助你完成这个任务。

在边缘和 Origin Shield 中执行 VCL


对于两层缓存设置,有一个需要记住的关键问题是,将在边缘和 Origin Shield 执行相同的 VCL 代码。这可能导致 VCL 代码在请求/响应的状态信息更改时出现意外的结果。

举例来说,我们之前的 VCL 代码将根据由上游缓存控制头或 VCL 代码本身指定的缓存 TTL,为 Origin Shield 和边缘节点设置缓存 TTL:

# in vcl_fetchif (beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {  # upstream set some cache control headers, so Fastly will use its cache TTL  return(deliver);} else {  # no cache headers, so use cache policies for endpoints  if (req.url ~ "^/v1/gifs/trending") {   # set 10 minute ttl for trending responses   set beresp.ttl = 600s;   return(deliver);  }}
复制代码


假设对于 Trending Endpoint,我们也设置了响应的 Cache-Control 头,这样我们就可以指示调用方将内容缓存到另一段的时间。这样做只需按以下步骤:

# in vcl_fetchif (beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {  # upstream set some cache control headers, so Fastly will use its cache TTL  return(deliver);} else {  # no cache headers, so use cache policies for endpoints  if (req.url ~ "^/v1/gifs/trending") {   # set 10 minute ttl for trending responses   set beresp.ttl = 600s;   # set 30 second ttl for callers   set beresp.http.cache-control = "max-age=30";   return(deliver);  }}
复制代码


Origin Shield 会执行这段 VCL 代码,向响应的头添加 Cache-Control 头,并将其返回到边缘。但是,在边缘处,它将看到响应中设置了 Cache-Control,并会执行 if 语句。这将导致边缘节点使用 30 秒的缓存 TTL,而不是预期的 10 分钟!

幸运的是,Fastly 提供了一种区分边缘和 Origin Shield 的方法,它在请求中设置了头(Fastly-FF):

# in vcl_fetchif (req.url ~ "^/v1/gifs/trending") {   # set 10 minute ttl for trending responses   set beresp.ttl = 600s;   return(deliver);}# in vcl_deliverif (!req.http.Fastly-FF) {   # set 30 second ttl for callers   set resp.http.cache-control = "max-age=30";}
复制代码


通过这个添加,Cache-Control 头将仅在边缘节点上设置,我们的缓存策略再次按预期运行!

调试和测试


我们刚才提到的陷阱可能难以发现和调试。VCL 代码只是运行在服务器上,并向你显示响应和响应头信息。只需将调试信息添加到自定义头信息中,并在响应中查看它们,但是这很快就会变得不方便了。

所幸的是,Fastly Fiddle 工具在执行 VCL 代码时能得到更好的信息。在这个工具中,我们可以模拟各种 VCL 代码部分,并了解 Fastly 的边缘以及 Origin Shield 服务器将如何处理 VCL 代码的信息。

以下是上述示例的 fiddle,显示双重执行 VCL 将影响缓存 TTL。

我们在左边的适当部分设置了 VCL,然后执行它,查看 Fastly 将如何处理右边的请求:



上图展示了在请求通过 edge 和 Origin Shield 节点时,关于它的生命周期的许多有用信息。实际环境中,VCL 代码可能会非常复杂,而这个工具在这种情况下非常出色。


作者简介:


Ethan Lu,API 团队技术领导。


原文链接:


https://engineering.giphy.com/how-giphy-uses-fastly-to-achieve-global-scale/

2021 年 12 月 01 日 15:24752

评论

发布
暂无评论
发现更多内容

一文搞懂一致性hash的原理和实现

万俊峰Kevin

微服务 hash Go 语言

为什么互动直播可以发展如此迅速?

anyRTC开发者

在线教育 视频直播 直播连麦 互动直播 电商直播

容器安全检查列表

greatersecurity

容器 云原生 DevSecOps

bash: docker-compose: 未找到命令

阿呆

Docker-compose

智慧能源:清洁低碳环保新能源,沙漠光伏与光热发电站 3D 可视化

一只数据鲸鱼

数据可视化 智慧能源 光伏发电 沙漠光伏

[翻译] 关于学习 InnoDB:InnoDB 核心之旅

keaper

MySQL 数据库 后端 服务端 innodb

产业区块链迎来新纪元,基础设施建设成核心命题

旺链科技

区块链 产业 基础设施建设

JVM优化过头了,直接把异常信息优化没了?

why技术

Java JVM

什么是高效,什么是好的企业文化

Ryan Zheng

手写希尔排序算法

实力程序员

编程 程序员 C语言 排序算法

基于用户角色的数据库智能监控系统应用场景分析

华为云开发者社区

数据库 架构 监控 用户 智能监控

500U等值 Ultra 在线空投

区块链小八歌

PNFile入门指南

Geek_6bf591

vim emacs vscode UltraEdit 文本编辑器

PNComp目录比较器

Geek_6bf591

vim emacs vscode UltraEdit 文本编辑器

Linux - 零拷贝

学个球

Linux zero copy

PNFile功能介绍

Geek_6bf591

vim emacs vscode UltraEdit 文本编辑器

PNEdit文本编辑器

Geek_6bf591

vim emacs vscode UltraEdit 文本编辑器

跨链DEX掀起数字资产交易革命 洗牌在即

区块链小八歌

360 政企安全集团基于 Flink 的 PB 级数据即席查询实践

Apache Flink

flink

PNTree 目录结构树

Geek_6bf591

vim emacs vscode UltraEdit 文本编辑器

比redis-rdb-tools快10倍的rdb分析工具

BUG侦探

redis bigkey rdb分析

天津大学教授站上 WICC2021 “讲坛” 将分享边缘计算新研究

融云 RongCloud

获客达人app系统开发

获客I3O6O643Z97

大数据

Go语言,你必须掌握的--高效并发模式!

微客鸟窝

Go 语言

什么是MircoPython?

华为云开发者社区

Python 编程语言 物联网 MicroPython 嵌入式应用

PNEdit 百科

Geek_6bf591

vim emacs vscode UltraEdit 文本编辑器

500U等值 Ultra 在线空投

股市老人币圈新

打造全景5G专网运营能力,差异化赋能行业生态

鲸品堂

场景

PNFile 百科

Geek_6bf591

PNFind文件搜索器

Geek_6bf591

vim emacs vscode UltraEdit 文本编辑器

DistSQL:像数据库一样使用 Apache ShardingSphere

SphereEx

撑起瞬时千亿交易额的云数据库是怎么炼成的?

撑起瞬时千亿交易额的云数据库是怎么炼成的?

Fastly 全球规模边缘云计算实践-InfoQ