Openresty3- imagetrick

OpenResty实战 -- 简单图片处理服务器 pictrick

2017-03-03 | 阅读

imagetrick

在简单学习了 openrestylua后,便开始实战,做一个简单的项目, 为 imagetrick,项目地址

该项目主要内容为 使用 openrestygraphicmagic做一个简单的实时图片处理服务器,即客户端请求图片时附带一些作图参数,服务器对图片进行处理然后下发。

安装Graphicsmagick

Graphicsmagick是一个开源的图片处理库,支持绝大多数的图像格式,想能强大。是 Imagemagick的一个分支版本,但性能更优。

安装一大堆基础包

yum install -y gcc gcc-c++ zlib zlib-devel openssl openssl-devel pcre pcre-devel libpng libjpeg libpng-devel libjpeg-devel ghostscript libtiff libtiff-devel freetype freetype-devel readline-devel  libwebp libwebp-devel giflib giflib-devel

然后官网下载包通过make & make install进行安装。

GraphicMagick的使用

GraphicMagick是一个C/C++库,而openresty可以轻松的使用 ffi来调用GraphicMagick,而在项目中,我们使用magick的封装。用法也比较简单 :

magick = requrie "magick.gmwand"
local img = magick.load_image("some_image.png")
img:set_format(format)
img:resize(w,h, f="Lanczos2", blur=1.0)
img:set_quality(quality)

使用lua-resty-http

作图服务器需要下载原图,网络请求我们使用lua-resty-http , 基于cosocket实现了协程方式的网络请求,可以使用同步的方式来编写异步代码,网络请求操作全部是异步非阻塞的。

local http = require "resty.http"
local httpc = http.new()
local res, err = httpc:request_uri("http://example.com/helloworld", {
	method = "POST",
	body = "a=1&b=2",
	headers = {
	  ["Content-Type"] = "application/x-www-form-urlencoded",
	}
})
if not res then
	ngx.say("failed to request: ", err)
	return
end
ngx.status = res.status

for k,v in pairs(res.headers) do
  --
end
ngx.say(res.body)

以上代码看起来是同步的网络请求,实际上,全部是异步非阻塞的操作。

编译动态库

当在使用 openresty时,我们经常要扩展lua的功能,会选择通过c编译动态库,然后使用luajit中的ffi来加载动态库。所以,我们要编译一个动态库,下面是一个简单动态库的代码:

#include <string.h>
#include <stdio.h>
#include <sys/time.h>

long getmillisecond() {
    struct timeval tv;
    gettimeofday(&tv,NULL);
    long millisecond = (tv.tv_sec*1000000+tv.tv_usec)/1000;
    return millisecond;
}

然后,我们通过gcc命令编译动态库 :

gcc -o libx.so x.c -fPIC -shared

编译选项 -fPIC表示编译为位置独立的代码。 一般编译为non-PIC代码,而动态库要求使用-fPIC编译出PIC代码。两者在指令上的表现:

# non-PIC
ld r3, var1
# PIC
ld r3, var1-offset@GOT

在PIC模式下,程序运行时要先去查询函数的位置,然后将地址写到GOT表中,而后从中获取函数地址,并执行。而非PIC模式下,函数与变量的地址是在编译时固定的。 所以 -fPIC模式,表示的是编译出位置独立的代码。

-shared表示编译出动态库。

遇到问题 路径寻找

我们通过 lua_package_pathlua_package_cpath来设置Lua运行时,查找依赖的路径。默认是按照luajit的配置去寻找的,但是这时会遇到一个问题,如果设置了相对路径,每次运行会根据之前 nginx的路径来寻找依赖,会出现错误,所以,要通过${prefix}来使用nginx -p指定的路径作为路径寻找的前缀:

lua_package_path "${prefix}/lib/?.lua;;";
lua_package_cpath "${prefix}/libc/?.so;;";

但是在我们使用 ffi来加载库时, 就无法使用prefix来帮我们确定路径了。 一般情况下,ffi会从C的动态链接库查找路径中去寻找要加载的库,而在linux中,我们通过ldconfig来管理动态库路径。我们可以通过 ldconfig -v来查看当前动态库列表,并能查看到支持的搜索路径。一般来说动态库会放在/lib/usr/lib下。

所以,我们要将我们的动态库放在全局的共享路径下:

ln -s /pathto/xx.so /lib/xx.so

然后执行ldconfig命令以刷新当前动态库查找列表。

遇到问题,执行ldconfig后,库只添加到ldconfig的缓存区域,并没有添加到正常区域,即使用 ldconfig -p可以找到,但是ldconfig -v无法找到动态库。 而运行时也有不同,直接使用luajit时,可以找到动态库,但是在openresty中运行时,无法找到动态库。

遇到权限问题

nginx默认使用 nginx.conf中的用户配置,默认是使用nginx用户来读写文件。

在nginx配置中设置使用 root用户 :

user  root;

总结

简单实现了一个简单功能的图片处理服务器,功能比较弱,只是为了试用openrestydocker,之后有空可能继续优化,以提高其性能,以及在分布式架构上做一些优化。

docker地址为 :

要想试用图片服务器,只要

docker pull dockerwhat/imagetrick
docker run -d -p 端口:8059 dockerwhat/imagetrick

如果在本地的8080端口运行服务,则可以使用以下连接进行测试 :

http://localhost:8080/resource.luoxianming.cn/radians_circle.jpg?format=webp&quality=75&width=200