使用腾讯云存储及CDN的实践经验总结

问题

问题大概出在18年的双十二期间,由于电商运营团队在做活动的时候,在几个活动页面展示了好几张特别大的图片(大概有800k-1M大小的样子), 致使用户在实际浏览过程中,体验并不是很好。而如果只是普通用户体验不好,也就罢了,偏偏那几天大BOSS关注起来了app,于是问起缘由来,一级一级问过来,问到了我这里。

我当然很明白这里面的问题所在,说白了就是由于你网站上的媒体资源加载太慢了,直接造成了用户体验差。而为什么你网站的媒体资源加载慢呢?那是因为你选择了在自有机房来托管这些媒体资源数据。而这些自有机房,在网络连接速度、稳定性等方面都与专业的云服务商没法比,这就间接导致了问题的产生。

选型

有了问题,就要有对应的策略。我于是首先负责了云存储的选型,当时面临的选择包括七牛云存储,腾讯云存储,阿里云储存这几家。当时与老大商量过,认为作为一款一多半流量来自于微信平台的app,当然还是应该选择一款腾讯旗下的云存储服务了,他对此表示赞同。但还是应该考虑价格因素,经过简单的计算,发现三家在价格上没有差多少。于是选型并不费事,直接就选用了腾讯云存储。

然而,我还需要根据我的选型,去做一个使用这些新服务的费用评估。这个费用评估报告,也会交给上级领导,最后由他们来拍板,是否使用腾讯云储存服务来作为媒体资源的提供者。

一切顺利,我的选型报告给领导看后,认为这个方案是可行的。一个预期的结果是,通过使用腾讯云存储方案,能够使app上的图片加载速度快将近10倍,这样的好事,为什么不做?

技术方案

摸着石头过河

我自己决定了技术方案,这个技术方案的核心是摸着石头过河。因为在当前的技术栈中,还从来没有使用过云存储,我们谁也不知道上云会有哪些风险,会产生多少费用,即便是有一些评估,但毕竟难以保证准确。

既然是摸着石头过河,我的第一步是先在app上做一个完全新的功能出来,这个新功能一定要用上云存储。这样做有几点好处,其一,数据是完全新的,没有任何历史数据,不用额外去做数据的迁移工作。其二,在做新功能的期间,也能够熟悉了解云存储接口和使用。

我选中了订单的评价功能的改进,来作为我使用腾讯云的第一步。由于历史的原因,以往的订单评价功能,只能给出文字评价以及好中差评,并不能带图片评价。之前,已经有业务部门的同事要求,希望能够实现带图评价。于是正好借助这个功能,练练手。事后来看,我这个思路非常好,这个功能做好后没多久,app所有的可用资源就都以腾讯云存储的数据方式展现了。

在这期间,由于后端语言使用的是python,因此直接参考腾讯云存储的python sdk文档 是很快速高效的学习方法。通过简单的测试,可以很方便地对接口进行熟悉。

技术细节

本地数据和远程数据

从一开始我就不想完全放弃本地数据,也就是说,即便是我将所有的本地数据都迁移到了云上。我还是要在本地进行一次备份。数据的存储,删除,更新等操作,一定是先在本地完成,再同步到云上。这个同步的过程,为了快速,并不是说再执行一次迁移数据的脚本,而是说,将原有的操作,在云上再重新执行一遍。而实际客户端读取资源文件时,还是直接拉取云上的资源,而无须去获取本地资源。这里要再多说两句,最初我为了以防万一,写的读取资源的方法,原理是如果云上没有这个资源,就去读取本地资源,但是经过实际测试,发现判断云上是否含有某个资源的方法(get_qcloud_object)执行效率太低了,考虑到我当时已经将所有的数据完全进行了迁移,并且保证本地所有的操作,也会同步到云上,因此我可以放心地拼接一个可用的云存储链接,来作为我的图片资源地址来使用。这样以来,整个读取速度就上去了一大截。当然这样做还有一个好处,也就是容灾,我看到前不久,阿里云的北京机房还出了乱子,导致很多app处于不可用状态。我这个方案,当然能够很好地解决这个问题,一旦腾讯云上的资源处于不可访问的状态,我也可以快速地进行部署,然后将资源读取从腾讯云切换到本地机房服务器。

说到这里,其实已经很明白了。其实我的核心方法,只有三个。一个是上传数据的,用到的sdk里面的方法是client.put_object这个方法,另外一个是删除数据,用到的sdk里面的方法是client.delete_object,还有一个则是展示资源的方法,这个方法是完全自己写的,其原理也不过是将云上的资源url拼接好。

本地bucket与远程bucket

在实现腾讯云存储的时候,有一个bucket的概念。其实按照我对于bucket的理解,就是跟他的中文解释一样,是一个篮子。这个篮子里面,什么东西都可以往里面装。在我最初的设计中,我考虑到要创建一个bucket的时候,想到了直接创建一个名叫commentbucket来存放商品评价图片。之所以这么做,也是因为我在本地也是想要创建一个commentbucket,但是后来发现不能简单地将本地bucket与远程bucket一一映射。

这主要也是从两个方面来考虑。第一是数据的迁移,数据迁移的时候,其中一个配置项就是bucket的名字,这个时候如果我将本地20几个bucket一一迁移,就会显得很麻烦,每次都要修改配置文件,也要上传好多次。所以这个时候我开始考虑将原来的bucket放到下一级去处理。这有点像是苏联的成立,原来的共和国本身也是国家,但是我让他成为苏联的加盟共和国,这样就能够方便管理。同样的道理,我这里只要对象存储上创建一个bucket,由它来作为‘苏联’。这样就能够让我的数据迁移工作更简单。

方便的还不只是数据迁移,由于在腾讯云的对象存储中,每个bucket需要单独配置。比如,跨域访问CORS设置,防盗链设置,回源设置,是否开启CDN设置等,这些操作我们不能通过API来完成,必须要通过工程师手动配置。而如果有多个bucket的话,那么配置起来就会很麻烦。

而我最后虽然建立了一个苏联,但是也只不过是多写了两行代码,将原来上传资源,删除资源,展示资源的方法又修改了一下,重新做了映射。一起都非常简单,就能够解决我的难题。

当然,我们也是需要考虑每个bucket的最大存储空间和存储资源数量,我后来调查了一下。发现我的数据量,完全可以将原来的多个bucket合并成一个,而无需担心这个问题。

迁移数据

迁移数据乍一看是个麻烦事,我开始有几点考虑。一是整个bucket的数据量,达到了几十GB。当时考虑如果在网络情况不好的情况下,一天的时间也未必能够完成数据的全部迁移。有这个担忧并不是毫无道理,我最先想到的其实是当前用迅雷下片的体验,几个G的资源都要下载几个小时,更不要说是几十GB的大量碎片文件了。但是后来发现,我本地网速还不错,上传的速度够快,至少是比我想象中要快。我的第二点考虑,虽然数据迁移速度很快,但是由于在迁移工作开展之前,并没有对哪些数据需要迁移进行分析,致使有很长一段时间,我都看着terminal窗口中在上传一些日志文件、发票文件。而这些文件,用户是很少有感知的,其实也并不是我此次工作想要解决的问题。

这个时候,就看出腾讯云这个数据迁移工具的可配置性了。

在本地迁移中,有两个设置,一个是用来设置本地数据迁移的包含目录,一个则是需要排除的目录的。

localPath=/opt/demo/var/buckets

exeludes=/opt/demo/var/buckets/log;/opt/ljmall-public--2/var/buckets/invoice

通过上面的配置,我就可以将占用大量内存空间的日志文件,发票(主要是pdf)文件排除出去,节省了云上大量的存储空间。

由于对配置文件进行了修改,也加上网络情况良好。实际上,整个数据迁移的过程不仅快速而且也很完美。并没有出现丢失数据的情况,这里需要补充一点,由于腾讯云存储数据迁移工具是支持日志记录的,因此所有已上传成功的文件信息都已经记录在日志中,这样也避免了重复上传等问题。所以,虽然我在中途修改了两次配置文件,但并不影响我最后将我需要上传的资源快速高效地上传上去。

由于在迁移数据之前,几乎所有的图片资源都是由运营人员产生的,所以我特地选择了一个运营不上班的周末来做这件事。之后,只需要在迁移数据完成之后,将原来写的上传、删除、展示资源的方法启用,之后所有的数据就能够实现同步了。当然,为了做的更好一点,也是可以每隔一段时间,定期执行迁移脚本,来保持数据的同步的。只是,从我目前的观察来看,无需定时迁移的脚本已经能够满足业务的需要了。

前端资源的处理和上云

本来我做这个功能的时候,最初其实只是想把图片等媒体资源进行迁移,这样能够确保用户在访问媒体资源的时候,不至于因为网络情况差,造成打开图片卡顿,半天出不来一张完整的图片。然而后来,我仔细想这个问题。所谓的对象存储,理论上来说,只要是静态资源文件,就都可以用上这个方案。因此,后来,我也将微商城的前端资源放到了云上。

这些前端资源是由webpack生成的一些js,css等文件,也包括由url-loader生成的一些图片资源,字体资源等。我使用到了一个开源的前端工具库来帮我自动完成build之后的上传操作,这个工具库是cos-webpack

这里的一切也很简单,不过这个工具库,让我觉得有一点不舒服的是,他只会负责将生成的文件上传到云上,但是却不会负责将云上原有的资源删除掉,这样一旦新的前端资源上传上去了,部署了新的前端代码。那么那些老旧的前端资源就失去了意义,再也不会有他们的用武之地。我并没有对这个前端工具库进行修改,直接使用了。当然,这样的设计也有好处,因为我们build新的前端资源的时机有可能与我们下一次部署服务的时机并不相同,这个时候如果说build之后,就将原有的资源删除掉,那么就会直接导致线上的某些页面,甚至所有页面处于不可访问状态。这显然不是我们希望得到的结果。

也许有一天,我会对之进行修改,做一个更好的工具,来处理前端资源。

顺便多说一句,我将前端资源单独放到了一个叫做febucket里面。这样,实际上,我整个项目完成之后,一共是有两个bucket,也能够很好地应付业务,逻辑清晰。

智能压缩

在使用COS来作为前端资源存放地的时候,还发现,如果不应用CDN的话,我没有办法做到资源的压缩。我们知道,包括js,css等资源,通过gzip压缩之后,能够节约一半以上的体积。对于chrome等浏览器来说,就意味着传输效率快了一倍以上。在没有应用COS之前,我们通过本地服务器上的nginx来实现gzip。相关原理,点这里:探索HTTP传输中gzip压缩的秘密。但是如果直接使用上传到COS上的资源链接,正常加载的时候,是不能进行智能压缩的。查看文档才知道,只有配合了CDN之后,我才能够实现智能压缩。但是仅仅启用了CDN并没有什么作用,后来我为此还专门发了工单提问,后来终于在腾讯云工程师的帮助下解决了。原来,我虽然启用了CDN,但是我没有相应地将对外展示的资源url进行修改,用户访问的其实还是对象存储北京机房里面的数据。后来,当我将url重新拼接,换成cdn的链接后,智能压缩才应用上。

CDN的设置

在使用过程中,由于没有或对CDN设置得有问题,导致CDN上的资源加载也出了问题。

需要说明一下的是,当以COS源的方式接入CDN的时候,在对象存储上的bucket是与CDN上的域名一一对应起来的。正式因为有这样的对应关系,我又要说了,我建立的那个苏联是多么的有必要。只需要一个苏联去跟美国单独建立外交关系,而无需各个加盟共和国单独去建立外交关系,省了好多事。

我最初设置了一个IP访问限频配置,当时设置的时候也没有在意。后来过了几天,发现有时候,资源的访问会出现514 错误,经过查询才发现原来是这个设置出的问题,又赶紧把这个设置放宽到了一个比较大的标准上。

另外,前面提到的fe这个bucket也出了问题,有跨域的问题,后来我把HTTP Header配置进行了设置,问题才得以解决。

当然,前面提到的智能压缩,在默认情况下也是关闭的,需要手动打开。

效果和理解

开始的时候,我虽然考虑到了要使用腾讯云的对象存储(COS)服务,也想按照大众的做法用上CDN,但是坦白讲,那个时候我对CDN还没有一个特别清晰的理解。我当然知道他是内容分发网络,能够让资源分配到各个节点,让全国各地,甚至全球各地的用户在获取资源时,都能够享受到一个比较快的速度。我有这样一个理解,但是还是很难将他与对象存储之间的关系说明白,讲透彻。

后来真正开始使用对象存储和CDN了。有那么几天,也通过腾讯云的后台,观测数据的变化,渐渐得也观察出来点门道。且听我一一道来。

我最初只用了对象存储,因此资源的访问地址就是

bucketname-appid.cos.region-code.myqcloud.com/key

如果上面的参照不好理解,可以举个例子,比如:

test-125777777.cos.ap-beijing.myqcloud.com/test.jpg

由于我访问资源的时候,已经指定了资源是在ap-beijing这个机房,因此全国各地的用户访问app进而访问到这个资源,都会从腾讯云北京机房获取这个资源。需要说明的是,我们的本地服务器的所在地也是在北京,但是由于我们本地服务器在网络延迟,响应速度方面还是与腾讯云有较大差距。从实际体验来看,只使用对象存储而不使用CDN已经对app中资源的加载速度有很大的改善了。(实际经过统计发现,有60%的流量是来自于北京,外地的流量不足一半)

之所以,我们还要使用CDN,一方面当然是希望能够越快越好,尽善尽美,这也是我作为一个开发者的追求。由于我身处北京,很难去测试外地用户在直接访问源站的时候的速度,但是我却能够通过CDN 的后台看到,全国各地,访问资源,普遍的延时在200ms以内,这对我来说,是可以接受的。另外一方面,其实从整体费用上来看,使用CDN并没有增加多少费用,没有使用CDN之前,费用的大部分来自于COS外网下行流量费,应用上CDN之后,由于用户可以访问分布在全国各地的各个节点来获取资源,因此对于COS来说,它的外网下行流量没有了。取而代之的是CDN流量,以及CDN回源流量。这里有必要再解释一下CDN回源流量,我最初还没有应用上腾讯云的时候,也不是很能理解CDN回源流量,当时在做费用评估的时候,将外网下行流量=CDN回源流量来计算。

实际上,按照我的理解,应该有这样的公式。在未使用CDN之前,

总流量 = 外网下行流量

在使用CDN之后,

总流量 = CDN流量 + CDN回源流量

当然我这里必须有一个前提,那就是COS(对象存储)的外部读取完全基于CDN。

通过上面两个公式,我们可以得出一个简单的结论,由于使用了CDN,外网下行流量没有了,由于业务的情况,总流量约等于CDN流量。

既然总流量约等于CDN流量,那么这个性价比就可以说非常高了。

后话

完成这个工作之后,被运营人员夸奖,说是自己家的app已经赶上天猫的速度了,听到这个话,还是很开心的,也不枉我这些天的努力。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348