OpenResty
简介
OpenResty 是一个nginx和它的各种三方模块的一个打包而成的软件平台。最重要的一点是它将lua/luajit打包了进来,使得我们可以使用lua脚本来进行web的开发。有了lua,我们可以借助于nginx的异步非阻塞的功能,达到使用 lua 异步并发访问后端的 MySQL, PostgreSQL, Memcached, Redis等等服务。特别是特有的 ngx.location.capture_multi 功能让人印象深刻,其可以达到极大的减少浏览器的http连接数量,并且可以异步并发的访问后台 Java/PHP/Python 等等接口。OpenResty 架构的web可以轻松超越Node.js的性能,并且对后端语言没有限制,你可以使用Java/PHP/Python等等各种语言。OpenResty(nginx+lua)可以替代node.js的前端渲染的功能。
Nginx 是俄罗斯人发明的, Lua 是巴西几个教授发明的,中国人章亦春把 LuaJIT VM 嵌入到 Nginx 中,实现了 OpenResty 这个高性能服务端解决方案。
OpenResty运行原理
Nginx 采用的是 master-worker 模型,一个 master 进程管理多个 worker 进程,基本的事件处理都是放在 woker 中,master 负责一些全局初始化,以及对 worker 的管理。在OpenResty中,每个 woker 使用一个 LuaVM,当请求被分配到 woker 时,将在这个 LuaVM 里创建一个 coroutine(协程)。协程之间数据隔离,每个协程具有独立的全局变量_G。
协程(Coroutine)
协程类似一种多线程,与多线程的区别有:
1. 协程并非os线程,所以创建、切换开销比线程相对要小。
2. 协程与线程一样有自己的栈、局部变量等,但是协程的栈是在用户进程空间模拟的,所以创建、切换开销很小。
3. 多线程程序是多个线程并发执行,也就是说在一瞬间有多个控制流在执行。而协程强调的是一种多个协程间协作的关系,只有当一个协程主动放弃执行权,另一个协程才能获得执行权,所以在某一瞬间,多个协程间只有一个在运行。
4. 由于多个协程时只有一个在运行,所以对于临界区的访问不需要加锁,而多线程的情况则必须加锁。
5. 多线程程序由于有多个控制流,所以程序的行为不可控,而多个协程的执行是由开发者定义的所以是可控的。
Nginx的每个Worker进程都是在epoll或kqueue这样的事件模型之上,封装成协程,每个请求都有一个协程进行处理。这正好与Lua内建协程的模型是一致的,所以即使ngx_lua需要执行Lua,相对C有一定的开销,但依然能保证高并发能力。
Lua
简介
Lua 是一个小巧的脚本语言。作者是巴西人。该语言的设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
特点
1: Lua脚本可以很容易的被C/C++代码调用,也可以反过来调用C/C++的函数,这使得Lua在应用程序中可以被广泛应用。不仅仅作为扩展脚本,也可以作为普通的配置文件,代替XML,Ini等文件格式,并且更容易理解和维护。
2: Lua由标准C编写而成,代码简洁优美,几乎在所有操作系统和平台上都可以编译,运行。一个完整的Lua解释器不过200k,在目前所有脚本引擎中,Lua的速度是最快的。这一切都决定了Lua是作为嵌入式脚本的最佳选择。
实验操作
安装OpenResty
1:本实验是为了与上篇博客中的实验做对比,基于上边的实验:PHP—memcache
2:关闭之前的nginx服务,因为我们要安装可以代替普通nginx的openresty
nginx -s stop
3:下载opneresty-1.13.6.1.tar.gz
tar zxf opneresty-1.13.6.1.tar.gz
cd opneresty-1.13.6.1
4:源码编译安装(三部曲)
(1):./configure --prefix=/usr/local/openresty --with-http_ssl_module --with-http_stub_status_module --user=nginx --group=nginx --with-threads --with-file-aio
(2):gmake
(3):gmake install
相关配置
1:cd /usr/local/openresty/nginx/conf/
vim nginx.conf
修改后的文件内容如下:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 65535; #
}
http {
upstream memcache {
server localhost:11211;
keepalive 512;
}
#upstream属于handler,只是他不产生自己的内容,而是通过请求后端服务器得到内容,所以才称为upstream(上游)。请求并取得响应内容的整个过
#程已经被封装到nginx内部,所以upstream模块只需要开发若干回调函数,完成构造请求和解析响应等具体的工作。
# nginx将memcache缓存前移,客户端请求到来,先查看memcache缓存
include mime.types;
default_type application/octet-stream;
#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;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.php index.html index.htm;
}
location /memc {
internal;
memc_connect_timeout 100ms;
memc_send_timeout 100ms;
memc_read_timeout 100ms;
set $memc_key $query_string;
set $memc_exptime 300;
memc_pass memcache;
}
#所有请求都通过请求这个location来操作 memcache,memc-nginx-module存取memcache是基于http method语义的,
#使用http的GET方法表示get、PUT方法表示set、这里我们将/memc设为internal表示只接受内部访问
#不接收外部http请求,这是为了安全考虑,当然如果需要通过http协议开放外部访问,可以去掉internal然后使用deny和allow指令控制权限。比较重要的是memckey这个变量,它表示以什么作为key,
#这里我们直接使用Nginx内置的query_string来作为key,$memc_exptime表示缓存失效时间,以秒记。
#这里统一设为300(5分钟),在实际应用中可以根据具体情况为不同的内容设置不同的过期时间。
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
set $key $uri$args;
srcache_fetch GET /memc $key;
srcache_store PUT /memc $key;
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
#fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
#为“~ \.php$”这个location配置了缓存,这表示所有以“.php”结尾的请求都会结果被缓存,当然这里只是示例需要,实际中一般不会这么配,而是为特定需要缓存的location配置缓存
#后面的内容不用修改
2:检测语法错误,因为是重新编译的,所以需要使用绝对路径,与之前的nginx区别开
/usr/local/openresty/nginx/sbin/nginx -t
/usr/local/openresty/nginx/sbin/nginx ##打开
3:将之前nginx默认发布目录中的.php文件复制到现在重新编译的nginx(openresty)的默认发布目录中
cd /usr/local/openresty/nginx/html/
cp /usr/local/nginx/html/example.php .
cp /usr/local/nginx/html/index.php .
测试
本次测试结果与上一篇博客最后的测试结果进行对比
1:本次实验测试:
在真机中
ab -c 10 -n 1000 http://172.25.66.1/example.php
查看处理情况,从下图可以看出,本次处理是由openresty服务所处理的
从图中可以看出,openresty服务所处理的1000次web请求,失败0个,错误0个,每秒钟处理次数为8700次
2:我们再来看看上篇博客中使用nginx服务处理同样为1000次请求的结果
可以看到nginx服务处理1000次请求,虽然同样是失败0次错误0次,但是它每秒只能处理1874次请求,所以,明显可以看出,openresty服务在web应用上的性能远远高于nginx,可以达到nginx的三四倍!!!