图床上传系统设计分析

2018-02-05 10:29:18来源:http://mp.weixin.qq.com/s/bpdCwZbkHKmDJcHRhLsygA作者:人点击

分享
女主宣言

在本篇文章中,女主就带大家去分析一下图床系统的上传模块的设计与实现,让大家能够更清晰的了解,图床系统是如何支撑各业务每天数以千万级的图片上传的。


PS:丰富的一线技术、多元化的表现形式,尽在“ HULK一线技术杂谈 ”,点关注哦!


图床上传系统每天处理各个业务上传的数以千万的图片,是目前360线上正式使用的图床系统,提供HTTP接口和SDK,支持JPEG、GIF、PNG、WEBP、ICO、BMP等主流图片格式。今天我们就来根据图床系统的上传模块的具体执行流程,来分析一下系统是如何设计部署的。


图床上传系统的难点


图床上传目前有几百亿的图片,这么多的图片应该如何存储才能保证数据安全和快速访问?


每天有数千万的上传,峰值的时候每分钟就会有几万的图片需要上传,系统要如何快速的处理这些任务?


问题解决


数据的安全存储和快速访问,这里使用了cassandra分布式数据库。Cassandra 是一个来自 Apache 的分布式数据库,具有高度可扩展性,可用于管理大量的结构化数据。它提供了高可用性,没有单点故障。关于cassandra更多的介绍大家可以到cassandra.apache.org 进行了解。


下面,我们来看一下系统的设计架构:



首先系统将任务平均分配到VIP的其中一台RS上,然后将任务保存在本地Redis队列中,随后被gearman抓取到此任务,然后将任务分配给其它worker进程继续处理直到任务处理完毕。


以下内容如果未特别说明,redis为RS对应的本地redis。


下面,以HTTP上传接口为例,来分析具体执行流程。


PHP伪代码:(上传一个二进制图片数据和一个url地址,并判断是否是二维码)



1


用户调用接口


用户上传数据到接口,系统保存任务到redis队列中,如下图。无论是传递了单张还是多张图片,都会为此次请求任务分配一个唯一的groupid,循环分析每一个IMGSTREAM,如果是url不做处理,如果是图片二进制内容,就将内容保存到redis中,保存的key针对每一个图片都是唯一不变的。



在分析下一步之前,先了解一下下面相关词语。


ReqQueue



正在处理(需要处理)的队列类



PreReqQueue



预处理的队列类,只有ReqQueue的队列长度为0,才会将PreReqQueue加入ReqQueue队列中



Imgkey



图片加密后的名称,不包含后缀,redis和cassandra中的数据都是根据此key存入的,针对每个图片都是唯一的



Groupid



组任务。每次http接口调用或SDK调用,都会分配一个唯一的groupid



Taskid



每一个图片及其处理规则都会包含在一个taskid中



Groupid和taskid的关系



一个groupid可以包含一个taskid


一个groupid可以包含多个taskid



gm_client任务的发起者用于将任务分配给worker


Worker



处理任务的进程,系统中共有以下几种worker


req_distributor


将redis队列中的数据通过一定算法分配给GroupDistributor





GroupDistributor


将任务根据任务数据明细,分配给TaskFetch或TaskProc


TaskFetch


获取url的图片内容并保存在本地redis


TaskProc


处理rule规则,存储图片到cassandra





GroupComplete


任务结束时的处理程序


GroupCallback


如果注册了回调url,则触发这个worker进行处理




2


gearman client分发任务



在这一步中,RS会有一个req_distributer进程,用来分发ReqQueue和PreReqRueue队列任务,分发到GroupDistributor进程。只有当ReqQueue队列为空时,才会处理不需要及时处理的PreReqQueue队列,防止ReqQueue队列产生积压。


现在,我们看到了任务的两个状态阶段,req_distributor(开始任务分发),GroupDistributor(开始处理任务),除了这两个阶段,任务还有以下四个阶段TaskFetch 、TaskProc、GroupComplete GroupCallback,在第一步中,已经解释过了。当然,一个任务不一定六个状态都会经历,其中req_distributor、GroupDistributor、TaskProc、GroupComplete是必经阶段。


让我们熟悉一下,后五个阶段是如何转变的,如下图:



结合第一步的状态说明还是很好理解的。


3


TaskFetch根据url获取图片内容


如果上传的为二进制数据,则无此步,直接进入TaskProc阶段。下面来看一下它的具体执行流程。



先根据url地址获取图片,如果获取成功,就保存到RS的redis队列里面,key则是根据图片内容计算出来的唯一值(和第一步保存内容是相同的),然后分发到TaskProc。如果图片获取失败,那么会分发到GroupComplete。至此TaskFetch就结束了。


4


TaskProc处理图片规则


这一步用来处理上面的代码里RULES内容的,用来对图片做进一步的处理,像水印、裁剪、缩放、人脸识别、二维码识别等等,都是在这一步处理的,下面让我们用图片方式分析它的执行过程。如下图:



需要注意的是如果一个图片指定了多个规则,会依次按顺序进行处理,所以在指定规则时,要想一想指定的规则和顺序是否合理,否则最终的图片可能不是你想要的结果就不同了。


5


GroupComplete 组任务处理


由于一个组任务可能有多个图片任务,即多个taskid任务,在每一个taskid任务变成GroupComplete后,就需要判断组任务是否已经全部完成,如果未全部完成,标记未完成任务减一,如果组任务全部完成,标记组任务完成。


6


GroupCallback 回调用户url(非必须)


如果用户在调用接口时,传递了回调url,则在任务执行GroupComplete时标记组任务全部完成后,会分发到GroupCallback处理。通知调用者任务已经完成,以及任务的详细信息,类似于支付API里的notify_url功能。


7


补充说明


关于六个任务状态分别分配的进程数:


req_distributor是纯IO的操作,所以分配了1个进程


GroupDistributor 也是起到了任务分发操作,目前分配8个进程


TaskFetch 比较消耗时间,建议多一些,目前分配400个进程


TaskProc 也消耗一定时间,建议多一些,目前分配300个进程


GroupComplete 目前分配50个进程


GroupCallback 比较消耗时间,建议多一些,目前分配300个进程


总结

图床上传系统使用了开源软件cassandra、gearman、redis、nginx、lvs、php等,以上软件在互联网里有着广泛的用户,也证明了这些软件的稳定性是非常好的,也是保证图床上传系统能够保持持续稳定可扩展的原因之一。希望以上的知识对大家在平时学习工作中带来帮助。


扫描下方


二维码


了解更多内容



最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台