概述
随着公司的快速发展,公司对外服务的系统在展现形式方面出现了多样化,目前包括Web端和手机端,不同的展现形式由于设备的多样性和设备对网络的依赖程度的不同,在对图片的尺寸或质量上都有不同的要求。原本为了满足不同设备的要求,在图片存储上会存储各种所需尺寸的图片,浪费了大量的磁盘空间,同时也浪费了高性能的硬件机器利用率。
同时公司对外的业务系统在数量和每个业务系统支撑的用户群方面也在快速的增长,势必会在对图片的请求上出现爆炸式的增长,这对图片系统的快速反映和高可用性提出了更高的要求,在保证公司的快速发展前提下,如何不降低用户使用系统的体验质量,如何保证7x24小时的高可靠性服务,在这个契机下,我们推出了分布式图片系统。
该系统在设计之初就充分考虑了上述问题,同时考虑到公司业务快速发展下,系统日后的可持续发展和系统的扩展性,从更全局的高度来定位这个系统的价值和目标,经过设计和论证,该系统在以下方面提供的服务和支持:
- 前端采用Nginx为web服务器,利用其高并发特性,提供对高并发访问量的支持
- 利用nginx的代理缓存特性和硬件的海量磁盘容量,为系统搭建了图片缓存模块,保证系统对已经处理过的图片资源进行再次访问时快速有效的提供响应,提高了系统的响应速度并避免了资源的重复执行,造成浪费,提高了系统利用率
- 图片数据源采用了多套方案实现,为使公司原有业务、新开发业务能快速使用分布式图片系统提供支持,减少了使用系统的复杂性
- 其中一种数据数据源采用了高性能的TFS分布式图片存储系统,利用多个数据节点,产生同一份数据的多份冗余备份,提高了数据的安全性,为遇到故障时数据的快速恢复提供了支持
- 能够应对客户端日益变化的希望获取各种图片尺寸的诉求,执行即时压缩和图片处理算法,快速处理后返回。避免原有系统为应对新增某一种新的图片尺寸,而必须将全部图片重新生成一份该尺寸,造成存储空间的浪费
- 图片处理模块能够应对不同系统对图片质量的不同需求,对要求高的可以采用较好的图片处理算法,对一般要求的可以采用一般的图片处理算法。
- 整体系统采用模块化划分,将系统分为各个部分,减少了系统的耦合性,增强了每个模块的独立性,整个系统采用分布式部署结构,防止单点结构的出现,为防止系统出现雪崩提供支持
项目的目的
a). 图片冗余存储,增强存储安全 b). 减少缩图数量,降低存储容量(60%) c). 满足日益繁多的图片尺寸格式需求
项目的意义
由图片单纯的文件存储变成一个系统平台,规则解析对于系统扩展提供灵活机制。使移动终端的图片格式需求不再受限。
系统使用到的技术
a) Nginx, Nginx proxy-store b) C c) Opencv d) ImageMagick、GraphicsMagick
系统图
系统部署图
系统模块间调用图
模块介绍
在设计之初,就按照功能对系统进行了模块化划分,目的是明确各个模块的功能边界,在每个模块内部封装实现细节,对外暴露出模块的访问接口,方便了模块间的通信和数据交换,同时各个模块的内部修改也不影响模块间的接口调用代码,最终为实现多数据源多图片处理算法提供了良好的模型支持。
前端模块-Nginx
使用nginx自定义module,接收http请求,在自定义module的handler中调用分布式图片实现。
代理缓存模块
图片服务器使用 Nginx 的 proxy_store 把主服务器的静态内容缓存到本地磁盘。 针对一张图片的一次访问结束后,其图片处理结果被缓存到处理机器的磁盘,以后针对该张图片相同目标尺寸的图片访问将不再经过图片压缩图片处理模块,直接从本地硬盘上读取返回。 从而避免CPU重复压缩图片的情况。 由于Nginx的Proxy_store的磁盘需要提前分配磁盘空间,而磁盘空间又有一定的容量限制,所以对于一定时间后的缓存图片,我们执行删除磁盘图片操作,释放缓存空间,为新近处理后的图片提供磁盘空间进行缓存,做到一个动态的流动,使磁盘容量一直维持一个流动的平衡。 当处理后的图片被磁盘缓存后,当客户端重新上传了图片源,我们会释放原本缓存的图片处理结果,下次再请求这种图片时,重新执行图片压缩,重新缓存。保证数据的一致性。
调度控制模块(parser module)
该模块作为统一接收数据和返回处理结果的协调者角色,整个流程包括: a) 接收来自外部的图片请求 b) 对图片请求进行处理 c) 处理结果执行规则匹配、验证等操作,其中会调用压缩防攻击模块 d) 如果不符合处理要求,不再向下执行处理,立刻返回 e) 如果请求符合约定,则依次向下调用图片存储模块和图片运算模块,并最终将处理结果返回给调用者。 另外,该模块负责处理各种业务逻辑错误,当请求的URL没有匹配某个rule对象下的操作数据时;当获取图片源发生错误时;当调用图片处理模块发生错误时;以及其他异常情况下时,必须向请求端返回默认图片,以保证每一个请求的流程完整性,避免造成进程崩溃,导致应用无法正常再被使用。
压缩防攻击模块
由于图片的大小是在调用时才动态生成,而图片压缩是一种很费服务器CPU资源的操作,当调用者频繁切换调用图片并随机调整图片尺寸,这种情况下因为CDN上不存在此种格式的图片缓存而被直接穿透,直接消耗尽服务器CPU资源,从而使图片压缩模块停止正常服务,进而达到攻击该系统的目的。防攻击模块在每收到一个图片压缩请求时,根据命名空间及所属项目,从图片尺寸注册中心获取该项目提供的所有图片尺寸列表,如果请求的图片格式不在该列表内则拒绝提供图片操作服务。
图片存取模块(data module)
对外提供获取原始图片源的接口,模块针对接口编程,提供针对各种情况下的图片存储实现,现已实现的图片源的模块包括: a) Tfs文件存储系统 b) 本地图片文件存储 图片存取模块的设计,提供了中间尺寸的概念,客户端对图片的尺寸是任意的,如果图片源中只存储原始图片,当请求的图片尺寸与原始图片源相差甚远时,在执行图片即时压缩时,会造成由一张很大的原图压缩成很小的小图,损失了图片的大部分质量,而且占用了较多的CPU资源,鉴于这种情况,在保存原始图片时,某种业务除了保存原图外,还会存储预定义的中间尺寸图片,在调用获取图片源接口前,根据目标图尺寸查找是否存在与之最接近的中间尺寸图,如果存在,获取中间尺寸图作为图片处理模块输入源,否则,获取原始图片作为图片处理输入源。 该功能的正确使用,对于提高CPU处理效率,减少CPU额外运算都有一定的效果。
图片运算模块(img-process module)
图片即时压缩核心模块代码,与图片存储模块类似,对外提供统一的图片处理接口,模块内部针对接口实现多种图片处理算法,可以根据不同的业务需要,使用不同的图片处理算法,完成不用的业务需求要求。目前完成的图片算法包括: a) Opencv压缩算法 b) GraphicsMagick压缩算法 c) ImageMagick压缩算法 其中每种图片压缩算法都需要支持根据图片质量参数进行不同质量的图片压缩,同时接口支持对图片打水印操作,支持多张水印操作。 可动态支持其他的图片处理算法,只需要实现约定的图片处理接口,完成特定算法下的图片缩放和图片水印操作,即可快速的切换一种新的图片处理算法。