淘宝的图片访问,有98%的流量都走了CDN缓存。只有2%会回源到源站,节省了大量的服务器资源。
但是,如果在用户访问高峰期,图片内容大批量发生变化,大量用户的访问就会穿透cdn,对源站造成巨大的压力。
结合阿里淘系2020年双11的淘宝实践,给大家分享下在图片业务里,我们是如何使用CDN以及如何解决挑战和困难。
CDN工作原理
内容分发网络(Content Delivery Network,简称CDN)是 建立并覆盖在 承载网之上,由分布在 不同区域的 边缘节点服务器群组成的分布式网络。【粉丝网】
CDN应用广泛,支持多种行业、多种场景内容加速,例如
:图片小文件、大文件下载、视音频点播、直播流媒体、全站加速、安全加速。借用阿里云官网的例子,来简单介绍CDN的工作原理。
假设通过CDN加速的域名为www.a.com
,接入CDN网络,开始使用加速服务后,当终端用户(北京)发起HTTP请求时,处理流程如下:
- 当终端用户(北京)向
www.a.com
下的指定资源发起请求时,首先向LDNS(本地DNS)发起域名解析请求。 - LDNS检查缓存中是否有
www.a.com
的IP地址记录。如果有,则直接返回给终端用户;如果没有,则向授权DNS查询。 - 当授权DNS解析
www.a.com
时,返回域名CNAMEwww.a.tbcdn.com
对应IP地址。 - 域名解析请求发送至阿里云DNS调度系统,并为请求分配最佳节点IP地址。
- LDNS获取DNS返回的解析IP地址。
- 用户获取解析IP地址。
- 用户向获取的IP地址发起对该资源的访问请求。
- 如果该IP地址对应的节点已缓存该资源,则会将数据直接返回给用户,例如,图中步骤7和8,请求结束。
- 如 果该IP地 址对应的 节点未缓存该资源,则节点向 源站发起对该资源的 请求。获取资源后,结合用户自定义配置的 缓存策略,将资源缓存至节点,例如 ,图中的 北京节点,并返回给用户,请求结束。
从这个例子可以了解到:
(1)CDN的加速资源是跟域名绑定的。 (2)通过 域名访问资源,首先是 通过 DNS分查找离用户最 近的 CDN节点(边缘服务器)的 IP(3)通过 IP访问实际资源时,如 果CDN上并没有 缓存资源,则会到源站请求资源,并缓存到CDN节点上,这样,用户下一次访问时,该CDN节点就会有对应资源的缓存了。
淘宝鹿班图片业务背景
商品的主图贯穿整个导购和
交易链路,相比文字,图片更能吸引眼球,主图对消费者 的购物决策有 很大的影响。主图上表达的 内容各式各样,但其中一定少不了的 一定是价格的 表达。长期以来,主图上的价格表达都是
商家自己维护,商品价格发生变化后,手动去换图。这样做,会带来3个问题: (1)价格的 准确性:商家手动填写的 图片价格,跟实际的 购买价可能不一致,造成不好的 用户体验。 (2)价格更新的 及时性:有 时候,由于 优惠券/品类券的 生效失效,会导致商品的 价格变化会很频繁,商家根本来不及换图。 (3)商家的 操作成本:手动修改图片的 价格,成本还是 很高的 ,需要通过 ps等 软件修改图片,重新上传,编辑商品。今年双11,我
们淘宝鹿班团队,试图通过 技术手段来解决这些问题。当商品价格发生变化后,系统自动计算新的价格,自动合成图片,然 后更新商品主图。我们知道,淘宝网有 上亿的 商品,光大促商品就有 几千万,因此,价格变化导致的图片变化频率非常高。最 高的 就是 在 双11的 0点,全部大促商品的 价格都会由日常价格变成大促价格。
这就意味着
,大促高峰期,有 上千万的 图片刚生成就会被用户访问。那这个情况会产生什么问题呢,让我 们先了 解下淘宝的 图片空间和 CDN的 架构,就清楚了。淘宝图片空间和CDN的架构
淘宝整个图片的访问链路有三级缓存(客户端本地、CDN L1、CDN L2),所有图片都持久化的存储到OSS中。真正处理图片的是img-picasso系统,它的功能比较复杂,包括从OSS读取文件,对图片尺寸进行缩放,编解码,所以机器成本比较高。
CDN的
缓存分成2级,合理的 分配L1和 L2的 比例,一方面,可以通过 一致性hash的 手段,在 同等 资源的 情况下,缓存更多内容,提升整体缓存命中率;另一方面,可以平衡计算和 IO,充分利用不同配置的 机器的 能力。用户访问图片的客户端本地 如 果有该图片的 缓存,则直接渲染图片,否则执行下一步。(4)从CDN L1回源图片,如 果L1有该图片的 缓存,则客户端渲染图片,同时缓存到本地 ,如果L1没有 缓存,则执行下一步。(5)从CDN L2回源图片,如 果L2有 该图片的 缓存,则客户端渲染图片,同时CDN L1及客户端缓存图片内容,如 果CDN L2没有缓存该图片,则执行下一步。(6)从图片空间回源图片,图片空间会从OSS拉取图片源文件,按要求进行尺寸缩放,然 后执行编解码,返回客户端能够支持的 图片内容,之后客户端就可以渲染图片,同时CDN的 L1、L2以及客户端都会缓存图片内容。
过 程如 下:(1)用户通过 手机淘宝来搜索商品或者 查看宝贝详情。(2)详情/搜索/推荐通过 调用商品中心返回商品的 图片URL。(3)频繁换图带来的技术挑战
当商品的价格发生变化时,我们会使用新的价格重新合成图片,更新商品中心中存储的图片URL。
这样会带来2个问题:(1)CDN及手机淘宝原本缓存的图片内容失效了,用户访问图片会全部回源到img-picasso。(2)由于更改了商品的字段,交易的核心应用(购物车和商品中心)的缓存也失效了,用户浏览及购物时,对商品的访问会走到db。
源站img-picasso处理图片,以及查询商品DB,都是非常消耗资源的。CDN及商品的缓存命中率降低后,对源站img-picsasso以及db会产生巨大的压力。
拿CDN缓存为例,简单计算一下,CDN平时的 命中率是 98%,假设命中率降低1个点,对源站的 压力就会增加1/3(原本承担2%的 流量,现在 需要承担3%的 流量),意味着img-picasso需要扩容1/3。如果全网一半的图片都同时变化,cdn的命中率降到50%,对img-picasso的访问量就会增加25倍,这个扩容成本肯定没法接受。
解决这2个问题,对应的
有 2个办法:(1)改图保持图片URL不变,可以避免商品链路的 缓存失效。(2)在 访问高峰到来之前,提前预热图片到CDN,可以避免CDN缓存失效对源站的压力。下面,介绍下我们具体是怎么做到这2点的。
频繁换图的应对方案
改图保持图片URL不变
图片内容发生变化时,执行下面2个操作:(1)更新OSS内容:使用新的
图片内容替换OSS中老的 图片内容(2)刷新CDN缓存:清除CDN之前缓存的 图片内容这样,用户再次访问图片时,发现CDN没有缓存,就会回源到img-picasso,从OSS拉取新的图片内容。
由于
图片URL没有 变化,就不必去更新商品中心的 图片链接,这样商品链路的 缓存可以保持不变。在 真正实施这个方案的 过 程中,遇到了 几个问题,简单跟大家分享下:OSS三地同步
淘宝的
图片空间,承载了 淘系所 有 图片的 上下行稳定性保障,为了 保障高可用,一份资源会存储到三地 OSS。图片上传时,默认只上传一地 ,利用OSS的 能力,自动同步到另外两地 。但图片内容没有变化。
是 使用URL不变方案,CDN缓存已经清除完成后,如果另外2地的 OSS还未同步完成,用户访问后,就会回源到旧的 图片内容,发现针对该问题,我
们将异步同步OSS软链的 模式,改成三地 同步建软链,三地 都返回成功后,再去清除CDN缓存,这就保证了 用户访问的 图片一定是 最 新的 内容。图片尺寸收敛
同一张商品图片会用于不同的场景坑位展现,不同的坑位对图片的尺寸有不同的要求。为此,图片空间提供了一项功能,可以方便的生成不同尺寸的缩率图。只需要访问图片时,给图片增加不同的后缀,img-picasso源站就可以按要求进行图片进行缩放。
由于
历史原因,之前对缩放的 尺寸种类没有 限制,导致CDN上的 图片后缀格式多达2400种+,TOP6格式覆盖率46%,TOP15格式覆盖率64%。这意味着 ,一张图片,在 cdn上最多可能有 2400+个不同的 url,当图片内容变化后,要把这些缓存全部清掉,才能保证所 有用户看到的 图片都是 新内容。为了解决这个问题,我们对域名格式进行了收敛。
图片空间对于q50、q30* 图片锐化参数常见有一下3种形式:s100,s150,s200
图片质量压缩参数的 规则如 下:* 图片质量参数常见有 一下8种形式:Q90、Q75、Q50、Q30、q90、q75、我
们重新将图片质量定义为高质量图片和 低质量图片,收敛格式为 q90 和 p50s150这样,就可以把2000多种格式收敛到6种主要格式,CDN清除缓存才变得可行。多副本清除CDN缓存
通过图片尺寸收敛,每张图片只需要清除6个不同的url就可以了,那能不能进一步提升刷新效率呢?
为此,阿里云CDN为我
们提供了 多副本刷新的 解决方案:每种不同后缀的 图片,作为图片的 一个副本,在 CDN的 swift层增加一层KV结构,存储url和不同副本的映射关系,清除缓存时,可以通过 该结构找到所 有 副本,实现快速清除所 有 副本。这样,每张图片,我 们只需要调用一次CDN清除缓存接口就可以了 ,极大提升了CDN缓存刷新效率。图片域名收敛
淘系的
图片域名有 300多种,主要有 下面2个原因:(1)图片完整的 链接太长,所 以存储时经常只存最 后一段,业务自己来拼域名,很多业务就自己申请了 一个图片域名来拼。(2)PC时代,浏览器对同一域名下的 并发请求数是 有 限制的 ,不同浏览器不一样,一般6个左右。为了突破该限制,一些业务就会申请多个域名,随机的拼不同的域名。
前面我们讲过,CDN的缓存是跟域名绑定的,不管是缓存命中还是缓存清除,都只能针对一个域名。
我http://picasso.alicdn.com,具体实现方式如下:
们显然不可能改一张图,就去对300个域名调用CDN刷新。于 是 我 们考虑对图片域名进行收敛,使得用户对图片的 访问都路由到同一个域名,我 们希望将所 有 的 图片访问统一收敛到(1)对于手淘和猫客客户端,图片访问都收口在图片库,我们推进图片库进行改造,符合一定规则的url,统一收敛到http://picasso.alicdn.com,实现了 域名的 一刀切。(2)对于PC浏览器端,就比较麻烦了 ,没有 统一收口的 地 方。我 们只能退而求其次,针对访问最 多的 6大域名,在 cdn上配置域名转发规则,重定向 到picasso域名。
通过这种方式,我们实现了全网99%以上的图片访问流量都路由到picasso域名,图片内容发生变化时,通过 清除picasso域名的 cdn缓存,就能保证基本所 有 的 场景都能看到新的 图片内容。
客户端及浏览器缓存
通过多副本和图片域名收敛,cdn的 缓存问题得到了解决。但在 cdn之上,用户图片访问首先是 来自客户端或者 浏览器,这里也 会有 一层缓存。
大家知道,浏览器的缓存都遵循标准的http max-age协议,指定该header后,到了时间图片就会失效,访问到新的图片。所以我们可以在源站img-picasso回源给cdn时,添加max-age协议头,值为1分钟,cdn会原封不动的透给浏览器,这样浏览器就可以实现1分钟内图片缓存失效,重新到cdn拉新的图片资源。
对于
手机淘宝客户端,我 们在 原有 的LRU缓存机制之上,另外支持标准的 http协议。这样,手机淘宝也实现了 1分钟内图片缓存失效。提前预热CDN图片
通过改图保持图片URL不变,我们解决了改图对商品链路缓存的影响。但是,图片变化时,虽然URL没有变,但我们清除了CDN缓存,导致用户访问时还是会回源到img-picasso源站,所以对图片源站的压力依然存在。
我
们发现,商品的 价格变化大部分发生在 大促节奏变化的 时刻,基于 这个特点,我 们通过 提前合成图片,提前预热到CDN,可以实现图片切换瞬间生效,同时对源站没有 压力。具体方案如下:(1)提前合成多波段图片:我
们知道大促期间商家集中换图的 时间点后,按这些时间点把图片的 展示分成多个波段,每个波段图片提前合成,并提前将图片URL写入到商品中心扩展结构中。(2)图片访问路由:营销系统根据配置的 大促氛围切换计划,告诉鹿班图片二方包,当前是 哪个波段,鹿班根据当前波段及场景,返回正确的 图片URL给各个场景。(3)图片渲染:各个场景拿到图片URL后,结合自身的 业务逻辑,决定是 否要展现该图片。(4)CDN图片预热:为了 避免图片集中切换时,把源站击垮,我 们会在 集中切换前把这些冷图片内容预热到CDN。(5)波段内图片变化:提前合成各个波段图片后,商家可能会临时发券/改价,导致商品价格再次变化,对于 这类换图需求,为了 避免更新商品中心的 图片URL,我 们通过 本文上一章节刷CDN缓存的方式实现。总结和展望
CDN技术广泛应用于
互联网的各个场景,如 今的 CDN服务商,都提供了 非常简单的 业务接入方式,而且 CDN的 费用每年都在 降低,这一切使得CDN的 接入和 使用成本越来越低。本文通过淘宝图片业务的例子,为大家阐述了使用CDN过程中可能遇到的问题和解决思路。
淘宝的图片业务除了
访问量大,还会面临更新频繁的 问题。图片的 频繁更新,一方面会由于 商品上的 图片url变化,导致商品缓存失效,另一方面会大幅降低CDN的 图片访问缓存命中率。针对图片url变化导致商品缓存失效的
问题,我 们通过 刷新cdn缓存,用户访问时重新回源的 方式,实现了 改图保持图片url不变,这个过程中了 ,我 们解决了 一些列的 问题,包括:OSS三地 同步更新、图片尺寸收敛、图片域名收敛、客户端及浏览器本地 缓存。针对改图降低CDN图片缓存命中率的
问题,我 们根据业务的 特点,提前合成不同波段的 图片,并预热到CDN,保障了 源站的 安全。目前,淘宝上用户看到的 图片,都是提前合成好的。未来,我 们考虑在用户访问图片时,实时合成图片。通过 这项技术,可以实时感知业务更多的 实时信息,可以根据这些信息,在 图片上合成当前用户或者 环境更匹配的 文案/元素等 内容,给用户带来更多的惊喜。