openresty practical experience

47
OpenResty 应应应应 应应应 - kim

Upload: ho-kim

Post on 14-Jan-2015

1.371 views

Category:

Technology


4 download

DESCRIPTION

Summary of programming experience with OpenResty in last year. All of the details are real and practical.

TRANSCRIPT

Page 1: OpenResty Practical Experience

OpenResty 应用总结

技术部 - kim

Page 2: OpenResty Practical Experience

讲什么?

• Lua 介绍

• Openresty 介绍

• 重构 Infov 的过程分享

Page 3: OpenResty Practical Experience

什么是 Lua ?• 轻量级脚本语言

• 最小、最快、最简单

• 嵌入式

Page 4: OpenResty Practical Experience

Lua 的特性• Functional 函数式

• Table 数组、哈希表、集合、对象

• Closure 闭包

• Coroutine 协程

Page 5: OpenResty Practical Experience

著名的 Lua 项目

• 魔兽世界、愤怒的小鸟、 Photoshop 、仙剑奇侠传五、淘宝内部

• 56.com (未来)

Page 6: OpenResty Practical Experience

什么是 OpenResty ?

• 最快的 Web 应用开发框架

Page 7: OpenResty Practical Experience

• 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 等都进行一致的高性能响应。

Page 8: OpenResty Practical Experience

性能对比• PHP-Fpm :速度慢、吞吐量低、短连接

• OpenResty :执行快、大吞吐量、连接池

• 春哥做的 benchmark :https://github.com/agentzh/mysql-driver-benchmark

Page 9: OpenResty Practical Experience
Page 10: OpenResty Practical Experience
Page 11: OpenResty Practical Experience

安装• 下载解压:

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

Page 12: OpenResty Practical Experience

Hello world - 1

location /helloworld { echo "hello world!";}

Page 13: OpenResty Practical Experience

Hello world - 2

location = /helloworld { content_by_lua ' ngx.say("hello world!") ';}

Page 14: OpenResty Practical Experience

Hello world - 3

location = /helloworld { content_by_lua_file 'hello_world.lua';}

--hello_world.luangx.say("hello world!")ngx.flush(true)

Page 15: OpenResty Practical Experience

更复杂例子# 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";}

Page 16: OpenResty Practical Experience

无阻塞 IO

location /nonblocking { content_by_lua ' local res = ngx.location.capture("/query") if res.status == 200 then ngx.print(res.body) end';}

Page 17: OpenResty Practical Experience

并发子请求

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) ';}

Page 18: OpenResty Practical Experience

重构 info.v.56.com

Page 19: OpenResty Practical Experience

为什么?

• 前端核心接口

• PHP 性能瓶颈

• 缓存和数据库压力

Page 20: OpenResty Practical Experience

开发

• 公共模块: /lib

• 实例代码: /lib/http.lua

Page 21: OpenResty Practical Experience

一般 debug 方法• 直接抛出错误: error(“ 抛出个 error !” )

• assert(io.read("*number"), "invalid input")

• Lua 提供了错误处理函数 pcall:r, msg = pcall(foo)

• 还可以用 xpcall

Page 22: OpenResty Practical Experience

以上,我们一般不用。。。

Page 23: OpenResty Practical Experience

实际 debug 方法

• tailf /home/openresty/nginx/logs/error.log

Page 24: OpenResty Practical Experience

具体配置• 新网段 + 3台新机器

• 高可用性: lvs + keepalive

• 高可用 Cache : twemproxy + kt(12 个 )

• 高性能: openresty

• 实时性:缓存耦合(人气、评论),缓存更新(直连 + httpsqs )

Page 25: OpenResty Practical Experience

切换原则

• 完全保留原 PHP 的所有读写功能,即线上功能不受影响

Page 26: OpenResty Practical Experience

Nginx 配置技巧

• ~ 为区分大小写的匹配。

• ~* 不区分大小写的匹配。

• !~ 和 !~* 意为“不匹配的”。

Page 27: OpenResty Practical Experience

多重 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;

Page 28: OpenResty Practical Experience

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';}

Page 29: OpenResty Practical Experience

切换过程

• 对每个应用,通过改 hosts 来灰度切换,有问题立刻发现立刻修复

• 播放页和 vxml 最后切换

Page 30: OpenResty Practical Experience

遇到的问题

Page 31: OpenResty Practical Experience

Json输出问题• PHP json_encode :会把 utf-8 强制 escape

成 unicode ,除非是新版 php5.4 以上,可通过指定 JSON_UNESCAPED_UNICODE 参数来禁掉。

• Lua cjson :默认并不会对 utf-8 做 escape 处理,输出的就是 utf-8

Page 32: OpenResty Practical Experience

Table类型

Page 33: OpenResty Practical Experience

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;

Page 34: OpenResty Practical Experience

• 数组部分:速度极快,内存比哈希省一半

• Hash 部分:链状发散表,本身即无序(比如用 PHP 接收到来自 Lua 的输出的时候,不能简单地“认为”它是有序的!)

Page 35: OpenResty Practical Experience

文件 vs 模块

• 为什么要把配置文件写成模块 config.lua ?

Page 36: OpenResty Practical Experience

测试环境问题

• 测试环境和正式环境最好还是分开,特别是不要在一个 server 配置里面

Page 37: OpenResty Practical Experience

dns 解析问题• 可以通过安装和配置 nginx 本地 dns 服务

来添加 resolver ,从而使 sock 能通过 Nginx core‘s dynamic resolver 来解析域名。

• 但是目前实际中还是直接使用 ip 来解析,未来可以对 hosts 进行单独解析,这样就能使用域名了。

Page 38: OpenResty Practical Experience

Bug问题

• Error 级别的都是要尽量修复的

• Emerg 级别的是必须修复的

• 举例 gsub 引发的血案。。。

Page 39: OpenResty Practical Experience

入口不能太“窄”

• vi /etc/sysctl.conf• net.netfilter.nf_conntrack_max = 655360• net.netfilter.nf_conntrack_tcp_timeout_establ

ished = 180

Page 40: OpenResty Practical Experience

Timeout 不能太短

• 无论是连接数据库、缓存还是Webservice ,超时时间太短反而不能充分发挥 OpenResty 的优势

Page 41: OpenResty Practical Experience

现状与展望

Page 42: OpenResty Practical Experience

价值• 1. 代码量

• 2. 开发效率

• 3. 性能提升

Page 43: OpenResty Practical Experience

站内应用• 用户信息接口• 短消息提醒接口• 头部消息接口• 视频观看记录接口• 视频信息接口• 专辑信息接口• 等等中间层。。。

Page 44: OpenResty Practical Experience

缺少的• 1. Session

• 2. Http/Smtp/Rpc/…

• 3. Html template

• 等等。。。

Page 45: OpenResty Practical Experience

场景

• 数据层

• 缓存层

Page 46: OpenResty Practical Experience

资料• 官网: http://openresty.org/• nginx 模块手册: https://github.com/

chaoslawful/lua-nginx-module• lua手册: http://www.lua.org/manual/5.2/

manual.html

Page 47: OpenResty Practical Experience

谢谢!