Weakyon blog
http://weakyon.com/2014/11/06/nginx-image-modules-with-fastdfs.html
nginx-image模块和fastdfs module的协作
FastDFS组合nginx的httpimagefilter_module建立的图片服务器,实现动态缩略图
用fastdfs存储图片,然后用nginx的图片处理模块httpimagefilter_module处理图片,根据输入的地址中的图片大小动态生成缩略图
原图http://192.168.8.127:801/group1/ ... WAAL8RoEHXq8410.jpg
动态生成的缩略图地址
http://192.168.8.127:801/group1/ ... HXq8410,222x222.jpg
http://192.168.8.127:801/group1/ ... HXq8410,555x555.jpg
通过在图片后面加入,axb
就能生成a,b为参数的缩略图
方法:
1、首先安装好fastdfs,并可以保证上传图片和访问图片正常(不会了,参考群里“Richard老兄写的FASTDFS 安装配置指南”这个文章写的很简单明了)
2、然后下载FastDFS的fastdfs-nginx-module模块
3、编译安装nginx,编译nginx的时候,注意带上这个2个模块,一个是nginx调用fastdfs的模块,一个是nginx的图片处理模块
--add-module=/software/fastdfs-nginx-module/src --with-http_image_filter_module
4、安装好nginx后,启动nginx和fastdfs,修改nginx的配置文件nginx.conf,修改/etc/fdfs/mod_fastdfs.conf
mod_fastdfs.conf需要修改的如下:
base_path=/fastdfs
tracker_server=172.16.3.15:22122
tracker_server=172.16.3.16:22122
group_name=group1
url_have_group_name = true
store_path_count=1
store_path0=/fastdfs
response_mode=proxy
鱼大说responese_mode如果为redirect,那么手机看图片会有问题
nginx.conf需要修改的如下:
在server段插入如下配置段
location ~ /group[0-9]/M[0-1][0-9]/.*,([0-9]+)x([0-9]+)\.(jpg|png|gif)$ {
alias /fastdfs/data;
ngx_fastdfs_module;
set $img_width2 $1;
set $img_height2 $2;
rewrite ^(.*),[0-9]+x[0-9]+\.(jpg|png|gif)$ $1.$2 break;
image_filter resize $img_width2 $img_height2;
}
location ~ /group[0-9]/M[0-1][0-9]/(.*){
alias /fastdfs/data;
ngx_fastdfs_module;
}
配置就是这么多
... HXq8410.jpg是group1的图片
... HXq8411.jpg是group2的图片
http://192.168.8.127:801/group1/ ... HXq8410.jpg
http://192.168.8.127:801/group2/ ... HXq8411.jpg
http://192.168.8.127:801/group1/ ... HXq8410,222x222.jpg
http://192.168.8.127:801/group2/ ... HXq8411,222x222.jpg
都应该能访问的到
然而http://192.168.8.127:801/group2/ ... HXq8411,222x222.jpg,这个跨组调用,经常会返回HTTP/1.1 415 Unsupported Media Type
经过初步的诊断,由于nginx的流式处理,fdfsmodule有时候在尚未完全下载到图片的时候,image module就开始运作了,这时image module的缓冲区是0字节数据,因此直接对图片格式判断不支持,从而导致出错。对image module简单的修改,使得fdfsmodule和image_module可以协作不报错。
修改了image模块的一部分来使得两模块协作正常
在贴代码之前,首先稍微对Nginx的I/O机制做一定的介绍,Nginx允许handler一次产生一组输出,可以产生多次,Nginx将输出组织成一个单链表结构,链表中的每个节点是一个chaint,定义在core/ngxbuf.h:
struct ngx_chain_s {
ngx_buf_t *buf;
ngx_chain_t *next;
};
其中ngxchaint是ngxchains的别名,buf为某个数据缓冲区的指针,next指向下一个链表节点,可以看到这是一个非常简单的链表。ngxbuft的定义比较长而且很复杂,这里就不贴出来了,请自行参考core/ngxbuf.h。ngxbutt中比较重要的是pos和last,分别表示要缓冲区数据在内存中的起始地址和结尾地址,这里我们将配置中字符串传进去,lastbuf是一个位域,设为1表示此缓冲区是链表中最后一个元素,为0表示后面还有元素。因为我们只有一组数据,所以缓冲区链表中只有一个节点,如果需要输入多组数据可将各组数据放入不同缓冲区后插入到链表。下图展示了Nginx缓冲链表的结构:
缓冲数据准备好后,用ngxhttpoutputfilter就可以输出了(会送到filter进行各种过滤处理)。ngxhttpoutputfilter的第一个参数为ngxhttprequestt结构,第二个为输出链表的起始地址&out。ngxhttpoutput_filter会遍历链表,输出所有数据。
下面是修改的代码
if (ctx->type == NGX_HTTP_IMAGE_NONE) {
if (conf->filter == NGX_HTTP_IMAGE_SIZE) {
out.buf = ngx_http_image_json(r, NULL);
if (out.buf) {
out.next = NULL;
ctx->phase = NGX_HTTP_IMAGE_DONE;
return ngx_http_image_send(r, ctx, &out);
}
}
if(in->buf->last == in->buf->pos)
return NGX_OK;
return ngx_http_filter_finalize_request(r,
&ngx_http_image_filter_module,
NGX_HTTP_UNSUPPORTED_MEDIA_TYPE);
}
插入的代码只有一句
if(in->buf->last == in->buf->pos)
return NGX_OK;
如果last和pos地址相同,说明图片尚未完整接收到,那么返回NGX_OK来跳过下面的步骤,等待下次流式处理。
用http_load对缩略图模块进行压测,全部是200的返回值,TPS并不高,瓶颈在nginx服务器的CPU上
如果比较懒,可以直接用https://github.com/tedcy/fastdfs_build这个我的开源fastdfs部署脚本进行部署
解压后./build -n trackerip1,trackerip2 -g group_name即可
如./build -n 192.168.1.1,192.168.1.2 -g 1
参考资料:
解剖Nginx·模块开发篇(1)跑起你的 Hello World 模块!