又拍云存储CDN技术探秘
导语:又拍云存储是一个提供文件快速存储及通过CDN系统快速分发至全国各地访问的综合型服务商,目前主要提供图片和音频文件为主的静态小文件服务。
文| 黄慧攀(UPYUN CTO)
又拍云存储是一个提供文件快速存储及通过CDN系统快速分发至全国各地访问的综合型服务商,目前主要提供图片和音频文件为主的静态小文件服务。海量小文件存储一直是业界难题,而我们数据中心的存储系统就是一个大型分布式Key/Value数据库,可很好解决小文件的存储问题(业界也有不少开源的分布式存储系统可使用,本文不再详述)。但对于小文件访问依然无法取得很好的性能,尤其是面对海量访问的情况,访问压力呈几何级数增大,对此我们有必要在此基础上加入CDN服务,以降低海量访问对数据中心造成的压力(以我们监控数据分析得到的结果:使用CDN服务可降低98%的压力)。
考虑到传统CDN系统架构是面向多种类型客户服务,如下载站或视频站点,这些都是大文件,而还有一部分图片或音乐站点则是小文件为主,传统架构只能在此取得一个平衡点,尽量对多种类型进行优化。但又拍云存储目前以小文件为主,所以我们的CDN系统架构要以小文件优化为主。同时面对客户的需求多样化,我们还在传统CDN服务基础上加入一些定制功能,比如图片缩略图、图片水印和音频转码这些附加功能。因此我们自主研发了UpCDN系统,接下来大家可以对此进行深入了解。
业务场景:
l 数万个网站客户
l 超过百亿个小文件,2PB的源数据,并且这个数字仍以每天数TB的规模在增长
l 每秒提供数十万次访问请求
讨论:
如使用传统的CDN架构来提供服务,会面临这些问题:
1. 小文件过多,读取性能差
2. 服务的网站数量大,难以提供完善的防盗链服务
3. 客户需求复杂:
a) 流量统计
b) 日志报表
c) 日志下载
d) 图片缩略图
e) 图片水印
f) 音频转码
g) 等等…
要解决小文件读取性能问题,可使用SSD固态硬盘解决,但考虑到SSD固态硬盘成本高昂,并不适合大面积使用,而CDN缓存则是要尽可能缓存更多的文件在本地节点,才可充分降低对存储中心的访问压力。那么SSD固态硬盘和SAS普通硬盘混合使用是最合适的,但Squid只支持根据存储对象大小来分配多种存储介质和调度,为此需要开发一个缓存调度系统。
对于防盗链策略,一般是直接在Nginx配置文件上加入。但如果写入大量的防盗链规则,会使得Nginx的配置文件非常庞大(这不反人类了嘛),日后的管理和维护都会是问题。那唯有在Nginx基础上加入动态防盗链功能,才能很好的解决这个问题。并且可降低运维人员的工作。
流量统计,面对40多个机房200多台服务器,要做到即时统计会非常困难。整个系统每秒几十万个请求,要将这些信息一一发送到数据中心做汇总统计,显然不现实。如果要做到即时统计的能力,只能在前端节点上进行数据压缩处理(这里指数据的汇总,并不是gzip类文本压缩),再传到数据中心,方可实现。
为此我们的CDN系统将会包括:防盗链、流量统计、缓存调度和防攻击等多个业务功能。考虑到前端CDN节点的访问请求量非常大,每秒数十万个请求,平台每台服务器要接受几千次访问,业务处理能力必须非常高才能应付。以我们多年经验分析,使用Squid来做CDN缓存的性能最好,高访问压力下也不会有太大影响,非常适合我们的业务场景。但Squid本身软件架构很独立、扩展性差,并不适合做二次开发,如需要增加前面所说的几个业务功能会非常费劲。为此我们选择了扩展性很好,且性能高的Nginx作为反向代理服务器,架设在最前端,所有的业务功能以Nginx模块的形式加入进去。这样看来Nginx+Squid可满足目前所有需求:) 我们就以此为基础研发UpCDN系统。
UpCDN系统介绍:
整体系统分为三层架构,第一层是部署在各个地区的CDN前端节点;第二层是部署在电信和联通网络骨干的中间节点;第三层是接入电信、联通、移动和铁通线路的核心机房,云存储服务的数据中心节点。
(图1)
前端CDN节点是基于Nginx+Squid 进行搭建,主要包括防盗链、流量统计、缓存调度和防攻击等多个业务模块:
(图2)
系统设计的主要目标:
l 高吞吐和低延迟。我们的CDN系统必须能提供海量访问请求,每秒几十万个请求是常态,所以我们的系统容量是以百万请求为基础进行部署。并且每次请求的处理时间必须要快,这不仅能提升用户体验还可节省服务器硬件成本。也因此前端CDN节点上的业务系统均以Nginx模块的形式,主要使用C语言进行开发。
l 功能强大且丰富。因是云存储服务,客户需求比较多,如防盗链、流量统计、日志报表等功能是必须的。可能A客户不需要流量统计,B客户只需要日志报表功能,但也因此要面向A、B客户都提供这些功能。
l 容错可扩展。在大规模系统中,服务器宕机每天都会发生。即使系统崩溃或硬件故障不可避免,也不能影响到我们整体服务,哪怕某个机房停电,UpCDN系统也要自动容错。所以前端CDN节点一般配以5台或10台服务器为一组提供服务,使用LVS进行容灾和负载均衡,而Squid的容灾和均衡则由Nginx负责;面向CDN机房级别的容灾处理,则由数据中心的监控系统进行调度,当某个机房出现访问故障,数据中心会第一时间把该机房剔除CDN网络(因是主动式调度,剔除操作会有几十秒的TTL延迟)。
l 简单可维护。前端CDN节点的数量多,运维人员需管理数百台服务器,工作量显而易见,并且人手操作容易犯小错误,所以我们尽最大的努力把UpCDN系统构建成全自动化的管理模式。前端CDN节点的服务器就是一个个的Copy,配上IP就能接入到CDN系统上提供服务。让运维人员可以从软件系统中脱身,只需关注硬件维护即可。
访问请求处理流程:
(图3)
系统模块功能与实现:
防盗链模块
防盗链模块在Nginx启动时并没有任何防盗链策略,但会到数据中心获取一份完整的客户域名列表,但针对某个空间域名的具体防盗链策略是未获取的,而是在某个URL请求访问过来的时候触发策略更新动作(该次请求只判断是否是合法的空间域名,如果该URL的空间域名不在客户列表上是不允许被访问的),前往数据中心获取该URL对应空间域名的防盗链策略,并以自定好的数据结构存储于Nginx的共享内存中,下次访问该空间的所有URL都能检索到对应的防盗链策略。也就是说防盗链模块是以按需被动触发、主动更新的模式进行操作,本地的防盗链策略不会跟数据中心保证严格一致,通常会延迟几分钟。因防盗链模块会每间隔几分钟前往数据中心获取一份防盗链策略更新的客户列表,如检测到某个空间域名的防盗链策略有更新,将把本地共享内存中的对应记录标记为“需更新”,当该空间再次有访问请求进来的时候再主动触发一个更新操作。这样做的好处是,客户更新防盗链策略,在数据中心的操作相对减少很多,都交由前段CDN服务器各自前来更新策略,但缺点是策略更新有延时,另外要注意CDN服务器数量太多或者服务的客户数量大,那发起策略更新的请求也将加大,所以我们采用0~5分钟随机定期检查的方法,以降低对数据中心的查询压力。
截至到目前统计到的数据有:
空间域名两万多个,也就是说有两万多个防盗链策略存储在Nginx的共享内存中,存储在Nginx共享内存中防盗链策略的内存消耗大概在 50MB/万个。可见防盗链模块并没消耗太多的系统资源,就能很好的解决问题。
流量统计模块
为降低数据统计的数据量,我们采用先在前端进行初步统计一个中间结果再交予数据中心进行大汇总的模式。每个URL访问请求进入Nginx,将通过流量统计模块并把该次请求的内容大小(如:102400字节)记录到该请求对应的空间域名记录下,而不是直接就把这次请求的流量数字报到后端数据中心。在前端的流量统计模块上暂时保留5分钟的记录,每隔5分钟后进行每个空间域名的汇总统计,得到一个中间值再报入到数据中心进行全部节点的汇总统计。
这样一来,数据量从几百万条记录降低到每5分钟几百条记录,那么在数据中心的汇总统计就相对简单很多。
缓存调度模块
调度模块在Nginx共享内存中存有几百万条URL信息,这些信息是标记某个URL应该调度到SSD磁盘或者SAS磁盘。这数百万条记录主要通过Nginx内部提供的RbTree 算法进行查找,百万条记录,最多只需20步就能定位到记录。而我们在RbTree算法基础上加入了LRU和MRU算法,以实现在固定范围内对这些URL进行排序操作,当某些URL访问密度明显大于其他URL时,它将被调到SSD磁盘的Squid缓存进行读写。
虽然每个访问请求都会经过缓存调度模块的判断,但模块的判断速度非常快,不会带来任何延迟。可将热门内容(占访问总量70%以上)都被调度到SSD磁盘上读取,明显提高系统整体性能。
防攻击模块
该模块核心算法跟缓存调度模块类似,都是要对大量的URL进行排序,对访问量大的URL进行判断。如果某个URL的访问频密度超过正常阈值,系统将对此URL的所有请求进行初步屏蔽处理(该次屏蔽以302重定向的方式进行保护,如果该次请求不是浏览器发起的正常访问一般是不会识别302重定向信号,从而可屏蔽掉机器刷新类型的攻击),如情况还继续恶化,系统将禁止该URL的访问请求,每隔5分钟再次审核该URL的请求量是否恢复到正常阈值,自动判断是否可以解除禁止。
模块开发要点:
l 效率,资源占用少。主要以Nginx模块,C语言为主进行开发,而个别复杂且访问密度较低的业务功能则使用Lua语言开发,以降低开发成本。
l 简单,自动化。尽最大的努力避免人为操作的加入,最好做到零配置,一个配置可拷贝到各个节点使用。
l 少依赖。尽量在Nginx基础上完成所有工作,包括数据记录。因为少一个软件的配置,对运维人员就是少一分工作,也少一个出现故障的可能。如果一个模块要装个MySQL类的软件配套才能工作,是不可接受的。装了MySQL,可能会因MySQL查询压力的问题要装个Redis或memcached中间缓存软件,并且MySQL还有软件崩溃或网络不通等意外,为此再做两台服务器进行热备?看上去只是多装一个软件,但为了配套,也许还有其他的软件也得加进来,所以万不得以就不能有过多依赖。
与传统CDN系统的区别:
UpCDN | 传统CDN | |
节点系统环境 | Linux+Nginx+自主研发多个业务模块+Squid | Linux+(Nginx|Apache)+(Squid|Varnish) |
节点硬件配置 | 高性能服务器(SAS磁盘+SSD固态硬盘) | 高性能服务器(SAS磁盘或SATA磁盘) |
CDN功能支持: | ||
热门内容加速 | 支持(缓存调度模块) | 不支持 |
实时流量统计 | 支持(提供在线监控图) | 不支持 |
日志分析报表 | 支持(Hadoop集群处理) | 不支持 |
日志文件下载 | 支持(多节点日志合并服务) | 提供日志文件下载,但每个节点都有一个日志文件,不提供合并服务 |
防盗链 | 支持(自动更新) | 支持(配置文件,手动或半自动更新) |
自定义错误提示页 | 支持 | 不支持 |
防攻击 | 传统防火墙策略+防攻击模块 | 传统防火墙策略 |
图片缩略图 | 支持(有图片处理服务器集群) | 不支持 |
音频转码 | 支持(有音频处理服务器集群) | 不支持 |
多线路的内容服务器 (指客户源服务器) | 支持(自动切换,可容灾) | 部分支持 |
实践总结:
虽然UpCDN系统的业务功能较传统的CDN系统复杂,多了好几个模块运算,但对访问请求的处理耗时并没产生影响,可忽略。并且使用到SSD固态硬盘来提供热门内容的缓存服务,整体的服务处理能力还大大增加(前后对比,使用SSD固态硬盘后单台服务器的服务能力提升了1倍多)。
整体系统分为三层,可充分降低数据中心的访问压力。我们还在第二层中间结点部署有图片处理服务器和音频处理服务器的集群,把一部分数据中心工作向外扩,进一步减轻压力并能提高整体系统性能。
UpCDN系统上线正式投入服务到今已稳定运行3年多,较我们早年部署的CDN系统有了很大提升。未来我们还将继续完善UpCDN系统,在自动化管理方面加大研发力度(这将涉及到服务器硬件、系统环境和软件部署等方面,需制定软硬件标准和完善的节点监控系统),以实现一个智能化、自动维护的CDN系统。
作者简介:
黄慧攀,网名oneoo,UPYUN CTO,,也是 aLiLuaWeb 开发框架的作者。2010年加入又拍网并开始又拍云存储相关技术研发工作。擅长Linux 服务端研发、Lua Web 服务端、分布式系统、CDN 加速系统。