openresty + lua-resty-weedfs + weedfs + graphicsmagick动态生成缩略图(类似淘宝方案)

--大部分的网站都要涉及到图片缩略图的处理,比如新闻配图,电商,微信朋友圈等,贴别是电商类网站,每个商品图对应多个不同尺寸的缩略图,用于不同的页面。

网站刚开始的时候,大家为了赶工期,尽快完成开发任务,基本上都会选择比较简单的方式实现功能,直接使用web服务器的图片上传和下载的功能。而且是单机部署。但问题是,图片响应速度比较慢,而且当访问量逐渐加大,服务器由单台变为多台时,这种方式扩展性较差。

我们自己的解决方案规划了几种:

  1. 使用web server上传,后面使用openresty +lua + graphicsmagick 将生成缩略图功能独立出来,与web程序解耦。(目前在投入使用,准备换掉)
  2. 将图片的上传,管理交由ftpserver处理,后面使用openresty +lua + graphicsmagick 将生成缩略图功能独立出来,与web程序解耦。(目前在投入使用)
  3. 将图片的上传,分布式管理 交由seaweedfs管理,可提供更快的响应速度,更方便,无痛的分布式扩展节点,billion 级别的。后面使用openresty + lua-resty-weedfs + graphicsmagick 生成缩略图功能独立处理。(准备投入使用)
  4. 使用七牛、又拍云提供的云存储及数据处理服务,解决图片的处理、存储、多节点访问速度的问题,这种方式优点是方案成熟,相应的有一定费用和开发工作,另外有一些小概率的风险,比如云服务挂掉影响本站访问。(方便的解决方案,下一节阶段重点考虑)

1,2 中解决方案,比较简单,就不具体细说,下面重点配置实做一下方案3.

所用软件版本信息:

服务器环境: ubuntu 13.10

openresty: 1.7.10.2

lua-resty-weedfs: master

weedfs(seaweedfs): v0.70beta

graphicsmagick: 1.3.16

安装步骤如下:

1.安装依赖的软件包:

sudo apt-get install libreadline-dev libpcre3-dev libssl-dev perl
sudo apt-cache search libjpeg
sudo apt-cache search libpng sudo apt-get install libjpeg62 libpng12-0

2:安装openresty,现在最新版本的openresty1.7.10.2:

sudo mkdir working
cd working
sudo wget https://openresty.org/download/ngx_openresty-1.7.10.2.tar.gz
tar xzvf ngx_openresty-VERSION.tar.gz
cd ngx_openresty-VERSION/
sudo ./configure --with-luajit \
--with-http_iconv_module \
--with-http_stub_status_module --with-openssl=/usr/local/ssl/lib --with-http_ssl_module
后面两个with,如果不能满足条件,不安装也可以
sudo make
sudo make install
安装成功后,在/usr/local/openresty/

3: 安装graphicsmagic

sudo add-apt-repository ppa:dhor/myway
sudo apt-get update
sudo apt-get install graphicsmagick
gm help

4:配置,并启动openresty 也即nginx

cd ~/working
mkdir logs/ conf/
sudo vi conf/nginx.conf 输入一下内容
=======start=========== worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 8090;
location / {
default_type text/html;
content_by_lua '
ngx.say("<p>hello, world</p>")
';
}
}
} =========end==============

添加nginx 到path,方便执行

PATH=/usr/local/openresty/nginx/sbin:$PATH
export PATH nginx -p `pwd`/ -c conf/nginx.conf curl http://localhost:8090/

输出:

<p>hello, world</p>

5.安装weedfs

sudo wget https://bintray.com/artifact/download/chrislusf/seaweedfs/weed_0.70beta_linux_amd64.tar.gz
tar zxvf weed_0.70beta_linux_amd64.tar.gz

start master server

./weed master

start volume server

cd ~/working
mkdir data

weed volume -dir="../data" -max=5 -mserver="localhost:9333" -port=9080 &

weed volume -dir="../data" -max=5 -mserver="localhost:9333" -port=9081 &

write file

curl -X POST http://localhost:9333/dir/assign

output:

{"fid":"7,02a3a52531","url":"127.0.0.1:9080","publicUrl":"127.0.0.1:9080","count":1}

second:

curl -X PUT -F file=@./detail_01.jpg http://127.0.0.1:9080/7,02a3a52531

output:

{"name":"detail_01.jpg","size":176946}

read file:

 curl http://localhost:9333/dir/lookup?volumeId=7

output:

{"volumeId":"7","locations":[{"url":"127.0.0.1:9080","publicUrl":"127.0.0.1:9080"}]}

或者通过网页显示图片:

http://192.168.15.201:9080/7/02a3a52531/detail_01.jpg
http://192.168.15.201:9080/7/02a3a52531.jpg
http://192.168.15.201:9080/7,02a3a52531.jpg
http://192.168.15.201:9080/7/02a3a52531
http://192.168.15.201:9080/7,02a3a52531

6.openresty 与 weedfs结合,配置 lua_resty_weedfs

cd ~/woring
git clone https://github.com/medcl/lua-resty-weedfs.git
cd /usr/local/openresty/nginx/conf
mv nginx.conf nginx.conf.backup
mv ~/woring/lua-resty-weedfs/resty ./resty
mv ~/woring/lua-resty-weedfs/nginx.conf ./nginx.conf
mv ~/woring/lua-resty-weedfs/weedfs.lua ./weedfs.lua

创建 www-data 组和用户,创建路径/home/wwwroot/weedfs.

nginx.conf 如下:

user  www-data www-data;
worker_processes 8;
daemon on;
master_process off; error_log logs/error.log error;
#error_log logs/error.log info; pid logs/nginx.pid; env MOCKEAGAIN_VERBOSE;
env MOCKEAGAIN_WRITE_TIMEOUT_PATTERN;
env LD_PRELOAD;
env DYLD_INSERT_LIBRARIES; worker_rlimit_nofile 65535;
events {
worker_connections 65535;
} http {
include mime.types;
default_type application/octet-stream;
# default_type text/plain; log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 8m; keepalive_timeout 0; sendfile on;
tcp_nopush on;
tcp_nodelay on; fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k; ##cache##
proxy_connect_timeout 5;
proxy_read_timeout 60;
proxy_send_timeout 5;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
proxy_temp_path temp_dir;
proxy_cache_path cache levels=1:2 keys_zone=cache_one:200m inactive=1d max_size=30g;
##end## open_file_cache max=1000 inactive=20s;
open_file_cache_min_uses 5;
open_file_cache_valid 30s; gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml;
gzip_disable "MSIE [1-6]\.";
gzip_vary on; #keepalive_timeout 65;
#problematic
#lua_code_cache off;
lua_package_path "/usr/local/openresty/lualib/?.lua;;";
resolver 8.8.8.8; server {
listen 80;
server_name localhost; rewrite_log on; charset utf-8,gbk; #access_log logs/host.access.log main; #note:must end with“/”
set $weed_audio_root_url "http://127.0.0.1:9080/";
set $weed_audio_root_url "http://127.0.0.1:9081/";
set $weed_img_root_url "http://127.0.0.1:9080/";
set $weed_img_root_url "http://127.0.0.1:9081/";
set $local_img_fs_root "/home/wwwroot/weedfs/";
set $local_audio_fs_root "/home/wwwroot/weedfs/"; location / {
root /home/wwwroot/weedfs/;
index index.html index.htm;
} #sample:/_img/?size=orig&volumn=1&id=1234
location /_img/{
default_type image/jpeg;
if ($request_method = 'DELETE' ) {
return 405;
}
if ($request_method = 'PUT' ) {
return 405;
}
if ($request_method = 'POST' ) {
return 405;
}
#content_by_lua 'ngx.say("<p>process here</p>")';
content_by_lua_file conf/weedfs.lua;
expires 30d;
# access_log off;
} # location /img/orig/{
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $remote_addr;
# proxy_set_header Host $http_host;
#
# # if ($uri ~* "/img/orig/([0-9]+)/([a-z0-9]+)(\.[a-z]+)?") {
# # rewrite "/img/orig/([0-9]+)/([a-z0-9]+)(\.[a-z]+)" /img/orig/$1,$2$3 permanent;
# # break;
# # }
#
# proxy_pass http://192.168.2.100:8080/;
# expires 7d;
# break;
# } location /img/{
rewrite "/img/([0-9]+x[0-9]+s?)/([0-9]+)/([a-z0-9]+)(\.[a-z]+)?" /_img/?type=img&size=$1&volumn=$2&id=$3 last;
rewrite "/img/([0-9]+x[0-9]+s?)/([0-9]+),([a-z0-9]+)(\.[a-z]+)?" /_img/?type=img&size=$1&volumn=$2&id=$3 last;
rewrite "/img/orig/([0-9]+)[,/]([a-z0-9]+)(\.[a-z]+)?" /_img/?type=img&size=orig&volumn=$1&id=$2 last;
expires 30d;
# access_log off;
} location /_audio/{
default_type audio/mp3;
if ($request_method = 'DELETE' ) {
return 405;
}
if ($request_method = 'PUT' ) {
return 405;
}
if ($request_method = 'POST' ) {
return 405;
} content_by_lua_file conf/weedfs.lua;
expires 30d;
# access_log off;
} #if you specified audio_fs_root separately,you should change this.
#location /audios{
# default_type audio/mp3;
# root /home/wwwroot/audios;
# expires 30d;
# access_log off;
# } location /audio/{
rewrite "/audio/(mp3)/([0-9]+)/([a-z0-9]+)(\.[a-z]+)?" /_audio/?type=audio&size=$1&volumn=$2&id=$3 last;
rewrite "/audio/(mp3)/([0-9]+),([a-z0-9]+)(\.[a-z]+)?" /_audio/?type=audio&size=$1&volumn=$2&id=$3 last;
rewrite "/audio/orig/([0-9]+),([a-z0-9]+)(\.[a-z]+)?" /_audio/?type=audio&size=orig&volumn=$1&id=$2 last;
expires 30d;
# access_log off;
} # location /upload{
# if ($request_method = 'DELETE' ) {
# return 405;
# }
# if ($request_method = 'PUT' ) {
# return 405;
# }
#
# proxy_pass $weed_xxx_root_url;
# proxy_redirect default ;
# } location /favicon.ico{
root /home/wwwroot/;
# access_log off;
} error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location ~ /\.ht {
deny all;
} location /status {
stub_status on;
access_log off;
} }
}

7.重新启动nginx 运行

访问 http://192.168.15.201/img/100x100/7,02a3a52531.jpg 成功 

http://192.168.15.201/img/100x100s/7,02a3a52531.jpg
增加s后,自动适应比例生成缩略图

8、参考文档

http://soltex.iteye.com/blog/2064749

https://github.com/chrislusf/seaweedfs

http://openresty.org/

openresty + lua-resty-weedfs + weedfs + graphicsmagick动态生成缩略图(类似淘宝方案)的更多相关文章

  1. Nginx 整合 Lua 实现动态生成缩略图

    原文地址:Nginx 整合 Lua 实现动态生成缩略图 博客地址:http://www.extlight.com 一.前提 最近在开发一个项目,涉及到缩略图的功能,常见的生成缩略图的方案有以下几个: ...

  2. 如何安装nginx_lua_module模块,升级nginx,nginx-lua-fastdfs-GraphicsMagick动态生成缩略图,实现图片自动裁剪缩放

    如何安装nginx_lua_module模块,升级nginx,nginx-lua-fastdfs-GraphicsMagick动态生成缩略图,实现图片自动裁剪缩放 参考网站:nginx-lua-fas ...

  3. nginx利用image_filter动态生成缩略图

    转自:http://www.nginx.cn/2160.html "我如今是有些图片须要生成缩略图.这个如今加了image_filter这个已经实现了.但我不知道怎么样才干訪问我上传的原图& ...

  4. 动态权限<二>之淘宝、京东、网易新闻 权限申请交互设计对比分析

    移动智能设备的快速普及,给生活带来巨大的精彩,但是智能设备上用户的信息数据很多,隐私数据也非常多,各种各样的app可能通过各种方式在悄悄的收集用户数据,而用户的隐私就变得耐人寻味了.比如之前的可以无限 ...

  5. (转)php 根据url自动生成缩略图并处理高并发问题

    分享是一种精神,与技术高低无关!   图片缩略图动态生成- [代码编程] 2011-08-23 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明http://www.blogbus.c ...

  6. axure 动态面板实现图片轮播效果(淘宝)

    淘宝中经常可以看到店铺中的图片轮播效果,本经验将通过axure7.0实现 工具/原料   axure7.0 方法/步骤     下载需要轮播的图片   将图片引入至axure中,将引入的第一张图片转为 ...

  7. LUA+resty 搭建验证码服务器

    使用Lua和OpenResty搭建验证码服务器 雨客 2016-04-08 16:38:11 浏览2525 评论0 云数据库Redis版 摘要: Lua下有个Lua-GD图形库,通过简单的Lua语句就 ...

  8. openresty+lua劫持请求,有点意思

    0x01 起因 几天前学弟给我介绍他用nginx搭建的反代,代理了谷歌和维基百科. 由此我想到了一些邪恶的东西:反代既然是所有流量走我的服务器,那我是不是能够在中途做些手脚,达到一些有趣的目的. op ...

  9. openresty+lua在反向代理服务中的玩法

    openresty+lua在反向代理服务中的玩法 phith0n · 2015/06/02 10:35 0x01 起因 几天前学弟给我介绍他用nginx搭建的反代,代理了谷歌和维基百科. 由此我想到了 ...

随机推荐

  1. 为什么选择PostgreSQL而不是MySQL

    David Bolton是一名独立开发者,他使用PostgreSQL和MySQL都已有超过十年的时间.近日,他撰文阐述了选择PostgreSQL而不是MySQL的理由.他认为,MySQL之所以仍然如此 ...

  2. 调用sed命令的三种方式

    调用sed命令的三种方式 调用sed有三种方式,一种为Shell命令行方式,另外两种是将sed命令写入脚本文件,然后执行该脚本文件. 三种方式的命令格式归纳如下: 一.在Shell命令行输入命令调用s ...

  3. 【翻译】Ext JS 5:为不同设备设置不同的主题

    原文:Sencha Ext JS 5: Supporting Different Themes for Different Devices 步骤1创建一个应用程序 步骤2定义主题 步骤3编辑Appjs ...

  4. UI设计切忌墨守成规,但改变也须用数据说话

    因为我提倡一种非标准的方法,Jon Galloway在一段评论里点了我的名: 年,他们很清楚怎么去填写这些表单.如果采用其他方法,用户会感到困惑,有些人还会落荒而逃(丢掉购物车,等等).Web表单很有 ...

  5. 手机广告投放(phone advertising)唯一标识

    手机标示,为了识别用户,方面advertising. 使用设备id,相当于暴露用户隐私.慢慢已不允许使用.. (长时间跟踪用户无异于暴露用户隐私,虽然大量数据适合兴趣建模,广告个性化推荐.但复杂多样会 ...

  6. jsp自动编译机制

    总的来说,Jasper的自动检测实现的机制比较简单,依靠某后台线程不断检测JSP文件与编译后的class文件的最后修改时间是否相同,若相同则认为没有改动,但倘若不同则需要重新编译.实际上由于在Tomc ...

  7. thinkpad x260在ubuntu 14.04lts wifi驱动安装 ( ubuntu iwlwifi驱动 都可行 )

    实验室要新购笔记本x260,用于ROS调试,装上ubuntu-ros后,发现wifi不支持. 查阅大量资料,如下: http://www.ubuntu.com/certification/hardwa ...

  8. 小强的HTML5移动开发之路(8)——坦克大战游戏2

    来自:http://blog.csdn.net/cai_xingyun/article/details/48629015 在上一篇文章中我们已经画出了自己的坦克,并且可以控制自己的坦克移动,我们继续接 ...

  9. 《java入门第一季》之java语法部分小案例

    到这里举一个小例子把语法部分梳理一下,下一节开始进入java正式基础--面向对象的学习整理. 案例: /* 某个公司采用公用电话传递数据信息,数据是小于8位的整数,为了确保安全, 在传递过程中需要加密 ...

  10. Struts源码之OgnlValueStack

    public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessVa ...