OpenResty 应用总结
技术部 - kim
讲什么?
• Lua 介绍
• Openresty 介绍
• 重构 Infov 的过程分享
什么是 Lua ?• 轻量级脚本语言
• 最小、最快、最简单
• 嵌入式
Lua 的特性• Functional 函数式
• Table 数组、哈希表、集合、对象
• Closure 闭包
• Coroutine 协程
著名的 Lua 项目
• 魔兽世界、愤怒的小鸟、 Photoshop 、仙剑奇侠传五、淘宝内部
• 56.com (未来)
什么是 OpenResty ?
• 最快的 Web 应用开发框架
• OpenResty (也称为 ngx_openresty )是一个全功能的 Web 应用服务器,它打包了标准的 Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。由章亦春于 2011 年底发表。
• OpenResty 通过汇聚各种设计精良的 Nginx 模块,从而将 Nginx 有效的变成一个强大的 Web 应用服务器,这样, Web 开发人员可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K+ 并发连接响应的超高性能 Web 应用系统。
• OpenResty 的目标是让你的 Web 服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL , PostgreSQL , Memcached 以及 Redis 等都进行一致的高性能响应。
性能对比• PHP-Fpm :速度慢、吞吐量低、短连接
• OpenResty :执行快、大吞吐量、连接池
• 春哥做的 benchmark :https://github.com/agentzh/mysql-driver-benchmark
安装• 下载解压:
wget http://openresty.org/download/ngx_openresty-1.4.3.9.tar.gztar -xzf ngx_openresty-1.4.3.9.tar.gz./configure --help
• 安装 mysql 连接开发包:yum install libdrizzle-devel
• 安装:./configure --prefix=/home/openresty/ --with-http_iconv_module --with-http_postgres_module --with-http_drizzle_module --with-luajit --with-pcre=/home/pcre-8.33gmake && gmake install
• 编辑 conf 配置vi /home/openresty/nginx/conf/nginx.conf
Hello world - 1
location /helloworld { echo "hello world!";}
Hello world - 2
location = /helloworld { content_by_lua ' ngx.say("hello world!") ';}
Hello world - 3
location = /helloworld { content_by_lua_file 'hello_world.lua';}
--hello_world.luangx.say("hello world!")ngx.flush(true)
更复杂例子# http://localhost/test?name=kim&class=Alocation /test { echo "uri = $uri"; echo "request_uri = $request_uri"; set_unescape_uri $name $arg_name; set_unescape_uri $class $arg_class; echo "name: $name"; echo "class: $class";}
无阻塞 IO
location /nonblocking { content_by_lua ' local res = ngx.location.capture("/query") if res.status == 200 then ngx.print(res.body) end';}
并发子请求
location = /nonblock-multi { content_by_lua ' local res1, res2, res3 = ngx.location.capture_multi{ {"/memc"}, {"/mysql"}, {"/postgres"} } ngx.say(res1.body, res2.body, res3.body) ';}
重构 info.v.56.com
为什么?
• 前端核心接口
• PHP 性能瓶颈
• 缓存和数据库压力
开发
• 公共模块: /lib
• 实例代码: /lib/http.lua
一般 debug 方法• 直接抛出错误: error(“ 抛出个 error !” )
• assert(io.read("*number"), "invalid input")
• Lua 提供了错误处理函数 pcall:r, msg = pcall(foo)
• 还可以用 xpcall
以上,我们一般不用。。。
实际 debug 方法
• tailf /home/openresty/nginx/logs/error.log
具体配置• 新网段 + 3台新机器
• 高可用性: lvs + keepalive
• 高可用 Cache : twemproxy + kt(12 个 )
• 高性能: openresty
• 实时性:缓存耦合(人气、评论),缓存更新(直连 + httpsqs )
切换原则
• 完全保留原 PHP 的所有读写功能,即线上功能不受影响
Nginx 配置技巧
• ~ 为区分大小写的匹配。
• ~* 不区分大小写的匹配。
• !~ 和 !~* 意为“不匹配的”。
多重 if 判断• # 仅当 uri 匹配 /?ids=xxxx ,即只读时才跳转至 lua :
set $flag 0;if ($arg_ids ~* "(\w)+") { set $flag "${flag}1"; }if ($request_uri !~ "\.php") { set $flag "${flag}2"; }if ($arg_dy !~ "c") { set $flag "${flag}3"; }if ($flag = "0123") { content_by_lua_file 'vinfo.lua';}fastcgi_pass 10.11.80.159:9000;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;fastcgi_index index.php;include fastcgi_params;expires off;
Infov当前的 conflocation ~ \.php { fastcgi_pass unix:/home/php/php-fastcgi.sock; fastcgi_index index.php; include fastcgi_params; expires off;}location / { if ($request_uri ~* "luzhi") { rewrite ^/(.*)$ /index.php?$query_string last; } content_by_lua_file '/diska/htdocs/openresty/vinfo.lua';}location /api { content_by_lua_file '/diska/htdocs/openresty/vapi.lua';}
切换过程
• 对每个应用,通过改 hosts 来灰度切换,有问题立刻发现立刻修复
• 播放页和 vxml 最后切换
遇到的问题
Json输出问题• PHP json_encode :会把 utf-8 强制 escape
成 unicode ,除非是新版 php5.4 以上,可通过指定 JSON_UNESCAPED_UNICODE 参数来禁掉。
• Lua cjson :默认并不会对 utf-8 做 escape 处理,输出的就是 utf-8
Table类型
lua 的 table 数据结构:typedef union TKey { struct { TValuefields; struct Node *next; /* for chaining */ } nk; TValue tvk;} TKey;
typedef struct Node { TValue i_val; TKey i_key;} Node;
typedef struct Table { CommonHeader; lu_byte flags; // 元表标记 lu_byte lsizenode; /* log2 of size of `node' array */ // 哈希部分大小 struct Table *metatable; // 元表 TValue *array; /* array part */ // 数组部分 Node *node; // 哈希部分 Node *lastfree; /* any free position is before this position */ // 第一个空闲位置指针 GCObject *gclist; int sizearray; /* size of `array' array */ // 数组部分大小} Table;
• 数组部分:速度极快,内存比哈希省一半
• Hash 部分:链状发散表,本身即无序(比如用 PHP 接收到来自 Lua 的输出的时候,不能简单地“认为”它是有序的!)
文件 vs 模块
• 为什么要把配置文件写成模块 config.lua ?
测试环境问题
• 测试环境和正式环境最好还是分开,特别是不要在一个 server 配置里面
dns 解析问题• 可以通过安装和配置 nginx 本地 dns 服务
来添加 resolver ,从而使 sock 能通过 Nginx core‘s dynamic resolver 来解析域名。
• 但是目前实际中还是直接使用 ip 来解析,未来可以对 hosts 进行单独解析,这样就能使用域名了。
Bug问题
• Error 级别的都是要尽量修复的
• Emerg 级别的是必须修复的
• 举例 gsub 引发的血案。。。
入口不能太“窄”
• vi /etc/sysctl.conf• net.netfilter.nf_conntrack_max = 655360• net.netfilter.nf_conntrack_tcp_timeout_establ
ished = 180
Timeout 不能太短
• 无论是连接数据库、缓存还是Webservice ,超时时间太短反而不能充分发挥 OpenResty 的优势
现状与展望
价值• 1. 代码量
• 2. 开发效率
• 3. 性能提升
站内应用• 用户信息接口• 短消息提醒接口• 头部消息接口• 视频观看记录接口• 视频信息接口• 专辑信息接口• 等等中间层。。。
缺少的• 1. Session
• 2. Http/Smtp/Rpc/…
• 3. Html template
• 等等。。。
场景
• 数据层
• 缓存层
资料• 官网: http://openresty.org/• nginx 模块手册: https://github.com/
chaoslawful/lua-nginx-module• lua手册: http://www.lua.org/manual/5.2/
manual.html
谢谢!
Top Related