目的:
减少图片存储数量,节省存储空间(现 mogilefs 存储了近 8 千万张图片,其中近一半为缩略图)。
存储系统中只存储原图,缩略图和其它尺寸的图根据 url 地址中的参数自动生成。
如:原图
缩略图:
在原图 url 后面加上尺寸信息,当只有一个参数时,宽固定,高按比例调节
当有两个参数时,分别为宽,高的尺寸。
要求 :
1 ,能够快速处理
2 ,能够根据 url 中的尺寸参数进行相应处理
系统的处理流程:
Client
|
Squid
|
Nginx
|gearmam
Python
使用到的技术:
Squid nginx php gearman python
Nginx rewrite 的写法:
upstream p_w_picpath_resize { server 192.168.1.X; }
######## 在 location 中对 url 进行判断,符合规则的 url 进行重写,代理到后端去执行,因为想地址重写后地址栏中 url 不变,因此使用了 proxy_pass 。
if ($request_uri ~* "^/([a-z0-9./_]+)-([0-9]+),([0-9]+)$") { rewrite "^/([a-z0-9./_]+)-([0-9]+),([0-9]+)$" /index.php?file=$1&x=$2&y=$3 break; proxy_pass http: //p_w_picpath_resize; } if ($request_uri ~* "^/([a-z0-9./_]+)-([0-9]+)") { rewrite "^/([a-z0-9./_]+)-([0-9]+)" /index.php?file=$1&x=$2 break; proxy_pass http: //p_w_picpath_resize; }
PHP 程序功能及代码:
PHP 接收 url 的参数,通过 gearman 发送给后端 python 处理,之后把处理的结果以图片形式展示出来
代码如下:
<?php header('Content-type: p_w_picpath/jpeg'); $img_file=$_GET['file']; $url= "http://cn.gcimg.net/".$img_file; $sizex=$_GET['x']; $sizey=isset($_GET['y'])?$_GET['y']:"-1"; $data=$url.",".$sizex.",".$sizey; $client= new GearmanClient(); $client->addServer("192.168.1.x ",4730);//job 服务器地址 $p_w_picpath=$client->do('liguxk',$data); //输出图片 echo $p_w_picpath;?>
Python 图片处理脚本
#!/usr/bin/env python ''' resize p_w_picpath size from gearman write by lgq @liguxk ''' import gearman import urllib from PIL import Image from cStringIO import StringIO class CustomGearmanWorker(gearman.GearmanWorker): def on_job_execute(self, current_job): return super(CustomGearmanWorker, self).on_job_execute(current_job) def resizeimg(gearman_worker,job): img_url,size_x,size_y=job.data.split(',') size_x= int(size_x) size_y= int(size_y) sock=urllib.urlopen(img_url) old_img_data=sock.read() sock.close() old_img=Image.open(StringIO(old_img_data)) old_x,old_y=old_img.size if old_img.mode !='RGBA': img_format='JPEG' else: img_format='PNG' new_img=StringIO() if size_y == -1: imgswap=old_img.resize((size_x,(old_y*size_x)/old_x),Image.ANTIALIAS) else: imgswap=old_img.resize((size_x,size_y),Image.ANTIALIAS) imgswap.save(new_img,img_format,quality=60) return new_img.getvalue() def main(): new_worker=CustomGearmanWorker(['192.168.1.x:4730','192.168.1.x:4730']) new_worker.register_task('liguxk',resizeimg) new_worker.work() if __name__=='__main__': while [1]: main()
squid 命中率:
此系统中最前端为 squid 缓存,命中率在 80% (见下图),因此透过 squid, 需要后端调度的本身就不多,这其中需要生成的图片又不多,而 worker 可以开多个,因此可以满足在线生成的需求。
压力测试报告:
左侧的为小图存储在mogilefs中的情况,右侧为使用实时处理的测试数据。
差别大的一个重要原因是因为通过处理的图片比原来的缩略图大小小了很多
李国强
2011-12-29