OpenResty 编译安装 与 lua 脚本

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cn_yaojin/article/details/81737258

编译openresty:

./configure --prefix=/usr/local/openresty --with-luajit --with-http_ssl_module --with-stream --with-stream=dynamic --with-stream_ssl_module --with-stream_realip_module --with-mail --with-mail=dynamic --with-http_v2_module --with-http_realip_module --user=root --group=root

如果提示需要 pcre,那么pcre 的安装命令:

yum install -y pcre pcre-devel  

如果缺失 perl, 点这儿

 或者 

 yum install perl

因为使用到了,template.lua,因此需要下载:https://github.com/bungle/lua-resty-template/tree/master/lib/resty

1、nginx配置:


#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  1024;
}


http {
    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;
    lua_shared_dict ip_blacklist 1m;
    lua_shared_dict limit 10m;

    gzip  on;

    #漏桶算法限流(限制请求速率为200 req/sec,并且允许100 req/sec的突发请求,就是说我们会把200以上300一下的请求请求给延迟,超过300的请求将会被拒绝)
    lua_shared_dict my_limit_req_store 100m;
    #server配置
    include domains/*.conf;

}

  domain文件夹下的  *.conf文件:   

#限速模块
server {
	listen       80;
	server_name  192.168.58.128;
	charset utf-8;

    #模板生成html
	location / { 
	    default_type text/html;
	    content_by_lua_file ../lua/index.template.lua;
	    #root   html; #站点目录
	    #index  index.html index.htm;
	}

	location /fameapi {
	    
	    default_type application/json;
	    access_by_lua_file ../lua/hight_limit_speed.lua;#限速模块
	    proxy_buffer_size 64k;
            proxy_buffers   32 32k;
            proxy_busy_buffers_size 128k;         
            proxy_pass     http://fameapi;
            proxy_set_header   X-Real-IP $remote_addr;
      	    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
      	    proxy_set_header    Host $host;
            proxy_pass_header    User-Agent;
      	    client_max_body_size 100M;
	    proxy_connect_timeout 60;#nginx跟后端服务器连接超时时间(代理连接超时)
	    proxy_send_timeout 60;#后端服务器数据回传时间(代理发送超时)
	    proxy_read_timeout 60;#连接成功后,后端服务器响应时间(代理接收超时)
	}

	location /postgres {
	    internal;

	    default_type text/html;
	    set_by_lua_block $query_sql {return ngx.unescape_uri(ngx.var.arg_sql)}
	    
	    postgres_pass   pg_server;
	    rds_json          on;
	    rds_json_buffer_size 16k;
	    postgres_query  $query_sql;
	    postgres_connect_timeout 1s;
	    postgres_result_timeout 2s;
	}

}
#文件
upstream fameapi {
     server  192.168.0.124:8080  weight=1;
}
upstream pg_server {
    postgres_server  192.168.0.103:5432 dbname=fame
            user=postgres password=root;
    postgres_keepalive max=800 mode=single overflow=reject;
}

2、LUA脚本 

-- 获取限流的uri
-- 获取黑名单
-- 获取白名单
-- 获取最大访问次数


--连接到 redis
local redis = require "resty.redis_iresty"
local cache = redis:new()

-- 写入日志记录
function writeLog(str)
	-- 系统当前时间
	local time = os.time()
	-- 格式化时间
	local date = os.date("%Y%m%d",time)
	file = io.open("d:/lua.limit."..date..".log","a+")
	file:write(str)
	file:write("\n")
	file:close()
end

--写json
function writeJson(retTable)
	local cjson = require "cjson"
	--local retTable = {};retTable["success"] = false;
	return cjson.encode(retTable);
end

--读取json
function readJson(str)
	local cjson = require "cjson"
	local c = cjson.decode(str)
	return c
end

--response
function response2Client()
	local retTable = {};
	retTable["success"] = false;
	retTable["msg"] ="网络繁忙,请稍后再试";
	return writeJson(retTable)
end

--与response2Client方法 可以合并了
function responseMsg(msg)
	local retTable = {};
	retTable["success"] = false;
	retTable["msg"] =msg;
	return writeJson(retTable)
end


--获取请求uri
function getUri()
	return ngx.var.uri
end

--获取客户端ip
function get_client_ip()
    local headers=ngx.req.get_headers()
    local ip_addr=headers["X-REAL-IP"] or headers["X_FORWARDED_FOR"] or ngx.var.remote_addr or "0.0.0.0"
    return ip_addr
end

--响应错误
function callerror()
    ngx.header.content_type="application/json;charset=utf8"
	ngx.say(response2Client())
	ngx.exit(200);
end


--响应错误消息(与callerror可以合并了 )
function callErrorMsg(msg)
	ngx.header.content_type="application/json;charset=utf8"
	ngx.say(responseMsg(msg))
	ngx.exit(200);
end


function respData2Client(obj)
	ngx.header.content_type="application/json;charset=utf8"
	local retTable = {};
	retTable["success"] = true;
	retTable["msg"] ="ok";
	retTable["obj"] = obj;
	ngx.say(writeJson(retTable))
	ngx.exit(200);
end


--获取客户端ip
local ip_addr = get_client_ip()
local local_url = getUri()


--检测黑名单
function checkblacklist()
	local is_black,err = cache:sismember('ip_blacklist',ip_addr)

	if is_black==1 then
		return callerror()
	end
end

--检测白名单
function checkwhitelist()
	local is_white,err = cache:sismember('ip_whitelist',ip_addr)

	if is_white=='1' then
		return callerror()
	end
end

-- 从缓存中读取基本配置
function readBaseConfig()
	local base = cache:get('FAME_GLOBAL_CONFIG_KEY')
	if base then
		local json = readJson(base)
		return json
	end
end


--全应用限流(所有接口的总限流入口)
function checklimit()

	--get req limit
	local json = readBaseConfig()

	local max_req_limit = json.max_req_limit
	local wait_req_limit = json.wait_req_limit
	if not max_req_limit then
		max_req_limit = 1
	end
	if not wait_req_limit then
		wait_req_limit = 0
	end
	--每秒最大请求数
	max_req_limit = tonumber(max_req_limit)
	--超过最大请求数后,允许继续等待的请求数
	wait_req_limit = tonumber(wait_req_limit)
	--
	if max_req_limit == 0 then
		return callerror()
	end

	-- ngx.log(ngx.ERR,"应用限流速度: ", max_req_limit)

	local limit_req = require "resty.limit.req"
	-- 限制请求速率为200 req/sec,并且允许100 req/sec的突发请求
	-- 就是说我们会把200以上300一下的请求请求给延迟
	-- 超过300的请求将会被拒绝
	local lim, err = limit_req.new("my_limit_req_store", max_req_limit, wait_req_limit)
	if not lim then --申请limit_req对象失败
		ngx.log(ngx.ERR,"failed to instantiate a resty.limit.req object: ", err)
		return callerror()
	end

	-- 下面代码针对每一个单独的请求
	local delay, err = lim:incoming('fame_api_limit', true)
	if not delay then
		if err == "rejected" then
			return callerror()
		end
		ngx.log(ngx.ERR, "failed to limit req: ", err)
		return callerror()
	end

	if delay > 0 then
		-- 第二个参数(err)保存着超过请求速率的请求数
		-- 例如err等于31,意味着当前速率是231 req/sec
		local excess = err
		-- 当前请求超过200 req/sec 但小于 300 req/sec
        -- 因此我们sleep一下,保证速率是200 req/sec,请求延迟处理
        ngx.sleep(delay) --非阻塞sleep(秒)
	end
end


--限制同一个IP在某时间内url的请求次数(192.168.0.1 在10秒内访问url的次数),超过次数后终止该ip的请求
function checkUrlLimit()
	local access_uri = ip_addr..local_url
	local key = access_uri
	local limit = ngx.shared.limit
	local req
	if limit then
		req = limit:get(key)
	end
	--读取基本配置
	local json = readBaseConfig()
	--单位时间内最大请求数
	local lock_limit_num = json.lock_limit_num
	--单位时间
	local lock_limit_seconds = json.lock_limit_seconds
	if not lock_limit_num then
		lock_limit_num = 100
	end
	if not lock_limit_seconds then
		lock_limit_seconds = 10
	end
	--每秒最大请求数
	lock_limit_num = tonumber(lock_limit_num)
	--超过最大请求数后,允许继续等待的请求数
	lock_limit_seconds = tonumber(lock_limit_seconds)


	if req then
		if req >=lock_limit_num then
			--添加单黑名单
			cache:sadd('ip_blacklist',ip_addr)
			return callerror()
		end
		limit:incr(key,1)
	else
		--60S
		limit:set(key,1,lock_limit_seconds)
	end
	ngx.log(ngx.ERR,"完成校验,即将进入content: ", "这是姚进的测试")
	--content.test()

end

--从postgres 查询数据,并以JSON的格式展示
function queryDataPostgres()
	local res = ngx.location.capture('/postgres',
            { args = {sql = "select user_id,user_name from fame_user where 1=1 limit 5 offset 0 " } }
	)
	local status = res.status
	--读取查询到的数据,并将json格式转换成表格对象
	local body = readJson(res.body)
	if status == 200 then
		--返回查询结果给客户端,以JSON的格式展示
		return respData2Client(body)
	else
		return callerror()
	end

end

-- api限速
function limitApiSpeed(key,max_req_limit,wait_req_limit,msg)
	if not max_req_limit then
		max_req_limit = 10
	end
	if not wait_req_limit then
		wait_req_limit = 1
	end
	--每秒最大请求数
	max_req_limit = tonumber(max_req_limit)
	--超过最大请求数后,允许继续等待的请求数
	wait_req_limit = tonumber(wait_req_limit)
	--
	if max_req_limit == 0 then
		return callErrorMsg(msg)
	end

	local limit_req = require "resty.limit.req"
	-- 限制请求速率为200 req/sec,并且允许100 req/sec的突发请求
	-- 就是说我们会把200以上300一下的请求请求给延迟
	-- 超过300的请求将会被拒绝
	local lim, err = limit_req.new("my_limit_req_store", max_req_limit, wait_req_limit)
	if not lim then --申请limit_req对象失败
		ngx.log(ngx.ERR,"failed to instantiate a resty.limit.req object: ", err)
		return callErrorMsg(msg)
	end

	-- 下面代码针对每一个单独的请求
	-- 使用 请求地址 地址作为限流的key
	local delay, err = lim:incoming(key, true)
	if not delay then
		if err == "rejected" then
			return callErrorMsg(msg)
		end
		ngx.log(ngx.ERR, "failed to limit req: ", err)
		return callErrorMsg(msg)
	end

	if delay > 0 then
		-- 第二个参数(err)保存着超过请求速率的请求数
		-- 例如err等于31,意味着当前速率是231 req/sec
		local excess = err
		-- 当前请求超过200 req/sec 但小于 300 req/sec
        -- 因此我们sleep一下,保证速率是200 req/sec,请求延迟处理
        ngx.sleep(delay) --非阻塞sleep(秒)
	end

end

-- 查询限速的接口(限流的api,保存在redis的map中)
function getApiSpeedLimit(url)
	local result = cache:hget('API_SPEED_LIMIT',url)
	if result then
		local json = readJson(result)
		return json
	end

end

--api限速
function checkApiUrl()
	local ip = ngx.var.binary_remote_addr
	local url = ngx.var.uri

	local result = getApiSpeedLimit(url)
	if result then
		-- api接口是否启用
		local flag =result.flag
		-- api接口1秒内最大的请求数
		local limit_api_count = result.limit_api_count
		-- api接口1秒内达到最大请求数后,允许等待的线程数
		local limit_api_realy = result.limit_api_realy
		local msg msg = result.msg
		if flag == 0 then
			-- 正常的接口
			limitApiSpeed(url,limit_api_count,limit_api_realy,msg)
		else
			--禁用的接口
			callErrorMsg(msg)
		end
	end
	
end

--功能清单
function access_check()
	queryDataPostgres()
    checkblacklist()
	checklimit()
	checkUrlLimit()
end

--请求入口
access_check()

api接口限流,具体信息保存在redis的map中

package com.cn.common.apiurls;

import java.io.Serializable;

public class ApiSpeedLimitInfo implements Serializable {

    /**
     * 接口名称
     */
    private String name;

    private String url;

    /**
     * 消息
     */
    private String msg;

    /**
     * 0-正常
     * 1-禁用
     */
    private int flag;

    /**
     * 接口限速- 1s内允许通过接口最大数目
     */
    private int limit_api_count;

    /**
     * 接口限速后 1s内允许该接口等待线程的最大数目
     */
    private int limit_api_realy;

    public String getMsg() {
        return msg;
    }

    public ApiSpeedLimitInfo setMsg(String msg) {
        this.msg = msg;
        return this;
    }

    public int getFlag() {
        return flag;
    }

    public ApiSpeedLimitInfo setFlag(int flag) {
        this.flag = flag;
        return this;
    }

    public int getLimit_api_count() {
        return limit_api_count;
    }

    public ApiSpeedLimitInfo setLimit_api_count(int limit_api_count) {
        this.limit_api_count = limit_api_count;
        return this;
    }

    public int getLimit_api_realy() {
        return limit_api_realy;
    }

    public ApiSpeedLimitInfo setLimit_api_realy(int limit_api_realy) {
        this.limit_api_realy = limit_api_realy;
        return this;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

api示例:

html模板:

local template = require "resty.template"
-- 请求url
local url = ngx.var.uri
--查询参数
local code_no = ngx.var.arg_code_no

template.render("index.html",{ message =url,params=code_no})

index.html:

<!DOCTYPE html>
<html>
<head>
<title>Welcome to OpenResty!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to OpenResty!</h1>
<p>Hi,{{message}}</p>
<p>收到的参数:{{params}}</p>

<p>For online documentation and support please refer to
<a href="https://openresty.org/">openresty.org</a>.<br/>
Commercial support is available at
<a href="https://openresty.com/">openresty.com</a>.</p>

<p><em>Thank you for flying OpenResty.</em></p>
</body>
</html>

3、域名配置,如下:

域名配置

 html5.api.conf配置如下:

#限速模块
server {
	listen       80;
	server_name  192.168.58.128;
	charset utf-8;

	location /fameapi {
	    
	    default_type application/json;
	    access_by_lua_file ../lua/hight_limit_speed.lua;#限速模块
	    proxy_buffer_size 64k;
            proxy_buffers   32 32k;
            proxy_busy_buffers_size 128k;         
            proxy_pass     http://fameapi;
            proxy_set_header   X-Real-IP $remote_addr;
      	    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
      	    proxy_set_header    Host $host;
            proxy_pass_header    User-Agent;
      	    client_max_body_size 100M;
	    proxy_connect_timeout 60;#nginx跟后端服务器连接超时时间(代理连接超时)
	    proxy_send_timeout 60;#后端服务器数据回传时间(代理发送超时)
	    proxy_read_timeout 60;#连接成功后,后端服务器响应时间(代理接收超时)
	}

	#查询postgres 
	location /postgres {
	    internal; #加上该参数后,禁止外部访问

	    default_type text/html;
	    set_by_lua_block $query_sql {return ngx.unescape_uri(ngx.var.arg_sql)}
	    
	    postgres_pass   pg_server;
	    rds_json          on;
	    rds_json_buffer_size 16k;
	    postgres_query  $query_sql;
	    postgres_connect_timeout 1s;
	    postgres_result_timeout 2s;
	}

}
#文件
upstream fameapi {
     server  192.168.0.124:8080  weight=1;
}
#postgres 查询
upstream pg_server {
    postgres_server  192.168.0.103:5432 dbname=fame
            user=postgres password=root;
    postgres_keepalive max=800 mode=single overflow=reject;
}

猜你喜欢

转载自blog.csdn.net/cn_yaojin/article/details/81737258