# OpenResty-Learning **Repository Path**: zhangjuntao/OpenResty-Learning ## Basic Information - **Project Name**: OpenResty-Learning - **Description**: OpenResty-Learning - **Primary Language**: Lua - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2018-03-08 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # OpenResty-Learning ## 1、学习资料 > * [OpenResty最佳实践](https://www.gitbook.com/book/moonbingbing/openresty-best-practices) > * [OpenResty官方文档](https://github.com/openresty/lua-nginx-module) ## 2、明日学习任务 > * ngx lua helloworld > * http 解析返回cookie > * lua redis MySQL > * ngx cache 和 openresty cache > * openrestry 最佳实践 > * shareddict 和 openrestry lrucache 优劣 > * ngx lua openrestry 文档 > * openrestry 最佳实践 有Windows版的 > * shareddict 和 openrestry lrucache 优劣 > * 缓存失效风暴 > * 并发过大,同时几万个并发请求获取缓存。打爆数据库。考虑使用lua_resty_lock 加锁实现。 ## 3、缓存失效风暴 **解释:** 并发过大,同时几万个并发请求获取缓存。打爆数据库。 **解决方案:** 考虑使用lua_resty_lock 加锁实现。 ## 4、配置文件 ```java worker_processes 1; #nginx worker 数量 error_log logs/error.log info; #设置log的级别为info events { worker_connections 1024; } http { server { #监听端口,若你的6699端口已经被占用,则需要修改 listen 80; lua_code_cache off; charset utf-8; location / { default_type text/html; content_by_lua_block { ngx.say("HelloWorld") } } location ~ ^/app/([-_a-zA-Z0-9/]+) { set $path $1; content_by_lua_file lua/app/$path.lua; } location ~ ^/home/* { default_type text/html; content_by_lua_block { ngx.say(" home") } } location ~ ^/auth/* { access_by_lua_file lua/app/auth_filter.lua; proxy_pass http://www.ttlsa.com; } location ~ ^/rewrite/* { rewrite_by_lua_file lua/app/rewrite_filter.lua; content_by_lua_block { ngx.say(" rewrite ") } } location = /t { content_by_lua ' require("my-lrucache").go() '; } } } ``` ## 5、缓存shared_dict、LRUCache 优劣: * **shared_dict:** 1、多个worker之间共享的变量。 2、非线程安全,多worker 必须加锁。 3、内存共享,更省内存。 * **LRUCache:** 1、worker私有的内存,线程安全的。 2、LRU 最近使用size个元素 3、无锁更快速。 ## 6、redis + lua ### 6.1、实现原子操作的分布式锁 lua代码: ```lua --- 分布式锁实现 -- call 函数直接终止lua命令 expire key second local empty = redis.call("setnx",KEYS[1],"distributed_lock") if tonumber(empty) > 0 then redis.call("expire",KEYS[1],ARGV[1]) return 1 end return 0 ``` JAVA客户端的调用: ```java import com.alibaba.fastjson.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.BoundValueOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.test.context.junit4.SpringRunner; import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest public class RedisConfigurationTest { @Autowired private RedisTemplate redisTemplate; @Test public void main() throws InterruptedException { Random random = new Random(); List keys = Arrays.asList("lock"); String lua = "local empty = redis.call(\"setnx\",KEYS[1],\"distributed_lock\") if tonumber(empty) > 0 then redis.call(\"expire\",KEYS[1],ARGV[1]) return 1 end return 0"; for (int i = 0; i < 100; i++) { Thread.sleep(random.nextInt(20) * 1000L); Object execute = redisTemplate.execute(new DefaultRedisScript(lua,Long.class),keys,10); System.err.println(execute); } } } ``` ### 6.2、实现redis原子操作 LUA代码: ```lua local num = redis.call("get",KEYS[1]) if not num then redis.call("set",KEYS[1],100) num = 100 end if tonumber(num) < 1 then return 0 else redis.call("set",KEYS[1],tonumber(num) - 1) return 1 end ``` ```commandline eval script keynum keys args keys引用 KEYS数组 args引用 ARGV数组 evalsha1 script_sha1 keynum keys args eval 'local num = redis.call("get",KEYS[1]) if not num then redis.call("set",KEYS[1],100) num = 100 end if tonumber(num) < 1 then return 0 else redis.call("set",KEYS[1],tonumber(num) - 1) return 1 end' 1 lock 10 ``` ### 6.3、lua实现redis eval操作 lua代码: ```lua --- 释放redis 链接到连接池中 -- @param red -- local function close_redis(red) if not red then return end --释放连接(连接池实现) local pool_max_idle_time = 10000 --毫秒 local pool_size = 100 --连接池大小 local ok, err = red:set_keepalive(pool_max_idle_time, pool_size) if not ok then ngx.say("set keepalive error : ", err) end end --- 执行lua函数 -- @param red -- function function_eval(red) local resp, _ = red:eval("return redis.call('get', KEYS[1])", 1, "msg"); ngx.print(resp) end --- 执行redis中的函数evalsha1、 装载redis函数 script load -- @param red redis 链接 -- function function_evalsha(red) local sha1, err = red:script("load", "return redis.call('get', KEYS[1])"); if not sha1 then ngx.say("load script error : ", err) return close_redis(red) end ngx.say("sha1 : ", sha1, "
") resp, err = red:evalsha(sha1, 1, "msg"); ngx.print(resp) end --- 创建redis链接 -- function redis_client() local redis = require "resty.redis" local red = redis:new() red:set_timeout(1000) -- 1 sec local ok, err = red:connect("192.168.61.128", 6379) if not ok then ngx.say("failed to connect: ", err) return end return red end local red = redis_client() function_eval(red) function_evalsha(red) ``` ## 7、Nginx 灰度发布 ### 7.2、应用包 > 1、nginx-upsync-module : 负责灰度发布的更新Nginx的路由规则 > > ​ [文档地址](https://github.com/weibocom/nginx-upsync-module/) > > 2、nginx_stream_upstream_check_module:负责定时检测应用、Consul路由数据 > > ​ [文档地址](https://github.com/xiaokai-wang/nginx_stream_upstream_check_module) > > 3、Nginx :负责网关的反向代理 > > ​ [文档地址](https://github.com/nginx/nginx) ### 7.3、安装Consul ```shell docker pull chenpeihai/consul docker run -p 8500:8500 -p 53:53/udp -h node1 chenpeihai/consul -server -bootstrap ``` ### 7.4、安装Nginx及插件 ```shell #安装编译依赖 sudo yum install libreadline-dev libncurses5-dev libpcre3-dev libssl-dev perl make build-essential sudo yum install zlib pcre pcre-devel openssl openssl-devel zlib-devel git #下载nginx wget 'http://nginx.org/download/nginx-1.8.0.tar.gz' tar -xzvf nginx-1.8.0.tar.gz cd nginx-1.8.0/ #下载check upsync 插件 git clone https://github.com/weibocom/nginx-upsync-module.git #选择1.8版本【适配nginx】 git checkout -b nginx-upsync-1.8.x origin/nginx-upsync-1.8.x git clone https://github.com/xiaokai-wang/nginx_stream_upstream_check_module #编译 patch -p1 < /path/nginx_upstream_check_module/check_1.7.5+.patch ./configure --add-module=/usr/local/apps/nginx_upstream_check_module --add-module=/usr/local/apps/nginx-upsync-module-nginx-upsync-1.8.x make make install ``` ### 7.5、配置 **vim /usr/local/nginx/conf/nginx.conf** ```properties user nginx; worker_processes 5; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /usr/local/nginx/conf/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 /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; #gzip on; include /usr/local/nginx/conf/conf.d/*.conf; } ``` **vim /usr/local/nginx/conf/conf.d/check.conf** ```properties upstream test { # fake server otherwise ngx_http_upstream will report error when startup server 127.0.0.1:11111; # all backend server will pull from consul when startup and will delete fake server # Consule 更新的规则 upsync 172.20.20.10:8500/v1/kv/upstreams/test upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off; upsync_dump_path /usr/local/nginx/conf/servers/servers_test.conf; check interval=1000 rise=2 fall=2 timeout=3000 type=http default_down=false; check_http_send "HEAD / HTTP/1.0\r\n\r\n"; check_http_expect_alive http_2xx http_3xx; } upstream bar { server 172.20.20.11:8080 weight=1 fail_timeout=10 max_fails=3; } server { listen 80; location = / { proxy_pass http://test; } location = /upstream_show { upstream_show; } location = /upstream_status { check_status; access_log off; } } ``` ### 7.6、启动 ```sh /usr/local/nginx/sbin/nginx curl -X PUT http://192.168.61.128:8500/v1/kv/upstreams/test/192.168.61.1:8888 curl -X PUT http://192.168.61.128:8500/v1/kv/upstreams/test/192.168.61.1:80 ``` 参考文档: ​ https://github.com/weibocom/nginx-upsync-module ​ http://blog.csdn.net/yueguanghaidao/article/details/52801043 ​ https://github.com/xiaokai-wang/nginx_stream_upstream_check_module ​ http://blog.csdn.net/tianhua79658788/article/details/78487927?locationNum=3&fps=1 ​ http://blog.csdn.net/weixin_39686421/article/details/78214327 ## 8、FFI ## 9、nginx 子查询 * **capture、capture_multi**