成本优化:新一代图片编码AVIF在手Q应用实践

1. 背景

面临的问题

图片瀑布流是我们手Q个性化业务最主要的表现形式,很多页面的图片资源都十分庞大。虽然之前已经做了一些优化,将除首屏模块外的所有图片进行懒加载,但是页面所需加载的资源仍然不小。

图片

由此带来的是巨大的流量成本,仅tianquan.gtimg.cn一个域名,峰值流量就超过50G,每年需要上百万的流量带宽费用。因此我们考虑将业务使用的图片改为比较新的压缩格式,在不影响用户使用体验的前提下,理论上可以极大的节约业务流量成本。

主流的压缩格式

目前比较主流的压缩格式有AVIF、WEBP、HEIF等几种。其中AVIF是一种基于AV1视频编码的新图像格式,相对于JPEG,WEBP这类图片格式来说,它的压缩率更高,画面细节更好。最关键的是,它是免费且开源的,没有任何授权费用。同时,它是由开放媒体联盟推动的一个标准,这个联盟包括了谷歌,微软,苹果等巨头,可以说是未来可期[1]

2. 压缩格式如何选择

虽然知道AVIF性能很优越,但是对于不同分辨率、不同内容的图片,压缩算法的表现会有很大的差异。因此在我们的业务场景下AVIF对比WEBP、HEIF等主流格式,在兼容性、图片质量、压缩效率压缩耗时上是否有优势,还需要进行实际测试才能确认。

兼容性

根据caniuse[2]的数据,除Safari外,Chrome、Firefox、Opera等主流浏览器均已实现对AVIF的支持。

图片

值得一提的是,iOS虽然不支持AVIF,但是在实际业务场景中,只要客户端能够自行解析AVIF,在iOS上也是可以显示的。具体参考iOS AVIF support[3]。经过实际测试后,手Q目前使用的WKWebView是不支持AVIF的,而若是使用WebAssembly等方式自行对AVIF格式进行解码,对于业务来说接入成本又过高了。

相比之下WebP兼容性更好,覆盖了几乎所有的主流浏览器;而苹果推出的HEIF则兼容性很差,甚至在Safari(iOS)也不能得到支持。两者的caniuse兼容性如下:

WEBP兼容性
HEIF兼容性

图片质量

除了兼容性,我们还需要考虑转换成新格式后的图片质量问题。因此我们取主题、名片、气泡等几种主要业务的图片各100张,作为原图和AVIF、WEBP图片(HEIF兼容性较差被排除)进行SSIM计算,以此来评估图片质量损失如何。

SSIM(Structural Similarity),结构相似性,是一种衡量两幅图像相似度的指标。该指标首先由德州大学奥斯丁分校的图像和视频工程实验室(Laboratory for Image and Video Engineering)提出。当两张图片其中一张为原图,另一张为失真后的图片时,两者的结构相似性可以看成是失真图片的品质衡量指标。

图片

计算结果如下:

图片

一般SSIM在0.95以上,就可以认为图片质量损失很低,肉眼几乎难以分辨。由上图可以看到,不管是AVIF还是WEBP,平均SSIM都在0.98左右。所以在图片质量角度,两种压缩格式都是满足我们需求的。

压缩效率

和上面类似,我们取自身业务的图片进行图片压缩效率测试,结果如下:

图片

压缩耗时

对于大尺寸的图片,很多压缩算法可能存在图片转换耗时较高的情况。但在我们的业务场景中,大部分用户走的是CDN缓存,并不需要重新转换和压缩。因此当业务访问量巨大时,图片压缩耗时几乎可以忽略。

小结

结合iOS在我们业务中所占的比例等多种因素,我们最终考虑在Android使用AVIF,在iOS上使用兼容性更好的WebP格式。

3. 功能如何落地?

腾讯云COS存储,基于数据万象产品推出了多种图片压缩功能。包括对AVIF、WEBP、HEIF等图片格式的转换和压缩。使用方法也很简单,在COS链接后加上 ?imageMogr2/format/avif 等后缀即可完成转换[4]

相比直接去批量修改素材,我们可以在CDN侧配置回源规则来添加COS图片压缩格式后缀,更轻松的实现AVIF或其他压缩格式图片的转换。

WebView场景的功能落地基本分为三步:

1)确认作为源站的COS桶,是否开启数据万象的图片压缩功能。

2)图片的CDN后缀加上COS图片压缩参数,如https://tianquan.gtimg.cn/card/item/2009152/newPreview2.jpg 

安卓可以变为:https://tianquan.gtimg.cn/card/item/2009152/newPreview2.jpg?imageMogr2/format/avif

iOS可以变为:https://tianquan.gtimg.cn/card/item/2009152/newPreview2.jpg?imageMogr2/format/webp

3)配置CDN回源规则,根据accept请求头来判断该图片请求环境是否支持该压缩格式。

accept头示例

具体逻辑如下:

如果请求后缀带有imageMogr2/format/avif,则判断accept中是否包含image/avif字段,如果没带,则直接去掉imageMogr2/format/avif后缀。webp也类似。参考CDN回源规则配置如下:

代码语言:javascript
复制
$uri ~ \?imageMogr2/format/avif
{
$accept !~ image/avif
{
    
    fwd_uri $url
    cache_key $host$uri_noavif
    
}

}
$uri ~ ?imageMogr2/format/webp
{

$accept !~ image/webp
{
    
    fwd_uri $url
    cache_key $host$uri_nowebp
    
}

}

以上方式的好处是可以使用代码按页面和图片种类来控制压缩格式灰度范围,控制风险。

降低转换成本

由于目前腾讯云数据万象图片编码都是按次收费的,avif 0.3元/千次,webp 0.1元/千次。总体产生费用和各个业务CDN回源率相关。CDN缓存的方案虽然方便,但是并不一定能带来降本的作用。因此我们需要更换一套新方案来落地:

1)使用腾讯云数据工作流-图片处理功能,一次性将cos桶中存量图片批量转换成avif和webp

2)工作流监听cos桶新增或变更情况,将新图片实时生成avif和webp。如新增或者替换/XXX/a.png,同目录下也会自动生成一个 /XXX/a.png.avif 和 /XXX/a.png.webp 两张图片

3)调整CDN规则,根据accept头回源新格式的图片

代码语言:javascript
复制
    uri ~ .*\.(jpg|jpeg|png|gif)
{

    ######mark a tip######
    $accept ~ image/avif
    {
        
        fwd_uri $url.avif
        content_type image/avif
        cache_key $host$url_avif
        
    }
    ######mark a tip######
    $accept ~ image/webp
    {
        
        fwd_uri $url.webp
        content_type image/webp
        cache_key $host$url_webp
        
    }
    
}</code></pre></div></div><p>新方案有两个好处:</p><p>1. 业务侧不需要改动代码(添加类似?imageMogr2/format/avif的url后缀),</p><figure class="">2. 每张图片只有一次转换成本,几乎可以忽略不计<div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722931428253467754.png" /></div></div></div></figure><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722931428598399758.png" /></div><div class="figure-desc">创建工作流</div></div></div></figure><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722931428799697173.png" /></div><div class="figure-desc">监听指定后缀文件的变化</div></div></div></figure><h2 id="bmgol" name="4.-%E6%95%B0%E6%8D%AE%E7%BB%9F%E8%AE%A1%E5%92%8C%E6%95%88%E6%9E%9C%E5%88%86%E6%9E%90"><strong>4. 数据统计和效果分析</strong></h2><p>虽然前面对新编码格式做了一些简单的测试。但是在会员个性化商城中,各个子商城页面上图片特征的差异是比较大的。为了证明AVIF编码对不同图片特征的压缩效果都是正向的,我们需要收集外网用户的实际资源加载大小和速度。在现代浏览器中已经内置了<strong>PerformanceResourceTiming API[5]</strong>,配置响应头<strong>Timing-Allow-Origin[6]</strong>后,可以非常灵活地统计出资源的加载情况。</p><p>我们对不同页面图片的图片平均加载时间和图片平均体积进行统计,并将结果进行上报统计:</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722931428961399509.png" /></div><div class="figure-desc">图片</div></div></div></figure><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722931429300603975.png" /></div><div class="figure-desc">图片</div></div></div></figure><p>以效果最好的名片商城为例,将AVIF(compress)和原图(common)进行对比:</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722931429807017981.png" /></div><div class="figure-desc">图片</div></div></div></figure><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722931430114044390.png" /></div><div class="figure-desc">图片体积</div></div></div></figure><p>图片平均加载时间由3755ms左右下降到了2034ms,图片平均体积由458KB下降到了95KB。</p><p>结论:经过对各个页面的数据分析,发现对高清晰度、大体积的图片压缩效果较好,对小体积图片压缩效果较差。值得一提的是,群昵称的图片由于业务原因,图片的颜色细节不需要非常丰富,因此选择了PNG-8的形式进行存储。PNG-8相比常规的PNG-24尺寸非常小,再使用AVIF效果并不明显,反而可能因为存储方式变化导致图片体积变大了。关于PNG-8的一些简单介绍见<strong>PNG-8、24、32区别介绍[7]</strong>。</p><p></p><h2 id="84nt2" name="5.-%E6%9C%80%E7%BB%88%E6%95%88%E6%9E%9C"><strong>5. 最终效果</strong></h2><p>5月9号全量压缩格式图片后,可以看到流量有一个比较明显的下降。</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:81.77%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722931430412085770.png" /></div></div></div></figure><p>周日峰值流量由23G左右下降到了14G左右,下降幅度将近<strong>40%</strong>。</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1722931430563702616.png" /></div><div class="figure-desc">图片</div></div></div></figure><p>根据我们的测算,峰值下降了40%每个月可以节省数万元CDN带宽成本,同时页面的打开速度也因为这项优化提升了约15%,是一种简单高效的降本增效利器!</p><p></p><p><strong>参考资料</strong></p><p>[1]关于下一代图片格式AVIF,你想要知道的都在这里了: <em style="font-style:italic">https://cloud.tencent.com/developer/article/1804942</em></p><p>[2]https://caniuse.com/avif</p><p>[3]https://avif.io/blog/tutorials/ios/#iosavifsupport</p><p>[4]图片压缩概述:https://cloud.tencent.com/document/product/436/49259</p><p>[5]https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceResourceTiming</p><p>[6]https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Timing-Allow-Origin</p><p>[7]PNG-8、24、32区别介绍:https://www.jianshu.com/p/31207790bad2</p>