From 21abfc154999af7dd264ee98dbf9cf984bd9e1a5 Mon Sep 17 00:00:00 2001 From: "https://blog.iamtsm.cn" <1905333456@qq.com> Date: Mon, 27 Feb 2023 23:04:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81api=E8=B7=AF=E7=94=B1?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E8=99=9A=E6=8B=9F=E5=89=8D=E7=BC=80=20feat:?= =?UTF-8?q?=20=E5=90=8C=E6=AD=A5=E8=A1=A5=E5=85=85=E6=96=87=E6=A1=A3=20fea?= =?UTF-8?q?t:=20=E4=BC=98=E5=8C=96=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81=20f?= =?UTF-8?q?eat:=20=E8=B0=83=E6=95=B4=E5=AE=98=E7=BD=91=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- balance/tl_ops_balance_core.lua | 20 +- balance/tl_ops_balance_core_api.lua | 30 ++- bin/install_centeros.sh | 2 +- bin/install_ubuntu.sh | 2 +- conf/tl_ops_manage.conf | 7 +- constant/tl_ops_constant_balance.lua | 1 + constant/tl_ops_constant_balance_api.lua | 2 + err/tl_ops_err_content.lua | 5 +- err/tl_ops_err_content_core.lua | 1 + gitbook/README_API.md | 2 +- gitbook/README_DEV.md | 9 +- gitbook/SUMMARY.md | 43 ++++- gitbook/code/auth/README.md | 131 +++++++++++++ gitbook/code/balance/README.md | 60 +++--- gitbook/code/balance/README_RULE.md | 141 +++++++++----- gitbook/code/cors/README.md | 3 + gitbook/code/fuselimit/README.md | 6 +- gitbook/code/fuselimit/README_BALANCE.md | 99 +++++----- gitbook/code/fuselimit/README_FUSE.md | 2 + gitbook/code/fuselimit/README_LIMIT.md | 10 +- gitbook/code/health/README.md | 3 + gitbook/code/health/README_CHECK.md | 39 ++-- gitbook/code/healthdebug/README.md | 3 + gitbook/code/loganalyze/README.md | 3 + gitbook/code/plugin/README.md | 1 + gitbook/code/plugin/README_HOOK.md | 177 +++++++++++------- gitbook/code/plugin/README_LOAD.md | 80 ++------ gitbook/code/tracing/README.md | 3 + gitbook/usage/auth/README.md | 0 gitbook/usage/balance/README.md | 9 +- gitbook/usage/balance/README_RULE.md | 69 +++++-- gitbook/usage/cors/README.md | 0 gitbook/usage/env/README.md | 120 ++---------- gitbook/usage/fuselimit/README.md | 32 ++-- gitbook/usage/healthdebug/README.md | 0 gitbook/usage/install/README.md | 4 +- gitbook/usage/intro/README.md | 4 +- gitbook/usage/loganalyze/README.md | 0 gitbook/usage/pageproxy/README.md | 0 gitbook/usage/plugin/README.md | 14 +- gitbook/usage/sync/README.md | 0 gitbook/usage/timealert/README.md | 0 limit/fuse/tl_ops_limit_fuse_leak_bucket.lua | 11 +- limit/fuse/tl_ops_limit_fuse_token_bucket.lua | 11 +- tl_ops_manage.lua | 1 + web/balance/tl_ops_web_api.js | 17 +- web/balance/tl_ops_web_api_form.html | 27 ++- web/balance/tl_ops_web_api_form.js | 9 +- website/en.html | 7 +- website/index.html | 7 +- 50 files changed, 755 insertions(+), 472 deletions(-) create mode 100644 gitbook/code/auth/README.md create mode 100644 gitbook/code/cors/README.md create mode 100644 gitbook/code/healthdebug/README.md create mode 100644 gitbook/code/loganalyze/README.md create mode 100644 gitbook/code/tracing/README.md create mode 100644 gitbook/usage/auth/README.md create mode 100644 gitbook/usage/cors/README.md create mode 100644 gitbook/usage/healthdebug/README.md create mode 100644 gitbook/usage/loganalyze/README.md create mode 100644 gitbook/usage/pageproxy/README.md create mode 100644 gitbook/usage/sync/README.md create mode 100644 gitbook/usage/timealert/README.md diff --git a/balance/tl_ops_balance_core.lua b/balance/tl_ops_balance_core.lua index 5ddf8dd..488873a 100644 --- a/balance/tl_ops_balance_core.lua +++ b/balance/tl_ops_balance_core.lua @@ -39,12 +39,12 @@ function _M:tl_ops_balance_core_filter(ctx) -- 服务节点配置列表 local service_list_str, _ = cache_service:get(tl_ops_constant_service.cache_key.service_list); if not service_list_str then - tl_ops_err_content:err_content_rewrite_to_balance("", "empty", "", tl_ops_constant_balance.cache_key.service_empty) + tl_ops_err_content:err_content_rewrite_to_balance("", "empty", "", tl_ops_constant_balance.cache_key.service_empty, "") return end local service_list_table = cjson.decode(service_list_str); if not service_list_table and type(service_list_table) ~= 'table' then - tl_ops_err_content:err_content_rewrite_to_balance("", "empty", "", tl_ops_constant_balance.cache_key.service_empty) + tl_ops_err_content:err_content_rewrite_to_balance("", "empty", "", tl_ops_constant_balance.cache_key.service_empty, "") return end @@ -75,7 +75,7 @@ function _M:tl_ops_balance_core_filter(ctx) node, node_state, node_id, host, rule_match_mode = tl_ops_balance_core_body.tl_ops_balance_body_service_matcher(service_list_table) if not node then -- 无匹配 - tl_ops_err_content:err_content_rewrite_to_balance("", "empty", balance_mode, tl_ops_constant_balance.cache_key.mode_empty) + tl_ops_err_content:err_content_rewrite_to_balance("", "empty", balance_mode, tl_ops_constant_balance.cache_key.mode_empty, "") return end end @@ -86,13 +86,13 @@ function _M:tl_ops_balance_core_filter(ctx) if rule_match_mode and rule_match_mode == api_match_mode.api then -- 域名负载 if host == nil or host == '' then - tl_ops_err_content:err_content_rewrite_to_balance("", "nil", balance_mode, tl_ops_constant_balance.cache_key.host_empty) + tl_ops_err_content:err_content_rewrite_to_balance("", "nil", balance_mode, tl_ops_constant_balance.cache_key.host_empty, "") return end -- 域名匹配 if host ~= "*" and host ~= ngx.var.host then - tl_ops_err_content:err_content_rewrite_to_balance("", "pass", balance_mode, tl_ops_constant_balance.cache_key.host_pass) + tl_ops_err_content:err_content_rewrite_to_balance("", "pass", balance_mode, tl_ops_constant_balance.cache_key.host_pass, "") return end end @@ -106,7 +106,7 @@ function _M:tl_ops_balance_core_filter(ctx) local token_result = tl_ops_limit_fuse_token_bucket.tl_ops_limit_token( node.service, node_id) if not token_result or token_result == false then balance_count:tl_ops_balance_count_incr_fail(node.service, node_id) - tl_ops_err_content:err_content_rewrite_to_balance("", "t-limit", balance_mode, tl_ops_constant_balance.cache_key.token_limit) + tl_ops_err_content:err_content_rewrite_to_balance("", "t-limit", balance_mode, tl_ops_constant_balance.cache_key.token_limit, "") return end end @@ -116,7 +116,7 @@ function _M:tl_ops_balance_core_filter(ctx) local leak_result = tl_ops_limit_fuse_leak_bucket.tl_ops_limit_leak( node.service, node_id) if not leak_result or leak_result == false then balance_count:tl_ops_balance_count_incr_fail(node.service, node_id) - tl_ops_err_content:err_content_rewrite_to_balance("", "l-limit", balance_mode, tl_ops_constant_balance.cache_key.leak_limit) + tl_ops_err_content:err_content_rewrite_to_balance("", "l-limit", balance_mode, tl_ops_constant_balance.cache_key.leak_limit, "") return end end @@ -137,7 +137,7 @@ function _M:tl_ops_balance_core_filter(ctx) end shared:incr(limit_req_fail_count_key, 1) - tl_ops_err_content:err_content_rewrite_to_balance(node.service .. ":" .. node.name, "offline", balance_mode, tl_ops_constant_balance.cache_key.offline) + tl_ops_err_content:err_content_rewrite_to_balance(node.service .. ":" .. node.name, "offline", balance_mode, tl_ops_constant_balance.cache_key.offline, "") return end @@ -155,6 +155,7 @@ function _M:tl_ops_balance_core_balance(ctx) local tlops_ups_mode = ctx.tlops_ups_mode local tlops_ups_node = ctx.tlops_ups_node local tlops_ups_node_id = ctx.tlops_ups_node_id + local tlops_ups_api_prefix = ngx.var.tlops_ups_api_prefix; if not tlops_ups_mode or not tlops_ups_node or not tlops_ups_node_id then return @@ -173,7 +174,8 @@ function _M:tl_ops_balance_core_balance(ctx) ngx.header[tl_ops_constant_balance.proxy_server] = tlops_ups_node.service .. ":" .. tlops_ups_node.name; ngx.header[tl_ops_constant_balance.proxy_state] = "online" ngx.header[tl_ops_constant_balance.proxy_mode] = tlops_ups_mode - + ngx.header[tl_ops_constant_balance.proxy_prefix] = tlops_ups_api_prefix + local ok, err = ngx_balancer.set_current_peer(tlops_ups_node.ip, tlops_ups_node.port) if ok then ngx_balancer.set_timeouts(3, 60, 60) diff --git a/balance/tl_ops_balance_core_api.lua b/balance/tl_ops_balance_core_api.lua index edd2ccf..f850592 100644 --- a/balance/tl_ops_balance_core_api.lua +++ b/balance/tl_ops_balance_core_api.lua @@ -13,6 +13,7 @@ local tl_ops_constant_health = require("constant.tl_ops_constant_health") local shared = ngx.shared.tlopsbalance local find = ngx.re.find + -- 处理匹配逻辑 local tl_ops_balance_api_matcher_mode = function (matcher, request_uri, obj) local match_mode = obj.match_mode @@ -21,13 +22,14 @@ local tl_ops_balance_api_matcher_mode = function (matcher, request_uri, obj) end -- 正则匹配模式 if match_mode == tl_ops_match_mode.reg or match_mode == tl_ops_match_mode.regi or match_mode == tl_ops_match_mode.regid then - local from, to , _ = find(request_uri , obj.url , match_mode); + local from, to , _ = find(request_uri , (obj.fake_prefix .. obj.url) , match_mode); if from and to then local sub = string.sub(request_uri, from, to) if sub then if not matcher or not matcher.url then matcher = obj end + -- 规则最长匹配优先 if matcher.url and #sub > #matcher.url then matcher = obj end @@ -36,7 +38,7 @@ local tl_ops_balance_api_matcher_mode = function (matcher, request_uri, obj) end -- 全文匹配 if match_mode == tl_ops_match_mode.all then - if request_uri == obj.url then + if request_uri == (obj.fake_prefix .. obj.url) then matcher = obj; end end @@ -45,7 +47,7 @@ local tl_ops_balance_api_matcher_mode = function (matcher, request_uri, obj) end -- 获取命中的api路由项 -local tl_ops_balance_api_get_matcher_rule = function(api_list_table, rule, rule_match_mode) +local tl_ops_balance_api_get_matcher_rule = function(api_list_table, rule, rule_match_mode, request_uri) local matcher = nil; local matcher_list = api_list_table[rule] @@ -53,15 +55,11 @@ local tl_ops_balance_api_get_matcher_rule = function(api_list_table, rule, rule_ return nil end - -- 获取当前url - local request_uri = tl_ops_utils_func:get_req_uri(); - -- 获取当前host local cur_host = ngx.var.host; for i, obj in pairs(matcher_list) do repeat - if rule_match_mode == tl_ops_constant_balance_api.mode.host then -- 如果是优先host规则匹配,先剔除不属于当前host的规则 if obj.host == nil or obj.host == '' then @@ -109,15 +107,18 @@ local tl_ops_balance_api_service_matcher = function(service_list_table) if not api_list_table then return nil, nil, nil, nil, rule_match_mode end + + -- 获取当前url + local request_uri = tl_ops_utils_func:get_req_uri(); -- 根据路由当前策略进行路由, 返回正则命中的api if api_rule == tl_ops_constant_balance_api.rule.point then matcher = tl_ops_balance_api_get_matcher_rule( - api_list_table, tl_ops_constant_balance_api.rule.point, rule_match_mode + api_list_table, tl_ops_constant_balance_api.rule.point, rule_match_mode, request_uri ); elseif api_rule == tl_ops_constant_balance_api.rule.random then matcher = tl_ops_balance_api_get_matcher_rule( - api_list_table, tl_ops_constant_balance_api.rule.random, rule_match_mode + api_list_table, tl_ops_constant_balance_api.rule.random, rule_match_mode, request_uri ); end @@ -142,7 +143,6 @@ local tl_ops_balance_api_service_matcher = function(service_list_table) end -- 服务内随机 elseif api_rule == tl_ops_constant_balance_api.rule.random then - local request_uri = tl_ops_utils_func:get_req_uri(); math.randomseed(#request_uri) node_id = tonumber(math.random(0,1) % #service_list_table[matcher.service]) + 1 node = service_list[node_id] @@ -158,6 +158,16 @@ local tl_ops_balance_api_service_matcher = function(service_list_table) if rewrite_url and rewrite_url ~= '' then ngx.req.set_uri(rewrite_url, false) end + + -- 需要转发到服务具体路径 + local fake_prefix = matcher.fake_prefix + if fake_prefix and matcher.fake_prefix ~= '' then + -- 通过虚拟前缀截取后缀 + local fake_sub = string.sub(request_uri, #fake_prefix + 1, #request_uri) + if fake_sub then + ngx.var.tlops_ups_api_prefix = fake_sub + end + end return node, node_state, node_id, host, rule_match_mode end diff --git a/bin/install_centeros.sh b/bin/install_centeros.sh index c642d0f..7d82d3b 100644 --- a/bin/install_centeros.sh +++ b/bin/install_centeros.sh @@ -6,7 +6,7 @@ TL_OPS_PATH="/usr/local/tl-ops-manage/" TL_OPS_CONF_PATH="/usr/local/tl-ops-manage/conf/tl_ops_manage.conf" TL_OPS_LUA_PATH="/usr/local/openresty/lualib/?.lua;;/usr/local/tl-ops-manage/?.lua;;" TL_OPS_LUAC_PATH="/usr/local/openresty/lualib/?.so;;" -TL_OPS_VER="v3.1.0" +TL_OPS_VER="v3.2.0" echo_msg(){ cur_time=$(date "+%Y-%m-%d %H:%M:%S") diff --git a/bin/install_ubuntu.sh b/bin/install_ubuntu.sh index 6e0204c..9df4b9d 100644 --- a/bin/install_ubuntu.sh +++ b/bin/install_ubuntu.sh @@ -6,7 +6,7 @@ TL_OPS_PATH="/usr/local/tl-ops-manage/" TL_OPS_CONF_PATH="/usr/local/tl-ops-manage/conf/tl_ops_manage.conf" TL_OPS_LUA_PATH="/usr/local/openresty/lualib/?.lua;;/usr/local/tl-ops-manage/?.lua;;" TL_OPS_LUAC_PATH="/usr/local/openresty/lualib/?.so;;" -TL_OPS_VER="v3.1.0" +TL_OPS_VER="v3.2.0" echo_msg(){ cur_time=$(date "+%Y-%m-%d %H:%M:%S") diff --git a/conf/tl_ops_manage.conf b/conf/tl_ops_manage.conf index 810fbf2..707613c 100644 --- a/conf/tl_ops_manage.conf +++ b/conf/tl_ops_manage.conf @@ -27,7 +27,10 @@ server { charset utf8; - location / { + # lua_code_cache off; + + location / { + set $tlops_ups_api_prefix ""; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; @@ -36,7 +39,7 @@ server { proxy_set_header X-CLIENT-VERIFY $ssl_client_verify; add_header Access-Control-Allow-Headers *; add_header Access-Control-Allow-Methods *; - proxy_pass http://tlopsmanage; + proxy_pass http://tlopsmanage$tlops_ups_api_prefix; rewrite_by_lua_block { tlops:tl_ops_process_init_rewrite(); diff --git a/constant/tl_ops_constant_balance.lua b/constant/tl_ops_constant_balance.lua index d4314ca..4f37e0f 100644 --- a/constant/tl_ops_constant_balance.lua +++ b/constant/tl_ops_constant_balance.lua @@ -25,6 +25,7 @@ local tl_ops_constant_balance = { proxy_server = "Tl-Proxy-Server", -- 请求头标记 proxy_state = "Tl-Proxy-State", proxy_mode = "Tl-Proxy-Mode", + proxy_prefix = "Tl-Proxy-Prefix", api = { list = { point = tl_ops_constant_balance_api.point, diff --git a/constant/tl_ops_constant_balance_api.lua b/constant/tl_ops_constant_balance_api.lua index f762c14..56b377a 100644 --- a/constant/tl_ops_constant_balance_api.lua +++ b/constant/tl_ops_constant_balance_api.lua @@ -22,6 +22,7 @@ local tl_ops_constant_balance_api = { node = 0, -- 当前url路由到的service下的node的索引 host = "tlops1.com", -- 当前url处理的域名范围 rewrite_url = "", -- 当前url重写后的url + fake_prefix = "", -- 当前uri规则的虚拟前缀 }, random = { id = 1, @@ -30,6 +31,7 @@ local tl_ops_constant_balance_api = { service = "tlops-demo", -- 当前url路由到的service host = "tlops1.com", -- 当前url处理的域名范围 rewrite_url = "", -- 当前url重写后的url + fake_prefix = "", -- 当前uri规则的虚拟前缀 } }, rule = {-- api rule 策略 diff --git a/err/tl_ops_err_content.lua b/err/tl_ops_err_content.lua index 17fbf70..347acd6 100644 --- a/err/tl_ops_err_content.lua +++ b/err/tl_ops_err_content.lua @@ -17,13 +17,14 @@ end -- uri重写,实现错误内容自定义 -- 重写到balance err内容处理 -function _M:err_content_rewrite_to_balance(server, state, mode, err) +function _M:err_content_rewrite_to_balance(server, state, mode, err, prefix) ngx.req.set_uri_args({ type = "balance", cache_key = err, mode = mode, state = state, - server = server + server = server, + prefix = prefix }) ngx.req.set_uri("/balanceerr/", true) end diff --git a/err/tl_ops_err_content_core.lua b/err/tl_ops_err_content_core.lua index fc38b14..03a894c 100644 --- a/err/tl_ops_err_content_core.lua +++ b/err/tl_ops_err_content_core.lua @@ -28,6 +28,7 @@ local tl_ops_err_content_balance_handler = function(args) ngx.header[constant_balance.proxy_server] = args.server ngx.header[constant_balance.proxy_state] = args.state ngx.header[constant_balance.proxy_mode] = args.mode + ngx.header[constant_balance.proxy_prefix] = args.prefix local str = cache_balance:get(args.cache_key) if not str then diff --git a/gitbook/README_API.md b/gitbook/README_API.md index b2768d4..a46be5b 100644 --- a/gitbook/README_API.md +++ b/gitbook/README_API.md @@ -8,4 +8,4 @@ ## 插件模块接口 -除了默认模块的配置外,项目还支持插件自行提供对外API管理接口,典型的例子就是, `SSL插件` 提供的 `get_ssl.lua` 和 `set_ssl.lua` \ No newline at end of file +除了默认模块的配置外,项目还支持插件自行提供对外API管理接口 \ No newline at end of file diff --git a/gitbook/README_DEV.md b/gitbook/README_DEV.md index e78cb28..91846e4 100644 --- a/gitbook/README_DEV.md +++ b/gitbook/README_DEV.md @@ -1,6 +1,6 @@ # 开发指引 -tl-ops-manage总体设计比较简单,对于稍微熟悉lua的同学来说,也可以快速上手,进行二次开发以贴合业务,我从以下几个方面来引导需要进行二次开发或者参与项目维护的同学 +tl-ops-manage总体设计比较简单,对于稍微了解lua的同学来说,也可以快速上手,进行二次开发以贴合业务,我从以下几个方面来引导需要进行二次开发或者参与项目维护的同学 ### 明确需求 @@ -15,9 +15,4 @@ tl-ops-manage总体设计比较简单,对于稍微熟悉lua的同学来说, 测试是一个必不可少的步骤,测试的完整性决定了你写的代码的可用性,一般的功能可以通过日志和模拟操作进行调试,更完善一些的可以通过编写一些test:ngixn用例( 需要学习一些前置试用知识 )。 -如果有可能,可以对功能进行单独压测和链路压测。提供记录一些性能瓶颈,以便于后续优化。 - - ---------------- - -##### 下面将以tl-ops-manage项目结构进行说明 \ No newline at end of file +如果有可能,可以对功能进行单独压测和链路压测。提供记录一些性能瓶颈,以便于后续优化。 \ No newline at end of file diff --git a/gitbook/SUMMARY.md b/gitbook/SUMMARY.md index e52c34e..cca3ec4 100644 --- a/gitbook/SUMMARY.md +++ b/gitbook/SUMMARY.md @@ -28,10 +28,6 @@ * [插件开发流程](usage/plugin/README.md) - * [动态证书配置](usage/ssl/README.md) - - * [集群部署配置](usage/cluster/README.md) - * [tl-ops-manage-源码解析](README_CODE.md) @@ -53,6 +49,8 @@ * [多规则匹配](code/balance/README_RULE.md) + * [多模式匹配](code/balance/README_RULE.md) + * [路由统计](code/balancecount/README.md) * [动态配置](code/dynamic/README.md) @@ -82,9 +80,35 @@ * [页面代理插件](code/pageproxy/README.md) + * [使用配置](usage/pageproxy/README.md) + * [动态证书插件](code/ssl/README.md) - * [同步器插件](code/sync/README.md) + * [使用配置](usage/ssl/README.md) + + * [登陆认证插件](code/auth/README.md) + + * [使用配置](usage/auth/README.md) + + * [跨域设置插件](code/cors/README.md) + + * [使用配置](usage/cors/README.md) + + * [日志分析插件](code/loganalyze/README.md) + + * [使用配置](usage/loganalyze/README.md) + + * [链路追踪插件](code/tracing/README.md) + + * [使用配置](usage/tracing/README.md) + + * [自检调试插件](code/healthdebug/README.md) + + * [使用配置](usage/healthdebug/README.md) + + * [同步预热插件](code/sync/README.md) + + * [使用配置](usage/sync/README.md) * [字段同步](code/sync/README_FIELDS.md) @@ -92,11 +116,15 @@ * [耗时告警插件](code/timealert/README.md) + * [使用配置](usage/timealert/README.md) + * [日志告警](code/timealert/README_LOG.md) * [邮件告警](code/timealert/README_EMIAL.md) - * [集群管理插件](code/cluster/README_CLUSTER.md) + * [集群节点插件](code/cluster/README_CLUSTER.md) + + * [使用配置](usage/cluster/README.md) * [主从节点](code/cluster/README_NODE.md) @@ -121,5 +149,4 @@ * [提交PR](dev/README_PR.md) - -* [常见问题解答](qa/README.md) \ No newline at end of file +* [常见问题解答](qa/README.md) diff --git a/gitbook/code/auth/README.md b/gitbook/code/auth/README.md new file mode 100644 index 0000000..4bcf472 --- /dev/null +++ b/gitbook/code/auth/README.md @@ -0,0 +1,131 @@ +# 登陆认证插件 + +登陆认证插件主要为管理后台系统提供一个操作可控的权限认证,实现的方式是在 `tl_ops_process_before_init_rewrite` 阶段进行cookie或者header验证,对于需要拦截验证的链接进行验证,当然,拦截链接是可视化配置的,可以根据需要自定义 + +登陆插件数据主要分为两个子模块,一个是自定义配置模块,一个是账号密码模块 + + +### 拦截配置 + +我们先看一下拦截配置的数据定义,主要包含几个方面,拦截的api,拦截api白名单,拦截后返回的内容,登陆验证身份相关。 + +```lua +# 代码位置 : plugins/tl_ops_auth/tl_ops_plugin_constant.lua + +login = { + code = 403, -- 拦截命中返回错误码 + content_type = "text/html", -- 拦截命中返回错误内容格式 + content = default_content_page, -- 拦截命中返回内容 + intercept = { -- 需要拦截的api列表 + "/tlopsmanage/", + "/tlops/", + }, + filter = { -- 不拦截的api列表 + "/tlops/auth/login", + "/tlopsmanage/lib/", + }, + auth_time = 3600, -- 登陆后session有效时间 + auth_cid = "_tl_t", -- 登陆后cookie值key + auth_hid = "Tl-Auth-Rid", -- 登陆后header值key +}, +``` + + +### 账号配置 + +我们先看看账号数据定义,账号配置比较简单,只需要配置账号密码就行了,也可以在管理后台界面添加修改 + +```lua +# 代码位置 : plugins/tl_ops_auth/tl_ops_plugin_constant.lua + +list = { + { + id = 1, + username = "admin", + password = "admin", + }, + { + id = 2, + username = "test", + password = "test" + } +} +``` + +下面看看主要的实现逻辑,在rewrite阶段优先校验身份 + +```lua +# 代码位置 : plugins/tl_ops_auth/tl_ops_plugin_core.lua + +function _M:tl_ops_process_before_init_rewrite(ctx) + + -- 登录态校验 + auth:auth_core(ctx) + + return true, "ok" +end +``` + +进入 `auth_core` 方法,看实现逻辑为拿到设置配置后,判断当前uri是否需要拦截,如果需要拦截, 判断cookie或者header中的sessionkey是否有效, +如果无效,则是没有登陆,返回自定义的配置内容。 + +```lua +# 代码位置 : plugins/tl_ops_auth/auth.lua + + +function _M:auth_core(ctx) + + local login_str, _ = cache:get(constant.cache_key.login) + if not login_str then + tlog:err("auth_core get login cache err login_str=",login_str,",err=",_) + return + end + + local login, _ = cjson.decode(login_str) + if not login then + tlog:err("auth_core decode login cache err login=",login,",err=",_) + return + end + + -- 处理白名单 + for i, filter_ui in ipairs(login.filter) do + if ngx.re.find(ctx.request_uri, filter_ui, 'jo') then + return + end + end + + -- 处理拦截名单uri + if not uri_in_intercept_uri(ctx) then + return + end + + -- cookie校验 + local cookie_utils = require("lib.cookie"):new(); + local auth_cid, _ = cookie_utils:get(login.auth_cid); + if auth_cid ~= nil and auth_cid then + local session = self:auth_get_session(auth_cid) + if session then + return + end + end + + -- header校验 + local headers = ngx.req.get_headers() + local auth_hid = headers[login.auth_hid] + if auth_hid ~= nil then + local session = self:auth_get_session(auth_hid) + if session then + return + end + end + + tlog:dbg("req uri no auth, uri=",ctx.request_uri) + + utils:set_ngx_req_return_content( + login.code, + login.content, + login.content_type + ) + return +end +``` diff --git a/gitbook/code/balance/README.md b/gitbook/code/balance/README.md index c77cb2a..4520eda 100644 --- a/gitbook/code/balance/README.md +++ b/gitbook/code/balance/README.md @@ -1,6 +1,6 @@ # 负载均衡 -负载均衡的实现是本身nginx是支持配置多种轮询机制的,如权重,随机,备份等。tl-ops-manage提供的负载策略是更加细化的负载。目前支持几种策略 `api最长前缀正则匹配负载`,`cookie键值对匹配负载`,`请求参数键值对匹配负载`,`请求头部键值对匹配负载`,以及每种策略下支持两种模式的动态切换,`指定节点负载` ,`随机节点负载`。 +负载均衡的实现是本身nginx是支持配置多种轮询机制的,如权重,随机,备份等。tl-ops-manage提供的负载策略是更加细化的负载。目前支持几种策略 `api最长前缀正则匹配负载`,`cookie键值对匹配负载`,`请求参数键值对匹配负载`,`请求头部键值对匹配负载`,`请求Body参数匹配负载`以及每种策略下支持两种模式的动态切换,`指定节点负载` ,`随机节点负载`。 在服务节点列表中,所有节点是依赖健康检查动态上下线。上线节点加入负载列表,下线节点剔除负载列表。在负载列表中的所有有效节点,将被用作根据负载策略进行负载。 @@ -92,9 +92,10 @@ end 接下来,我们看回负载核心逻辑代码 : `tl_ops_balance_core_filter`,可以看到先获取当前所有服务节点,然后根据负载策略依次匹配,直到命中规则,得到具体节点。得到具体节点后,通过ctx保存节点,然后在balance阶段转发到具体节点 -策略匹配顺序为 : `api策略 > 请求参数策略 > 请求cookie策略 > 请求头策略 `。 +策略匹配顺序为 : `api策略 > 请求参数策略 > 请求cookie策略 > 请求头策略 > 请求Body参数策略`。 + +在决定执行某一种策略后,会根据设置的负载优先模式(当前有 优先host,优先api两种),进行模式优先匹配 -匹配到具体规则后,转而匹配域名,如果域名匹配也命中,说明当前请求应该被此条规则所配置的节点处理。 当前在实际负载前,应该要考虑当前节点所配置的流控策略,在流控限制下,如果能拿到令牌或正常留出漏桶,说明当前请求已经被允许转发到上游服务了,当然,如果此时,服务状态不佳,不能正常处理请求,那么就无需转发请求,直接丢弃即可。 @@ -121,41 +122,49 @@ function _M:tl_ops_balance_core_filter(ctx) local balance_mode = "api" -- 先走api负载 - local node, node_state, node_id, host = tl_ops_balance_core_api.tl_ops_balance_api_service_matcher(service_list_table) + local node, node_state, node_id, host, rule_match_mode = tl_ops_balance_core_api.tl_ops_balance_api_service_matcher(service_list_table) if not node then -- api不匹配,走param负载 balance_mode = "param" - node, node_state, node_id, host = tl_ops_balance_core_param.tl_ops_balance_param_service_matcher(service_list_table) + node, node_state, node_id, host, rule_match_mode = tl_ops_balance_core_param.tl_ops_balance_param_service_matcher(service_list_table) if not node then -- param不匹配,走cookie负载 balance_mode = "cookie" - node, node_state, node_id, host = tl_ops_balance_core_cookie.tl_ops_balance_cookie_service_matcher(service_list_table) + node, node_state, node_id, host, rule_match_mode = tl_ops_balance_core_cookie.tl_ops_balance_cookie_service_matcher(service_list_table) if not node then -- cookie不匹配,走header负载 balance_mode = "header" - node, node_state, node_id, host = tl_ops_balance_core_header.tl_ops_balance_header_service_matcher(service_list_table) + node, node_state, node_id, host, rule_match_mode = tl_ops_balance_core_header.tl_ops_balance_header_service_matcher(service_list_table) if not node then - -- 无匹配 - tl_ops_err_content:err_content_rewrite_to_balance("", "empty", balance_mode, tl_ops_constant_balance.cache_key.mode_empty) - return + -- header不匹配,走body负载 + balance_mode = "body" + + node, node_state, node_id, host, rule_match_mode = tl_ops_balance_core_body.tl_ops_balance_body_service_matcher(service_list_table) + if not node then + -- 无匹配 + tl_ops_err_content:err_content_rewrite_to_balance("", "empty", balance_mode, tl_ops_constant_balance.cache_key.mode_empty) + return + end end end end end - -- 域名负载 - if host == nil or host == '' then - tl_ops_err_content:err_content_rewrite_to_balance("", "nil", balance_mode, tl_ops_constant_balance.cache_key.host_empty) - return - end + if rule_match_mode and rule_match_mode == api_match_mode.api then + -- 域名负载 + if host == nil or host == '' then + tl_ops_err_content:err_content_rewrite_to_balance("", "nil", balance_mode, tl_ops_constant_balance.cache_key.host_empty) + return + end - -- 域名匹配 - if host ~= "*" and host ~= ngx.var.host then - tl_ops_err_content:err_content_rewrite_to_balance("", "pass", balance_mode, tl_ops_constant_balance.cache_key.host_pass) - return + -- 域名匹配 + if host ~= "*" and host ~= ngx.var.host then + tl_ops_err_content:err_content_rewrite_to_balance("", "pass", balance_mode, tl_ops_constant_balance.cache_key.host_pass) + return + end end -- 流控介入 @@ -171,7 +180,7 @@ function _M:tl_ops_balance_core_filter(ctx) return end end - + -- 漏桶流控 if depend == tl_ops_constant_limit.depend.leak then local leak_result = tl_ops_limit_fuse_leak_bucket.tl_ops_limit_leak( node.service, node_id) @@ -205,13 +214,9 @@ function _M:tl_ops_balance_core_filter(ctx) ctx.tlops_ups_node = node ctx.tlops_ups_node_id = node_id ctx.tlops_ups_mode = balance_mode - - return end - - -- 请求负载分发 function _M:tl_ops_balance_core_balance(ctx) @@ -233,9 +238,9 @@ function _M:tl_ops_balance_core_balance(ctx) end shared:incr(limit_req_succ_count_key, 1) - ngx.header['Tl-Proxy-Server'] = tlops_ups_node.service .. ":" .. tlops_ups_node.name; - ngx.header['Tl-Proxy-State'] = "online" - ngx.header['Tl-Proxy-Mode'] = tlops_ups_mode + ngx.header[tl_ops_constant_balance.proxy_server] = tlops_ups_node.service .. ":" .. tlops_ups_node.name; + ngx.header[tl_ops_constant_balance.proxy_state] = "online" + ngx.header[tl_ops_constant_balance.proxy_mode] = tlops_ups_mode local ok, err = ngx_balancer.set_current_peer(tlops_ups_node.ip, tlops_ups_node.port) if ok then @@ -243,7 +248,6 @@ function _M:tl_ops_balance_core_balance(ctx) end end - ``` 需要注意的点,负载中出现的各种情况都有对应的返回码,需要自行配置,以上就是负载核心思路,下面我将对不同策略以及每种策略下的不同模式进行说明 diff --git a/gitbook/code/balance/README_RULE.md b/gitbook/code/balance/README_RULE.md index 2054c90..dfcb2cb 100644 --- a/gitbook/code/balance/README_RULE.md +++ b/gitbook/code/balance/README_RULE.md @@ -7,69 +7,116 @@ ```lua # 代码位置 : balance/tl_ops_balance_core_api.lua -local tl_ops_balance_api_service_matcher = function(service_list_table) - local matcher = nil - local node = nil + +-- 处理匹配逻辑 +local tl_ops_balance_api_matcher_mode = function (matcher, request_uri, obj) + local match_mode = obj.match_mode + if not match_mode then + match_mode = tl_ops_match_mode.reg + end + -- 正则匹配模式 + if match_mode == tl_ops_match_mode.reg or match_mode == tl_ops_match_mode.regi or match_mode == tl_ops_match_mode.regid then + local from, to , _ = find(request_uri , obj.url , match_mode); + if from and to then + local sub = string.sub(request_uri, from, to) + if sub then + if not matcher or not matcher.url then + matcher = obj + end + if matcher.url and #sub > #matcher.url then + matcher = obj + end + end + end + end + -- 全文匹配 + if match_mode == tl_ops_match_mode.all then + if request_uri == obj.url then + matcher = obj; + end + end + + return matcher +end + +-- 获取命中的api路由项 +local tl_ops_balance_api_get_matcher_rule = function(api_list_table, rule, rule_match_mode) + local matcher = nil; + local matcher_list = api_list_table[rule] + + if not matcher_list then + return nil + end -- 获取当前url local request_uri = tl_ops_utils_func:get_req_uri(); + -- 获取当前host + local cur_host = ngx.var.host; + + for i, obj in pairs(matcher_list) do + repeat + if rule_match_mode == tl_ops_constant_balance_api.mode.host then + -- 如果是优先host规则匹配,先剔除不属于当前host的规则 + if obj.host == nil or obj.host == '' then + break + end + if obj.host ~= "*" and obj.host ~= cur_host then + break + end + end + + matcher = tl_ops_balance_api_matcher_mode(matcher, request_uri, obj) + + break + until true + end + + return matcher +end + + +local tl_ops_balance_api_service_matcher = function(service_list_table) + local matcher = nil + local node = nil + + -- 规则匹配模式 + local rule_match_mode, _ = cache_api:get(tl_ops_constant_balance_api.cache_key.rule_match_mode); + if not rule_match_mode then + -- 默认以host优先匹配 + rule_match_mode = tl_ops_constant_balance_api.mode.host; + end + -- api路由策略 local api_rule, _ = cache_api:get(tl_ops_constant_balance_api.cache_key.rule); if not api_rule then - return nil, nil, nil, nil + return nil, nil, nil, nil, rule_match_mode end - + -- api配置列表 local api_list, _ = cache_api:get(tl_ops_constant_balance_api.cache_key.list); if not api_list then - return nil, nil, nil, nil + return nil, nil, nil, nil, rule_match_mode end local api_list_table = cjson.decode(api_list); if not api_list_table then - return nil, nil, nil, nil - end + return nil, nil, nil, nil, rule_match_mode + end -- 根据路由当前策略进行路由, 返回正则命中的api if api_rule == tl_ops_constant_balance_api.rule.point then - local point = api_list_table.point - - for i, obj in pairs(point) do - local from, to , _ = find(request_uri , obj.url , 'joi'); - if from and to then - local sub = string.sub(request_uri, from, to) - if sub then - if not matcher or not matcher.url then - matcher = obj - end - if matcher.url and #sub > #matcher.url then - matcher = obj - end - end - end - end + matcher = tl_ops_balance_api_get_matcher_rule( + api_list_table, tl_ops_constant_balance_api.rule.point, rule_match_mode + ); elseif api_rule == tl_ops_constant_balance_api.rule.random then - local random = api_list_table.random - - for i, obj in pairs(random) do - local from, to , _ = find(request_uri , obj.url , 'joi'); - if from and to then - local sub = string.sub(request_uri, from, to) - if sub then - if not matcher or not matcher.url then - matcher = obj - end - if matcher.url and #sub > #matcher.url then - matcher = obj - end - end - end - end + matcher = tl_ops_balance_api_get_matcher_rule( + api_list_table, tl_ops_constant_balance_api.rule.random, rule_match_mode + ); end if not matcher or type(matcher) ~= 'table' then - return nil, nil, nil, nil + return nil, nil, nil, nil, rule_match_mode end local service_list = service_list_table[matcher.service] @@ -85,10 +132,11 @@ local tl_ops_balance_api_service_matcher = function(service_list_table) if node_id ~= nil then node = service_list[tonumber(node_id) + 1] else - return nil, nil, nil, host + return nil, nil, nil, host, rule_match_mode end -- 服务内随机 elseif api_rule == tl_ops_constant_balance_api.rule.random then + local request_uri = tl_ops_utils_func:get_req_uri(); math.randomseed(#request_uri) node_id = tonumber(math.random(0,1) % #service_list_table[matcher.service]) + 1 node = service_list[node_id] @@ -97,8 +145,15 @@ local tl_ops_balance_api_service_matcher = function(service_list_table) -- 获取当前节点健康状态 local key = tl_ops_utils_func:gen_node_key(tl_ops_constant_health.cache_key.state, matcher.service, node_id) local node_state , _ = shared:get(key) + + + -- 需要重写url + local rewrite_url = matcher.rewrite_url + if rewrite_url and rewrite_url ~= '' then + ngx.req.set_uri(rewrite_url, false) + end - return node, node_state, node_id, host + return node, node_state, node_id, host, rule_match_mode end ``` diff --git a/gitbook/code/cors/README.md b/gitbook/code/cors/README.md new file mode 100644 index 0000000..66e0e05 --- /dev/null +++ b/gitbook/code/cors/README.md @@ -0,0 +1,3 @@ +# 跨域设置插件 + +文档待补充 \ No newline at end of file diff --git a/gitbook/code/fuselimit/README.md b/gitbook/code/fuselimit/README.md index 0b8723e..c37546f 100644 --- a/gitbook/code/fuselimit/README.md +++ b/gitbook/code/fuselimit/README.md @@ -6,11 +6,13 @@ ### 为什么称其为自动化熔断 ? ``` -因为我们在判断服务是否处于 `性能不佳` 状态,而不能及时处理请求时,是需要依据一些服务本身的`健康状态`或实际`负载率`来衡量是否将服务降级,但是我们在进行服务降级后,此服务恢复正常,那么此时该服务应该被升级,用于处理更多请求。而此 ‘服务升级/降级’ 步骤应该实现系统自动化。 +因为我们在判断服务是否处于 `性能不佳` 状态,而不能及时处理请求时,是需要依据一些服务本身的`健康状态`或实际`负载率`来衡量是否将服务降级, +但是我们在进行服务降级后,此服务恢复正常,那么此时该服务应该被升级,用于处理更多请求。而此 ‘服务升级/降级’ 步骤应该实现系统自动化。 ``` -对于服务自动化熔断来说,其应该是根据节点 ‘状态’ 来进行一种服务降级的手段。在节点负载过高时,应该对节点减少流量的进入,在服务性能较优时,增加流量的进入,而控制流量的进入就需要用到一些流控手段。所以我将其组合设计。 +对于服务自动化熔断来说,其应该是根据节点 ‘状态’ 来进行一种服务降级的手段。在节点负载过高时,应该对节点减少流量的进入, +在服务性能较优时,增加流量的进入,而控制流量的进入就需要用到一些流控手段。所以我将其组合设计。 对于这两种服务治理手段,在各大框架中也有不少应用,如java的spring cloud Hystrix,其实现也是做到了自动化熔断恢复。 diff --git a/gitbook/code/fuselimit/README_BALANCE.md b/gitbook/code/fuselimit/README_BALANCE.md index b2965e4..6b00dcb 100644 --- a/gitbook/code/fuselimit/README_BALANCE.md +++ b/gitbook/code/fuselimit/README_BALANCE.md @@ -10,29 +10,29 @@ # 代码位置 : balance/tl_ops_balance_core.lua -- 流控介入 -local depend = tl_ops_balance_core_get_limiter(node.service, node_id) -if depend then - -- 令牌桶流控 - if depend == tl_ops_constant_limit.depend.token then - local token_result = tl_ops_limit_fuse_token_bucket.tl_ops_limit_token( node.service, node_id) - if not token_result or token_result == false then - ngx.header['Tl-Proxy-Server'] = ""; - ngx.header['Tl-Proxy-State'] = "t-limit" - ngx.header['Tl-Proxy-Mode'] = balance_mode - ngx.exit(503) - end - end - - -- 漏桶流控 - if depend == tl_ops_constant_limit.depend.leak then - local leak_result = tl_ops_limit_fuse_leak_bucket.tl_ops_limit_leak( node.service, node_id) - if not leak_result or leak_result == false then - ngx.header['Tl-Proxy-Server'] = ""; - ngx.header['Tl-Proxy-State'] = "l-limit" - ngx.header['Tl-Proxy-Mode'] = balance_mode - ngx.exit(503) - end - end +if tl_ops_manage_env.balance.limiter then + local depend = tl_ops_limit.tl_ops_limit_get_limiter(node.service, node_id) + if depend then + -- 令牌桶流控 + if depend == tl_ops_constant_limit.depend.token then + local token_result = tl_ops_limit_fuse_token_bucket.tl_ops_limit_token( node.service, node_id) + if not token_result or token_result == false then + balance_count:tl_ops_balance_count_incr_fail(node.service, node_id) + tl_ops_err_content:err_content_rewrite_to_balance("", "t-limit", balance_mode, tl_ops_constant_balance.cache_key.token_limit) + return + end + end + + -- 漏桶流控 + if depend == tl_ops_constant_limit.depend.leak then + local leak_result = tl_ops_limit_fuse_leak_bucket.tl_ops_limit_leak( node.service, node_id) + if not leak_result or leak_result == false then + balance_count:tl_ops_balance_count_incr_fail(node.service, node_id) + tl_ops_err_content:err_content_rewrite_to_balance("", "l-limit", balance_mode, tl_ops_constant_balance.cache_key.leak_limit) + return + end + end + end end ``` @@ -45,17 +45,18 @@ end ```lua # 代码位置 : limit/fuse/tl_ops_limit_fuse_token_bucket.lua +-- get token with lazy generate -- block 取用令牌数量 -local tl_ops_limit_token = function( service_name, node_id ) +local tl_ops_limit_token_bucket = function( block ) + ... -- 取出令牌 if token_bucket > block then - local ok, _ = shared:incr(token_bucket_key, -block) + local ok, _ = shared:incr(self.keys.token_bucket, -block) if not ok then return false end - return true end @@ -68,15 +69,15 @@ local tl_ops_limit_token = function( service_name, node_id ) end local new_token_bucket = math.min(token_bucket + duration_token_bucket, capacity) - + -- 令牌还是不够 if new_token_bucket < block then - local ok, _ = shared:set(token_bucket_key, new_token_bucket) + local ok, _ = shared:set(self.keys.token_bucket, new_token_bucket) if not ok then return false end - - local ok, _ = shared:set(pre_time_key, cur_time) + + local ok, _ = shared:set(self.keys.pre_time, cur_time) if not ok then return false end @@ -85,18 +86,19 @@ local tl_ops_limit_token = function( service_name, node_id ) end -- 移除一个令牌 - local ok, _ = shared:set(token_bucket_key, new_token_bucket - block) + local ok, _ = shared:set(self.keys.token_bucket, new_token_bucket - block) if not ok then return false end - local ok, _ = shared:set(pre_time_key, cur_time) + local ok, _ = shared:set(self.keys.pre_time, cur_time) if not ok then return false end - + return true end + ``` @@ -109,41 +111,40 @@ end ```lua # 代码位置 : limit/fuse/tl_ops_limit_fuse_leak_bucket.lua --- block 取用漏桶数量 -local tl_ops_limit_leak = function( service_name, node_id ) - +-- get leak with lazy generate +-- block 漏桶流速单位 +local tl_ops_limit_leak_bucket = function( block ) + ... -- 当前堆积量 - local leak_bucket_key = tl_ops_utils_func:gen_node_key(leak_mode.cache_key.leak_bucket, service_name, node_id) - local leak_bucket, _ = shared:get(leak_bucket_key) + local leak_bucket, _ = shared:get(self.keys.leak_bucket) if not leak_bucket then - local res, _ = shared:set(leak_bucket_key, 0) - if not res then - return false - end leak_bucket = 0 end - -- 漏桶当前可堆积请求量 = 当前堆积量 - (在此时间区间应该被漏出的请求量) + -- 漏桶当前时间区间内的剩余请求量 = 当前堆积量 - (在此时间区间应该被漏出的请求量) -- == - -- 漏桶当前可堆积请求量 = 当前堆积量 - (距离上次时间差 * 漏出速率) + -- 漏桶当前时间区间内的剩余请求量 = 当前堆积量 - (距离上次时间差 * 生成速率) ngx.update_time() local cur_time = ngx.now() - local lave_leak_bucket = math.max(leak_bucket - (cur_time - pre_time) * rate, 0) + local lave_leak_bucket = leak_bucket - (cur_time - pre_time) * rate + if lave_leak_bucket <= 0 then + return false + end -- 溢出 - if lave_leak_bucket + block > capacity then + if lave_leak_bucket + 1 > capacity then return false end - local new_leak_bucket = math.min(capacity, lave_leak_bucket + block) - local ok, _ = shared:set(leak_bucket_key, new_leak_bucket) + local new_leak_bucket = math.max(capacity, lave_leak_bucket) + local ok, _ = shared:set(self.keys.leak_bucket, new_leak_bucket) if not ok then return false end - local ok, _ = shared:set(pre_time_key, cur_time) + local ok, _ = shared:set(self.keys.pre_time, cur_time) if not ok then return false end diff --git a/gitbook/code/fuselimit/README_FUSE.md b/gitbook/code/fuselimit/README_FUSE.md index 9be6f91..1b6168f 100644 --- a/gitbook/code/fuselimit/README_FUSE.md +++ b/gitbook/code/fuselimit/README_FUSE.md @@ -145,9 +145,11 @@ tl_ops_limit_fuse_check_nodes = function ( conf ) if upgrade then upgrade_count = upgrade_count + 1 + tlog:dbg("node state upgrade : service_name=",service_name, ",node_name=",nodes[i].name, ",mode=",mode, ",upgrade_count=",upgrade_count) tl_ops_limit_fuse_node_upgrade( conf, node_id ) else degrade_count = degrade_count + 1 + tlog:dbg("node state degrade : service_name=",service_name, ",node_name=",nodes[i].name, ",mode=",mode, ",degrade_count=",degrade_count) tl_ops_limit_fuse_node_degrade( conf, node_id ) end end diff --git a/gitbook/code/fuselimit/README_LIMIT.md b/gitbook/code/fuselimit/README_LIMIT.md index d73ad40..430e817 100644 --- a/gitbook/code/fuselimit/README_LIMIT.md +++ b/gitbook/code/fuselimit/README_LIMIT.md @@ -20,6 +20,9 @@ local tl_ops_limit_token_expand = function( service_name, node_id ) local token_mode = tl_ops_limit_token_mode( service_name, node_id) + if not token_mode then + return false + end local capacity_key = tl_ops_utils_func:gen_node_key(token_mode.cache_key.capacity, service_name, node_id) local capacity = shared:get(capacity_key) @@ -31,10 +34,6 @@ local tl_ops_limit_token_expand = function( service_name, node_id ) capacity = token_mode.options.capacity end - if capacity <= 1 then - return false - end - local expand_key = tl_ops_utils_func:gen_node_key(token_mode.cache_key.expand, service_name, node_id) local expand = shared:get(expand_key) if not expand then @@ -45,7 +44,10 @@ local tl_ops_limit_token_expand = function( service_name, node_id ) expand = token_mode.options.expand end + tlog:dbg("token expand=",expand, ",service_name=", service_name, ",node_id=",node_id,",expand_key=", expand_key) + -- 扩容量 = 当前桶容量 * 比例 + -- 扩容最大容量暂时不限制大小,理论上扩容前,必定伴随一次缩容,所以不最大容量会超过设置的最大容量 local expand_capacity = capacity * expand local capacity_key = tl_ops_utils_func:gen_node_key(token_mode.cache_key.capacity, service_name, node_id) diff --git a/gitbook/code/health/README.md b/gitbook/code/health/README.md index d33c163..174032a 100644 --- a/gitbook/code/health/README.md +++ b/gitbook/code/health/README.md @@ -15,6 +15,9 @@ check_timeout = 1000, #自检心跳包接收超时时间,默认单位/ms check_content = "GET / HTTP/1.0", #自检心跳包内容,可自定义,但是需要被检方处理兼容。 check_service_name = "product" #自检服务名称 + check_success_status = { #自检返回成功状态, 如 201,202(代表成功) + 200 + }, } ``` diff --git a/gitbook/code/health/README_CHECK.md b/gitbook/code/health/README_CHECK.md index 3d144b9..8298430 100644 --- a/gitbook/code/health/README_CHECK.md +++ b/gitbook/code/health/README_CHECK.md @@ -69,6 +69,7 @@ tl_ops_health_check_nodes = function (conf) local bytes, _ = sock:send(check_content .. "\r\n\r\n\r\n") if not bytes then tlog:err("tl_ops_health_check_nodes failed to send socket: ", _) + sock:close() tl_ops_health_check_node_failed(conf, node_id, node) break end @@ -76,19 +77,21 @@ tl_ops_health_check_nodes = function (conf) tlog:dbg("tl_ops_health_check_nodes send socket ok : byte=", bytes) -- socket反馈 - local receive_line, _ = sock:receive() - if not receive_line then + local receive_10k, _ = sock:receiveany(10240) + if not receive_10k then if _ == "check_timeout" then tlog:err("tl_ops_health_check_nodes socket check_timeout: ", _) - sock:close() end + + tlog:err("tl_ops_health_check_nodes socket receive failed: ", receive_10k) + sock:close() tl_ops_health_check_node_failed(conf, node_id, node) break end - tlog:dbg("tl_ops_health_check_nodes receive socket ok : ", receive_line) + tlog:dbg("tl_ops_health_check_nodes receive socket ok : ", receive_10k) - local from, to, _ = ngx.re.find(receive_line, [[^HTTP/\d+\.\d+\s+(\d+)]], "joi", nil, 1) + local from, to, _ = find(receive_10k, [[^HTTP/\d+\.\d+\s+(\d+)]], "joi", nil, 1) if not from then tlog:err("tl_ops_health_check_nodes ngx.re.find receive err: ", from, to, _) sock:close() @@ -97,7 +100,7 @@ tl_ops_health_check_nodes = function (conf) end -- 心跳状态 - local status = tonumber(string.sub(receive_line, from, to)) + local status = tonumber(string.sub(receive_10k, from, to)) tlog:dbg("tl_ops_health_check_nodes get status ok ,name=" ,name, ", status=" , status) local statusPass = false; @@ -147,6 +150,8 @@ tl_ops_health_check_node_ok = function (conf, node_id, node) local key = tl_ops_utils_func:gen_node_key(tl_ops_constant_health.cache_key.success, check_service_name, node_id) local cur_success_count, _ = shared:get(key) + tlog:dbg("tl_ops_health_check_node_ok success key= " , key ,", cur_success_count=" , cur_success_count) + if not cur_success_count then cur_success_count = 1 local ok, _ = shared:set(key, cur_success_count) @@ -166,6 +171,8 @@ tl_ops_health_check_node_ok = function (conf, node_id, node) key = tl_ops_utils_func:gen_node_key(tl_ops_constant_health.cache_key.failed, check_service_name, node_id) local fails, _ = shared:get(key) + tlog:dbg("tl_ops_health_check_node_ok success key= " , key , ",cur_success_count=", cur_success_count, ", check_failed_max_count=" , fails) + if not fails or fails == 0 then if _ then tlog:err("tl_ops_health_check_node_ok failed to get node nok key: " , key) @@ -183,15 +190,19 @@ tl_ops_health_check_node_ok = function (conf, node_id, node) if not node.state and cur_success_count >= check_success_max_count then local name = node.port .. ":" .. node.ip + + tlog:dbg("tl_ops_health_check_node_ok success count > max success count , state=",node.state," cur_success_count=",cur_success_count, ",ip=" .. node.ip .. ":" .. node.port) + key = tl_ops_utils_func:gen_node_key(tl_ops_constant_health.cache_key.state, check_service_name, node_id) local ok, _ = shared:set(key, true) if not ok then tlog:err("tl_ops_health_check_node_ok failed to set node down state:", _) end node.state = true + + conf.service_version = tl_ops_health_check_version.incr_service_version(check_service_name); - ... - + tlog:dbg("tl_ops_health_check_node_ok conf.service_version=" , conf.service_version) end tlog:dbg("tl_ops_health_check_node_ok end ,node=" , node) @@ -218,6 +229,8 @@ tl_ops_health_check_node_failed = function (conf, node_id, node) local key = tl_ops_utils_func:gen_node_key(tl_ops_constant_health.cache_key.failed, check_service_name, node_id) local cur_failed_count, _ = shared:get(key) + tlog:dbg("tl_ops_health_check_node_failed failed key= " , key ,", cur_failed_count=" , cur_failed_count) + if not cur_failed_count then cur_failed_count = 1 local ok, _ = shared:set(key, cur_failed_count) @@ -236,6 +249,8 @@ tl_ops_health_check_node_failed = function (conf, node_id, node) if cur_failed_count == 1 then key = tl_ops_utils_func:gen_node_key(tl_ops_constant_health.cache_key.success, check_service_name, node_id) local succ, _ = shared:get(key) + + tlog:dbg("tl_ops_health_check_node_failed success key= " , key ,", succ_count=" , succ) if not succ or succ == 0 then tlog:err("tl_ops_health_check_node_failed failed to get node check_success_max_count key: " , key , " or check_success_max_count = 0") @@ -252,20 +267,22 @@ tl_ops_health_check_node_failed = function (conf, node_id, node) if node.state and cur_failed_count > check_failed_max_count then local name = node.ip .. ":" .. node.port + tlog:dbg("tl_ops_health_check_node_failed failed count > max failed count , cur_failed_count=",cur_failed_count, ",ip=" .. node.ip .. ":" .. node.port) + key = tl_ops_utils_func:gen_node_key(tl_ops_constant_health.cache_key.state, check_service_name, node_id) local ok, _ = shared:set(key, nil) if not ok then tlog:err("tl_ops_health_check_node_failed failed to set node down state:", _) end node.state = false + + conf.service_version = tl_ops_health_check_version.incr_service_version(check_service_name); - ... - + tlog:dbg("tl_ops_health_check_node_failed conf.service_version=" , conf.service_version) end tlog:dbg("tl_ops_health_check_node_failed end ,node=" , node) end - ``` diff --git a/gitbook/code/healthdebug/README.md b/gitbook/code/healthdebug/README.md new file mode 100644 index 0000000..d59f519 --- /dev/null +++ b/gitbook/code/healthdebug/README.md @@ -0,0 +1,3 @@ +# 健康自检调试插件 + +文档待补充 \ No newline at end of file diff --git a/gitbook/code/loganalyze/README.md b/gitbook/code/loganalyze/README.md new file mode 100644 index 0000000..b9b3183 --- /dev/null +++ b/gitbook/code/loganalyze/README.md @@ -0,0 +1,3 @@ +# 日志文件分析插件 + +文档待补充 \ No newline at end of file diff --git a/gitbook/code/plugin/README.md b/gitbook/code/plugin/README.md index 3190b22..15c6c02 100644 --- a/gitbook/code/plugin/README.md +++ b/gitbook/code/plugin/README.md @@ -32,6 +32,7 @@ init_worker_by_lua_block { function _M:tl_ops_process_init() -- 加载所有插件 m_plugin:tl_ops_process_load_plugins(); + _M.plugins = m_plugin:tl_ops_process_get_plugins() end diff --git a/gitbook/code/plugin/README_HOOK.md b/gitbook/code/plugin/README_HOOK.md index b8f2d31..8c1a3a9 100644 --- a/gitbook/code/plugin/README_HOOK.md +++ b/gitbook/code/plugin/README_HOOK.md @@ -19,9 +19,9 @@ init_worker阶段和其他阶段不太一样,此阶段存在多worker竞争, ```lua # 代码位置 : plugins/tl_ops_plugin.lua --- init_worker阶段执行 -function _M:tl_ops_process_init_worker() - local lock_key = "tl_ops_plugin_process_worker_lock" +-- init_worker前置阶段执行 +function _M:tl_ops_process_before_init_worker(ctx) + local lock_key = "tl_ops_plugin_process_before_worker_lock" local lock_time = 5 if not tl_ops_utils_func:tl_ops_worker_lock(lock_key, lock_time) then return @@ -29,17 +29,21 @@ function _M:tl_ops_process_init_worker() for i = 1, #self.plugins do local plugin = self.plugins[i] - if type(plugin.func.tl_ops_process_init_worker) == 'function' then - local ok, _ = plugin.func:tl_ops_process_init_worker() - if not ok then - tlog:err("tl_ops_process_init_worker process err , name=",plugin.name, ", ",_) - else - tlog:dbg("tl_ops_process_init_worker process ok , name=",plugin.name, ", ",_) + local open = plugin.open_func and plugin.open_func() + if open then + if type(plugin.func.tl_ops_process_before_init_worker) == 'function' then + local ok, _ = plugin.func:tl_ops_process_before_init_worker(ctx) + if not ok then + tlog:err("tl_ops_process_before_init_worker process err , name=",plugin.name, ", ",_) + else + tlog:dbg("tl_ops_process_before_init_worker process ok , name=",plugin.name, ", ",_) + end end + else + tlog:dbg("tl_ops_process_before_init_worker process not open , name=",plugin.name) end end end - ``` @@ -53,20 +57,25 @@ end ```lua # 代码位置 : plugins/tl_ops_plugin.lua -function _M:tl_ops_process_init_ssl(ctx) +-- ssl前置阶段执行 +function _M:tl_ops_process_before_init_ssl(ctx) for i = 1, #self.plugins do local plugin = self.plugins[i] - if type(plugin.func.tl_ops_process_init_ssl) == 'function' then - local ok, _ = plugin.func:tl_ops_process_init_ssl(ctx) - if not ok then - tlog:err("tl_ops_process_init_ssl process err , name=",plugin.name, ", ",_) - else - tlog:dbg("tl_ops_process_init_ssl process ok , name=",plugin.name, ", ",_) + local open = plugin.open_func and plugin.open_func() + if open then + if type(plugin.func.tl_ops_process_before_init_ssl) == 'function' then + local ok, _ = plugin.func:tl_ops_process_before_init_ssl(ctx) + if not ok then + tlog:err("tl_ops_process_before_init_ssl process err , name=",plugin.name, ", ",_) + else + tlog:dbg("tl_ops_process_before_init_ssl process ok , name=",plugin.name, ", ",_) + end end + else + tlog:dbg("tl_ops_process_before_init_ssl process not open , name=",plugin.name) end end end - ``` ### tl_ops_process_*_init_rewrite @@ -78,17 +87,28 @@ end ```lua # 代码位置 : plugins/tl_ops_plugin.lua --- rewrite阶段执行 -function _M:tl_ops_process_init_rewrite() +-- rewrite前置阶段执行 +function _M:tl_ops_process_before_init_rewrite(ctx) for i = 1, #self.plugins do local plugin = self.plugins[i] - if type(plugin.func.tl_ops_process_init_rewrite) == 'function' then - local ok, _ = plugin.func:tl_ops_process_init_rewrite() - if not ok then - tlog:err("tl_ops_process_init_rewrite process err , name=",plugin.name, ", ",_) - else - tlog:dbg("tl_ops_process_init_rewrite process ok , name=",plugin.name, ", ",_) + local open = plugin.open_func and plugin.open_func() + + -- 插件api加载执行 + if plugin.api_func then + plugin.api_func(ctx) + end + + if open then + if type(plugin.func.tl_ops_process_before_init_rewrite) == 'function' then + local ok, _ = plugin.func:tl_ops_process_before_init_rewrite(ctx) + if not ok then + tlog:err("tl_ops_process_before_init_rewrite process err , name=",plugin.name, ", ",_) + else + tlog:dbg("tl_ops_process_before_init_rewrite process ok , name=",plugin.name, ", ",_) + end end + else + tlog:dbg("tl_ops_process_before_init_rewrite process not open , name=",plugin.name) end end end @@ -103,17 +123,22 @@ end ```lua # 代码位置 : plugins/tl_ops_plugin.lua --- access阶段执行 -function _M:tl_ops_process_init_access() +-- access前置阶段执行 +function _M:tl_ops_process_before_init_access(ctx) for i = 1, #self.plugins do local plugin = self.plugins[i] - if type(plugin.func.tl_ops_process_init_access) == 'function' then - local ok, _ = plugin.func:tl_ops_process_init_access() - if not ok then - tlog:err("tl_ops_process_init_access process err , name=",plugin.name, ", ",_) - else - tlog:dbg("tl_ops_process_init_access process ok , name=",plugin.name, ", ",_) + local open = plugin.open_func and plugin.open_func() + if open then + if type(plugin.func.tl_ops_process_before_init_access) == 'function' then + local ok, _ = plugin.func:tl_ops_process_before_init_access(ctx) + if not ok then + tlog:err("tl_ops_process_before_init_access process err , name=",plugin.name, ", ",_) + else + tlog:dbg("tl_ops_process_before_init_access process ok , name=",plugin.name, ", ",_) + end end + else + tlog:dbg("tl_ops_process_before_init_access process not open , name=",plugin.name) end end end @@ -128,17 +153,22 @@ end ```lua # 代码位置 : plugins/tl_ops_plugin.lua --- content阶段执行 -function _M:tl_ops_process_init_balancer() +-- balance前置阶段执行 +function _M:tl_ops_process_before_init_balancer(ctx) for i = 1, #self.plugins do local plugin = self.plugins[i] - if type(plugin.func.tl_ops_process_init_balancer) == 'function' then - local ok, _ = plugin.func:tl_ops_process_init_balancer() - if not ok then - tlog:err("tl_ops_process_init_balancer process err , name=",plugin.name, ", ",_) - else - tlog:dbg("tl_ops_process_init_balancer process ok , name=",plugin.name, ", ",_) + local open = plugin.open_func and plugin.open_func() + if open then + if type(plugin.func.tl_ops_process_before_init_balancer) == 'function' then + local ok, _ = plugin.func:tl_ops_process_before_init_balancer(ctx) + if not ok then + tlog:err("tl_ops_process_before_init_balancer process err , name=",plugin.name, ", ",_) + else + tlog:dbg("tl_ops_process_before_init_balancer process ok , name=",plugin.name, ", ",_) + end end + else + tlog:dbg("tl_ops_process_before_init_balancer process not open , name=",plugin.name) end end end @@ -154,17 +184,22 @@ end ```lua # 代码位置 : plugins/tl_ops_plugin.lua --- header阶段执行 -function _M:tl_ops_process_init_header() +-- header前置阶段执行 +function _M:tl_ops_process_before_init_header(ctx) for i = 1, #self.plugins do local plugin = self.plugins[i] - if type(plugin.func.tl_ops_process_init_header) == 'function' then - local ok, _ = plugin.func:tl_ops_process_init_header() - if not ok then - tlog:err("tl_ops_process_init_header process err , name=",plugin.name, ", ",_) - else - tlog:dbg("tl_ops_process_init_header process ok , name=",plugin.name, ", ",_) + local open = plugin.open_func and plugin.open_func() + if open then + if type(plugin.func.tl_ops_process_before_init_header) == 'function' then + local ok, _ = plugin.func:tl_ops_process_before_init_header(ctx) + if not ok then + tlog:err("tl_ops_process_before_init_header process err , name=",plugin.name, ", ",_) + else + tlog:dbg("tl_ops_process_before_init_header process ok , name=",plugin.name, ", ",_) + end end + else + tlog:dbg("tl_ops_process_before_init_header process not open , name=",plugin.name) end end end @@ -180,17 +215,22 @@ end ```lua # 代码位置 : plugins/tl_ops_plugin.lua --- body阶段执行 -function _M:tl_ops_process_init_body() +-- body前置阶段执行 +function _M:tl_ops_process_before_init_body(ctx) for i = 1, #self.plugins do local plugin = self.plugins[i] - if type(plugin.func.tl_ops_process_init_body) == 'function' then - local ok, _ = plugin.func:tl_ops_process_init_body() - if not ok then - tlog:err("tl_ops_process_init_body process err , name=",plugin.name, ", ",_) - else - tlog:dbg("tl_ops_process_init_body process ok , name=",plugin.name, ", ",_) + local open = plugin.open_func and plugin.open_func() + if open then + if type(plugin.func.tl_ops_process_before_init_body) == 'function' then + local ok, _ = plugin.func:tl_ops_process_before_init_body(ctx) + if not ok then + tlog:err("tl_ops_process_before_init_body process err , name=",plugin.name, ", ",_) + else + tlog:dbg("tl_ops_process_before_init_body process ok , name=",plugin.name, ", ",_) + end end + else + tlog:dbg("tl_ops_process_before_init_body process not open , name=",plugin.name) end end end @@ -206,17 +246,22 @@ end ```lua # 代码位置 : plugins/tl_ops_plugin.lua --- log阶段执行 -function _M:tl_ops_process_init_log() +-- log前置阶段执行 +function _M:tl_ops_process_before_init_log(ctx) for i = 1, #self.plugins do local plugin = self.plugins[i] - if type(plugin.func.tl_ops_process_init_log) == 'function' then - local ok, _ = plugin.func:tl_ops_process_init_log() - if not ok then - tlog:err("tl_ops_process_init_log process err , name=",plugin.name, ", ",_) - else - tlog:dbg("tl_ops_process_init_log process ok , name=",plugin.name, ", ",_) + local open = plugin.open_func and plugin.open_func() + if open then + if type(plugin.func.tl_ops_process_before_init_log) == 'function' then + local ok, _ = plugin.func:tl_ops_process_before_init_log(ctx) + if not ok then + tlog:err("tl_ops_process_before_init_log process err , name=",plugin.name, ", ",_) + else + tlog:dbg("tl_ops_process_before_init_log process ok , name=",plugin.name, ", ",_) + end end + else + tlog:dbg("tl_ops_process_before_init_log process not open , name=",plugin.name) end end end diff --git a/gitbook/code/plugin/README_LOAD.md b/gitbook/code/plugin/README_LOAD.md index 937a65a..017f773 100644 --- a/gitbook/code/plugin/README_LOAD.md +++ b/gitbook/code/plugin/README_LOAD.md @@ -1,6 +1,6 @@ # 插件加载器 -前面说到了在init阶段会加载所有插件,并将插件都缓存在一个全局变量 `tlops` 中,我们看回插件加载器 `tl_ops_process_load_plugins`,其核心逻辑是通过 `tl_ops_manage_env.lua`中配置的插件名称进行以此 require,并放入table的过程。 +前面说到了在init阶段会加载所有插件,并将插件都缓存在一个全局变量 `tlops` 中,我们看回插件加载器 `tl_ops_process_load_plugins`,其核心逻辑是通过 cache.get101("tl_ops_plugins_list") 获取到的配置的插件名称进行以此 require,并放入table的过程。 流程比较简单,代码如下。 @@ -8,77 +8,33 @@ # 代码位置 : plugins/tl_ops_plugin.lua --- 插件数据加载器 -local tl_ops_process_load_plugins_constant = function(name) - - local status, constant = pcall(require, "plugins.tl_ops_" .. name .. ".tl_ops_plugin_constant") - if status then - if plugin and type(constant) == 'table' then - return constant - else - tlog:dbg("tl_ops_process_load_plugins_constant constant err, name=",name,",constant=",constant) - end - else - tlog:dbg("tl_ops_process_load_plugins_constant status err, name=",name,",status=",status) - end - - return nil -end - - --- 插件启动加载器 -local tl_ops_process_load_plugins_func = function(name) - - local status, func = pcall(require, "plugins.tl_ops_" .. name .. ".tl_ops_plugin_core") - if status then - if func and type(func) == 'table' then - if type(func.new) == 'function' then - return func - else - tlog:dbg("tl_ops_process_load_plugins_func func no new func err, name=",name,",func=",func) - end - else - tlog:dbg("tl_ops_process_load_plugins_func func err, name=",name,",func=",func) - end - else - tlog:dbg("tl_ops_process_load_plugins_func status err, name=",name,",status=",status) - end - - return nil -end - - -- 插件加载器 function _M:tl_ops_process_load_plugins() - local open = tl_ops_manage_env.plugin.open - if not open then - tlog:dbg("tl_ops_process_load_plugins close") - return + local module_str, _ = cache_plugins_manage:get101(constant_plugins_manage.cache_key.list); + if not module_str or module_str == nil then + tlog:dbg("tl_ops_process_load_plugins no module, use constant default, default=",constant_plugins_manage.list) + module_str = cjson.encode(constant_plugins_manage.list) end - local module = tl_ops_manage_env.plugin.module - if not module then - tlog:dbg("tl_ops_process_load_plugins no module") - return + local module = cjson.decode(module_str) + if not module or module == nil then + tlog:err("tl_ops_process_load_plugins module decode err") + return; end for i = 1, #module do - local name = module[i] + local name = module[i].name - -- 先load数据 - local constant = tl_ops_process_load_plugins_constant(name) - - -- 在load启动器 - local func = tl_ops_process_load_plugins_func(name) + local plugin_data = plugin_load:tl_ops_plugin_load_by_name(name) - table.insert(self.plugins, { - name = name, - func = func:new(), - constant = constant - }) + table.insert(self.plugins, plugin_data) end - tlog:dbg("tl_ops_process_load_plugins , module=",module,",plugin=",self.plugins) + tlog:dbg("tl_ops_process_load_plugins , module=",module,",plugins=",self.plugins) end -``` \ No newline at end of file +``` + +### 备注 + +可能大家会对get101有点疑惑,这里我解释一下,plugin的加载我放在 `tl_ops_process_init` 阶段,在这个阶段,部分内置api和函数调用是不可用的,因此为了避免这种问题,plugin的加载默认从 store 文件中取值,就不走自定义数据源了 \ No newline at end of file diff --git a/gitbook/code/tracing/README.md b/gitbook/code/tracing/README.md new file mode 100644 index 0000000..61e16e8 --- /dev/null +++ b/gitbook/code/tracing/README.md @@ -0,0 +1,3 @@ +# 链路追踪插件 + +文档待补充 \ No newline at end of file diff --git a/gitbook/usage/auth/README.md b/gitbook/usage/auth/README.md new file mode 100644 index 0000000..e69de29 diff --git a/gitbook/usage/balance/README.md b/gitbook/usage/balance/README.md index f701e52..1facf6e 100644 --- a/gitbook/usage/balance/README.md +++ b/gitbook/usage/balance/README.md @@ -8,37 +8,44 @@ ## 在文件中的配置 ```lua -service_empty = { -- 路由服务空错误定制 +service_empty = { -- 路由服务空错误码 + zname = '路由服务为空', code = 503, content_type = "text/html", content = "
service_empty err
" }, mode_empty = { -- 路由匹配空错误码 + zname = '路由匹配为空', code = 503, content_type = "text/html", content = "mode_empty err
" }, host_empty = { -- 路由域名空错误码 + zname = '路由域名为空', code = 503, content_type = "text/html", content = "host_empty err
" }, host_pass = { -- 路由服务不匹配错误码 + zname = '路由服务不匹配', code = 503, content_type = "text/html", content = "host_pass err
" }, token_limit = { -- 路由令牌桶限流错误码 + zname = '路由令牌桶限流', code = 503, content_type = "text/html", content = "token_limit err
" }, leak_limit = { -- 路由漏桶限流错误码 + zname = '路由漏桶限流', code = 503, content_type = "text/html", content = "leak_limit err
" }, offline = { -- 路由服务下线错误码 + zname = '路由服务下线', code = 503, content_type = "text/html", content = "offline err
" diff --git a/gitbook/usage/balance/README_RULE.md b/gitbook/usage/balance/README_RULE.md index 87250f7..2700fbc 100644 --- a/gitbook/usage/balance/README_RULE.md +++ b/gitbook/usage/balance/README_RULE.md @@ -1,4 +1,17 @@ +# 负载均衡模式 + +在v3.0.1版本后才支持,最初在设计上没有考虑到这一点,后面有同学反馈了这一个场景后便补充了这个功能 + + ![图片](https://qnproxy.iamtsm.cn/WechatIMG22.png "图片") + + ![图片](https://qnproxy.iamtsm.cn/WechatIMG23.png "图片") + +这个功能可以支持到根据设置的负载模式,来决定在规则匹配前进行模式选择,目前有两种模式,项目默认选用host,这个设置是对全负载策略生效,不进行区分 + +host: 优先匹配host,再匹配不同策略下的规则 +api : 优先匹配规则,再从匹配的规则中进行host匹配 + # 负载均衡策略 对于负载均衡,目前分为五个负载策略,在负载时,会按照这个顺序进行负载,而每个策略分为两种模式 指定路由,随机路由。 @@ -18,32 +31,52 @@ 对于 `请求参数`,`请求COOKIE`,`请求HEADER` 的随机负载,是根据当前命中的key的长度设置随机种子,得到随机数进行随机负载。 +## 正则匹配自定义 + +API策略和Body策略,是支持每条规则自定义正则匹配模式的,目前支持一下几种。其他几种策略暂不支持 + +```lua +tl_ops_match_mode = {-- api匹配模式 + -- 精准匹配模式 + all = "all", + -- 正则匹配 + reg = "jo", + -- 正则忽略大小写 + regi = "joi", + -- 最长字符串匹配 + regid = "joid" +} +``` + ## 在文件中的配置 在文件中的配置需注意的是,如果`sync`插件为开启状态时,会有后台任务同步文件中的配置数据至store中,且是根据 `id` 来判定是否需要执行同步逻辑。所以需要保证文件中的配置的数据的id是具有唯一性的标识字段。 当然,此字段如果为关闭状态,静态规则将不会同步至store中,规则也就不会生效, + `API策略` ```lua point = { { - id = 1, - url = "/*", -- 当前url匹配规则 - service = "测试服务1", -- 当前url路由到的service - node = 0, -- 当前url路由到的service下的node的索引 - host = "tlops1.com", -- 当前url处理的域名范围 - rewrite_url = "", -- 当前url重写后的url + id = 1, + url = "/*", -- 当前url匹配规则 + match_mode = match_mode.reg, -- 正则匹配模式 + service = "tlops-demo", -- 当前url路由到的service + node = 0, -- 当前url路由到的service下的node的索引 + host = "tlops1.com", -- 当前url处理的域名范围 + rewrite_url = "", -- 当前url重写后的url } }, random = { { id = 1, - url = "/*", -- 当前url匹配规则 - service = "测试服务1", -- 当前url路由到的service - host = "tlops1.com", -- 当前url处理的域名范围 - rewrite_url = "", -- 当前url重写后的url + url = "/api", -- 当前url匹配规则 + match_mode = match_mode.all, -- 精准匹配模式 + service = "tlops-demo", -- 当前url路由到的service + host = "tlops1.com", -- 当前url处理的域名范围 + rewrite_url = "", -- 当前url重写后的url } }, ``` @@ -138,18 +171,20 @@ random = { point = { { id = 1, - body = "iamtsm", -- 当前url匹配规则 - service = "tlops-demo", -- 当前url路由到的service - node = 0, -- 当前url路由到的service下的node的索引 - host = "tlops1.com", -- 当前url处理的域名范围 + body = "iamtsm", -- 当前url匹配规则 + match_mode = match_mode.reg, -- 正则匹配模式 + service = "tlops-demo", -- 当前url路由到的service + node = 0, -- 当前url路由到的service下的node的索引 + host = "tlops1.com", -- 当前url处理的域名范围 } }, random = { { id = 1, - body = "iamtsm", -- 当前url匹配规则 - service = "tlops-demo", -- 当前url路由到的service - host = "tlops1.com", -- 当前url处理的域名范围 + body = "iamtsm", -- 当前url匹配规则 + match_mode = match_mode.all, -- 精准匹配模式 + service = "tlops-demo", -- 当前url路由到的service + host = "tlops1.com", -- 当前url处理的域名范围 } }, ``` diff --git a/gitbook/usage/cors/README.md b/gitbook/usage/cors/README.md new file mode 100644 index 0000000..e69de29 diff --git a/gitbook/usage/env/README.md b/gitbook/usage/env/README.md index f355361..274ae33 100644 --- a/gitbook/usage/env/README.md +++ b/gitbook/usage/env/README.md @@ -1,37 +1,37 @@ # 配置 -#### 对于tl-ops-manage来说,配置以 `*.tlindex` 和 `*.tlstore`中的数据为主。 配置有两种方式,一种是在配置文件中填写配置,另外一种是在管理台填写配置。同时,配置是分为两种类别,一种是定时任务中的配置,另外一种是无需进入定时任务的规则配置。 -## 配置类别 - - -### 定时任务配置 +## 定时任务配置 在定时任务中的配置,是在ngx.timer启动时传入,并启动相应的timer,其作用域是在timer的作用域中,如果发生配置变动ngx.timer是主动无法感知的。所以是需要主动判断timer内的conf是否需要同步为最新 如 “健康检查配置”,“熔断限流配置”,“服务节点配置” 这些需要依赖定时任务的都属于定时任务配置。 -### 规则配置 +## 规则配置 而像负载多策略配置,如 “API负载规则” ,“WAF-CC规则”,... 这类配置是在请求阶段实时获取的,是实时保持最新,无需主动同步的 -## 配置方式 +## 文件中配置 + 在文件中配置的数据,只有服务配置,健康检查配置,熔断配置等依赖定时器的情况下,才会从文件配置中取值,其他情况下在文件中配置不生效。 + 因为配置的读取都在cache中进行,如果需要将文件中新增或者修改的数据生效,可以开启同步数据插件,在启动时同步合并至cache中。 -### 文件中配置 +### 内置模块文件中配置 - 在文件中配置的数据,会在启动时同步合并至store文件中,并进行数据预热至内存中。 + 在内置的模块中,如服务,自检,负载等模块中的文件配置是统一在 constant 包下的文件 +### 插件模块文件中配置 -### 管理台配置 + 在插件模块中,配置统一放置在各个插件包下的tl_ops_plugin_constant.lua中 - 在管理后台设置的数据,会直接进入store中 +## 管理台配置 + 在管理后台设置的数据,会直接进入cache中 # 全局项目配置 @@ -41,123 +41,29 @@ ```lua -local ROOT_PATH = "F:/code/tl-open-source/tl-ops-manage/" +local ROOT_PATH = "/path/to/tl-open-source/tl-ops-manage/" return { path = { - --[[ - en :Console path setting, the page forwarding plugin will use this path for path matching - - zn :控制台路径设置,页面转发插件会将此路径用于路径匹配 - ]] tlopsmanage = ROOT_PATH .. "web/", - --[[ - en :The official website path setting, the page forwarding plugin - will use this path for path matching - - zn :官网路径设置,页面转发插件会将此路径用于路径匹配 - ]] website = ROOT_PATH .. "website/", - --[[ - en :log output directory, all module logs will be output to this directory - - zn :日志输出目录,所有模块的日志都将输出到此目录下 - ]] log = ROOT_PATH, - --[[ - en :data storage directory, the directory where the module data is stored - - zn :数据存放目录,模块的数据存放的目录 - ]] store = ROOT_PATH .. "store/", }, log = { - --[[ - en :log level, please be careful not to enable debug level logs - in the production environment, it will greatly affect the performance. - - zn :日志等级, 注意请不要在生产环境开启调试级别日志,十分影响性能。 - ]] level = 1, - --[[ - en :log formatting. Turning this option on will take up more disk space. - It is recommended to turn off this option in a production environment - - zn :日志格式化,开启此选项会占用更多磁盘空间,生产环境推荐关闭此选项 - ]] format_json = true, }, cache = { - --[[ - en : enable custom L2 cache, currently supports options [redis], [none], - [none] means close L2 cache - Supports custom extended cache implementations, such as etcd, mysql, etcd. - - zn :开启自定义二级缓存,目前支持选项 【redis】, 【none】, 【none】表示不开启二级缓存 - 支持自定义扩展缓存实现,如etcd,mysql等。 - ]] - cus = "redis" + cus = "none" }, balance = { - --[[ - en :load counter, after this option is enabled, every time nginx is started, - a timer will be enabled to count the load requests within a certain period of time - The time interval is configured in 'constant.tl_ops_constant_balance.count.interval' - Notice: Do not set the statistical time interval too short, which may affect performance. - - zn :负载统计器,开启此选项后,将在每次启动nginx时,将开启定时器统计一定时间段内的负载请求情况 - 时间间隔在‘constant.tl_ops_constant_balance.count.interval’进行配置 - 注意:统计时间间隔不要设置过短,可能会影响性能。 - ]] counting = true, - --[[ - en :load current limiter. After this option is enabled, a current limiter will be - connected to the load balancing module. If you need to access current limit, - it is recommended to enable this option - - zn :负载限流器,开启此选项后,将在负载均衡模块接入限流器。如果需要接入限流,推荐开启此选项 - ]] limiter = true, }, waf = { - --[[ - en :waf filtering, after this option is enabled, all traffic will be cleaned according - to the configuration rules, it is recommended to enable - - zn :waf过滤,开启此选项后,将根据配置规则对所有流量进行清洗,推荐开启 - ]] open = true, - --[[ - en :waf filter statistic, after this option is enabled, every time nginx is started, - a timer will be enabled to count the waf filter requests within a certain period of time - The time interval is configured in 'constant.tl_ops_constant_waf.count.interval' - Notice: Do not set the statistical time interval too short, which may affect performance. - - zn :waf过滤统计器,开启此选项后,将在每次启动nginx时,将开启定时器统计一定时间段内的waf过滤请求情况 - 时间间隔在‘constant.tl_ops_constant_waf.count.interval’进行配置 - 注意:统计时间间隔不要设置过短,可能会影响性能。 - ]] counting = true, - - }, - plugin = { - --[[ - en :plugins, when this option is turned on, the added plugins will be enabled - - zn :插件,开启此选项后,将在启动时加载添加的所有插件 - ]] - open = true, - --[[ - en :plugin module definition, the imported plugin needs to be defined here before it can be loaded. - Otherwise it will not take effect - Notice: the order in which plugins are filled in will affect the order in which the same plugin stages are executed - - zn :插件模块定义,引入的插件需要在此定义好才能被加载。否则将不生效。注意,插件填写的顺序将影响相同插件阶段执行的顺序 - ]] - module = { - "ssl", "sync", "sync_cluster", "page_proxy", - -- "jwt", "cors", "log_analyze", "tracing" - } } } diff --git a/gitbook/usage/fuselimit/README.md b/gitbook/usage/fuselimit/README.md index 4d2765c..4be691a 100644 --- a/gitbook/usage/fuselimit/README.md +++ b/gitbook/usage/fuselimit/README.md @@ -17,8 +17,8 @@ options = { service_threshold = 0.5, -- 切换状态阈值 (service切换阈值,取决于node失败状态占比) recover = 15 * 1000, -- 全熔断恢复时间 单位/ms depend = depend.token, -- 默认依赖组件 :token_bucket - level = level.service, -- 默认组件级别,服务层级 [限流熔断针对的层级] - mode = mode.balance_fail, -- 默认策略 :节点路由失败率 + level = level.service, -- 默认组件级别,服务层级 [限流熔断针对的层级] + mode = mode.balance_fail, -- 默认策略 :节点路由失败率 }, .... }, @@ -31,7 +31,7 @@ local depend = { -- 组件级别 local level = { - service = "service" + service = "service" } -- 熔断策略 @@ -47,13 +47,13 @@ local mode = { -- 限流配置 options = { - service_name = "测试服务1", -- 令牌桶配置所属服务 - capacity = 10 * 1024 * 1024, -- 最大容量 10M (按字节为单位,可做字节整型流控) - rate = 1024, -- 令牌生成速率/秒 (每秒 1KB) - warm = 100 * 1024, -- 预热令牌数量 (预热100KB) - block = 1024, -- 流控以1024为单位 - expand = 0.5, -- 扩容比例 - shrink = 0.5, -- 缩容比例 + service_name = "测试服务1", -- 令牌桶配置所属服务 + capacity = 10 * 1024 * 1024, -- 最大容量 10M (按字节为单位,可做字节整型流控) + rate = 1024, -- 令牌生成速率/秒 (每秒 1KB) + warm = 100 * 1024, -- 预热令牌数量 (预热100KB) + block = 1024, -- 流控以1024为单位 + expand = 0.5, -- 扩容比例 + shrink = 0.5, -- 缩容比例 } ``` @@ -65,12 +65,12 @@ options = { -- 限流配置 options = { - service_name = "测试服务1", -- 漏桶配置所属服务 - capacity = 10 * 1024 * 1024, -- 最大容量 10M (按字节为单位,可做字节整型流控) - rate = 1024 * 10, -- 漏桶流速/秒 (每秒 10KB) - block = 1024, -- 流控以1024为单位 - expand = 0.5, -- 扩容比例 - shrink = 0.5, -- 缩容比例 + service_name = "测试服务1", -- 漏桶配置所属服务 + capacity = 10 * 1024 * 1024, -- 最大容量 10M (按字节为单位,可做字节整型流控) + rate = 1024 * 10, -- 漏桶流速/秒 (每秒 10KB) + block = 1024, -- 流控以1024为单位 + expand = 0.5, -- 扩容比例 + shrink = 0.5, -- 缩容比例 } ``` diff --git a/gitbook/usage/healthdebug/README.md b/gitbook/usage/healthdebug/README.md new file mode 100644 index 0000000..e69de29 diff --git a/gitbook/usage/install/README.md b/gitbook/usage/install/README.md index ac3b20e..32e62a9 100644 --- a/gitbook/usage/install/README.md +++ b/gitbook/usage/install/README.md @@ -1,11 +1,11 @@ # 安装 -**下载项目 : https://github.com/iamtsm/tl-ops-manage** +下载项目 : https://github.com/iamtsm/tl-ops-manage 或者 -**git clone https://github.com/iamtsm/tl-ops-manage** +git clone https://github.com/iamtsm/tl-ops-manage ## 安装依赖 diff --git a/gitbook/usage/intro/README.md b/gitbook/usage/intro/README.md index 7227ed1..bd4283d 100644 --- a/gitbook/usage/intro/README.md +++ b/gitbook/usage/intro/README.md @@ -1,8 +1,8 @@ # 简介 -tl-ops-manage (tl-openresty-web-manage),基于openresty开发的一款基础服务管理工具,支持服务动态扩展,自定义路由规则,健康检查,服务熔断,服务限流,动态配置,数据统计,日志记录,数据版本控制,后台可视化管理,自定义插件 等等... +tl-ops-manage (tl-openresty-web-manage),基于openresty开发的一款基础服务管理工具,支持服务动态扩展,自定义路由规则,健康检查,服务熔断,服务限流,动态配置,数据统计,日志记录,数据版本控制,后台可视化管理,自定义插件, 集群部署 等等... -做这个项目最开始的想法很简单,只是想在造轮子的过程中了解,学习一些新的知识面。到后面完成了大部分基础功能点后,发现可以整理为一个服务管理工具的项目。于是就有了tl-ops-manage。 +做这个项目最开始的想法很简单,只是想在造轮子的过程中了解,学习一些新的知识面。到后面完成了大部分基础功能点后,发现可以整理为一个服务管理工具的项目。于是在不断的迭代下就有了tl-ops-manage。 ## 优势 diff --git a/gitbook/usage/loganalyze/README.md b/gitbook/usage/loganalyze/README.md new file mode 100644 index 0000000..e69de29 diff --git a/gitbook/usage/pageproxy/README.md b/gitbook/usage/pageproxy/README.md new file mode 100644 index 0000000..e69de29 diff --git a/gitbook/usage/plugin/README.md b/gitbook/usage/plugin/README.md index fec1e8c..38572bf 100644 --- a/gitbook/usage/plugin/README.md +++ b/gitbook/usage/plugin/README.md @@ -14,13 +14,17 @@ ### 编写插件代码 - 根据你想编写的插件,在tl_ops_plugin_core模板文件中相应阶段编写相应的代码。 +根据你想编写的插件,在模板文件中相应阶段编写相应的代码。 -### 修改配置文件 +`tl_ops_plugin_core` : 插件逻辑 - 在总配置文件中 `tl-ops-manage/tl_ops_manage_env` 引入插件名称。 +`tl_ops_plugin_constant` : 插件配置数据定义 +`tl_ops_plugin_open` : 插件开关 -## 插件实例 +`tl_ops_plugin_api` : 插件对外api接口 -tl-ops-manage提供了一个同步器插件,`tl_ops_sync`,此插件的作用是,在启动nginx/openresty时,同步静态配置中的数据至store文件中,并提供配置数据预热功能。且支持新增静态配置字段时,同步新增至对应store文件中 + +### 添加插件 + +添加插件支持两种形式,从 tl_ops_constant_plugins_manage.lua 配置文件中添加, 从管理后台插件管理中添加 \ No newline at end of file diff --git a/gitbook/usage/sync/README.md b/gitbook/usage/sync/README.md new file mode 100644 index 0000000..e69de29 diff --git a/gitbook/usage/timealert/README.md b/gitbook/usage/timealert/README.md new file mode 100644 index 0000000..e69de29 diff --git a/limit/fuse/tl_ops_limit_fuse_leak_bucket.lua b/limit/fuse/tl_ops_limit_fuse_leak_bucket.lua index 1f162b8..1b32aa5 100644 --- a/limit/fuse/tl_ops_limit_fuse_leak_bucket.lua +++ b/limit/fuse/tl_ops_limit_fuse_leak_bucket.lua @@ -60,6 +60,9 @@ end -- block 取用漏桶数量 local tl_ops_limit_leak = function( service_name, node_id ) local leak_mode = tl_ops_limit_leak_mode( service_name , node_id) + if not leak_mode then + return false + end local block_key = tl_ops_utils_func:gen_node_key(leak_mode.cache_key.block, service_name, node_id) local block = shared:get(block_key) @@ -142,6 +145,9 @@ end -- 扩容 熔断定时器中保证锁,所以这里不加锁 local tl_ops_limit_leak_expand = function( service_name, node_id ) local leak_mode = tl_ops_limit_leak_mode( service_name, node_id) + if not leak_mode then + return false + end local capacity_key = tl_ops_utils_func:gen_node_key(leak_mode.cache_key.capacity, service_name, node_id) local capacity = shared:get(capacity_key) @@ -183,7 +189,10 @@ end local tl_ops_limit_leak_shrink = function( service_name, node_id ) local leak_mode = tl_ops_limit_leak_mode( service_name, node_id) - + if not leak_mode then + return false + end + local block_key = tl_ops_utils_func:gen_node_key(leak_mode.cache_key.block, service_name, node_id) local block = shared:get(block_key) if not block then diff --git a/limit/fuse/tl_ops_limit_fuse_token_bucket.lua b/limit/fuse/tl_ops_limit_fuse_token_bucket.lua index 316ecce..a075204 100644 --- a/limit/fuse/tl_ops_limit_fuse_token_bucket.lua +++ b/limit/fuse/tl_ops_limit_fuse_token_bucket.lua @@ -60,6 +60,9 @@ end -- block 取用令牌数量 local tl_ops_limit_token = function( service_name, node_id ) local token_mode = tl_ops_limit_token_mode( service_name , node_id) + if not token_mode then + return false + end local capacity_key = tl_ops_utils_func:gen_node_key(token_mode.cache_key.capacity, service_name, node_id) local capacity = shared:get(capacity_key) @@ -130,7 +133,7 @@ local tl_ops_limit_token = function( service_name, node_id ) return false end - local new_token_bucket = math.min(token_bucket + duration_token_bucket, capacity) + local new_token_bucket = math.min(token_bucket + duration_token_bucket, capacity) -- 令牌还是不够 if new_token_bucket < block then @@ -165,6 +168,9 @@ end local tl_ops_limit_token_expand = function( service_name, node_id ) local token_mode = tl_ops_limit_token_mode( service_name, node_id) + if not token_mode then + return false + end local capacity_key = tl_ops_utils_func:gen_node_key(token_mode.cache_key.capacity, service_name, node_id) local capacity = shared:get(capacity_key) @@ -206,6 +212,9 @@ end local tl_ops_limit_token_shrink = function( service_name, node_id ) local token_mode = tl_ops_limit_token_mode( service_name, node_id) + if not token_mode then + return false + end local capacity_key = tl_ops_utils_func:gen_node_key(token_mode.cache_key.capacity, service_name, node_id) local capacity = shared:get(capacity_key) diff --git a/tl_ops_manage.lua b/tl_ops_manage.lua index cd67893..8a24dce 100644 --- a/tl_ops_manage.lua +++ b/tl_ops_manage.lua @@ -19,6 +19,7 @@ local utils = require("utils.tl_ops_utils_func"); local env = require("tl_ops_manage_env") local constant = require("constant.tl_ops_constant") local cache = require("cache.tl_ops_cache") +local tlops_api = require("api.tl_ops_api_core") local m_err_content = require("err.tl_ops_err_content") local balance_shared = ngx.shared.tlopsbalance local plugin_shared = ngx.shared.tlopsplugin diff --git a/web/balance/tl_ops_web_api.js b/web/balance/tl_ops_web_api.js index f8cf80b..f2aac66 100644 --- a/web/balance/tl_ops_web_api.js +++ b/web/balance/tl_ops_web_api.js @@ -59,11 +59,13 @@ const tl_ops_web_api_point_cols = function () { }, { field: 'service', title: '所属服务',width:"10%" }, { - field: 'node', title: '节点索引',width:"10%" + field: 'node', title: '节点索引',width:"5%" }, { field: 'rewrite_url', title: '重写地址',width:"10%" }, { - field: 'updatetime', title: '更新时间',width:"15%", + field: 'fake_prefix', title: '节点路径',width:"10%" + }, { + field: 'updatetime', title: '更新时间',width:"10%", }, { width: "10%", align: 'center', @@ -84,15 +86,17 @@ const tl_ops_web_api_random_cols = function () { }, { field: 'host', title: '域名',width:"10%" }, { - field: 'url', title: 'API', width:"15%" + field: 'url', title: 'API', width:"10%" }, { field: 'match_mode', title: '匹配模式',width:"10%" }, { field: 'service', title: '所属服务',width:"10%" }, { field: 'rewrite_url', title: '重写地址',width:"10%" + },{ + field: 'fake_prefix', title: '节点路径',width:"10%" }, { - field: 'updatetime', title: '更新时间',width:"15%", + field: 'updatetime', title: '更新时间',width:"10%", }, { width: "10%", align: 'center', @@ -365,7 +369,7 @@ const tl_ops_api_data_add_filter = function( data ) { delete data.field.node } for(let key in data.field){ - if(key === 'id' || key === 'rewrite_url'){ + if(key === 'id' || key === 'rewrite_url' || key === 'fake_prefix'){ continue; } if(data.field[key] === undefined || data.field[key] === null || data.field[key] === ''){ @@ -376,6 +380,7 @@ const tl_ops_api_data_add_filter = function( data ) { data.field[key] = parseInt(data.field[key]) } } + res_data.tl_ops_balance_api_list[rule].push(data.field) res_data.tl_ops_balance_api_list[rule].forEach(item=>{ @@ -394,7 +399,7 @@ const tl_ops_api_data_edit_filter = function( data ) { delete data.field.node } for(let key in data.field){ - if(key === 'rewrite_url'){ + if(key === 'rewrite_url' || key === 'fake_prefix'){ continue } if(data.field[key] === undefined || data.field[key] === null || data.field[key] === ''){ diff --git a/web/balance/tl_ops_web_api_form.html b/web/balance/tl_ops_web_api_form.html index c57a033..a279815 100644 --- a/web/balance/tl_ops_web_api_form.html +++ b/web/balance/tl_ops_web_api_form.html @@ -22,6 +22,23 @@ top: 3px; margin-right: 15px; } + .prefix{ + max-width: 40%; + border-radius: 5px; + } + #prefix{ + margin-top: 10px; + text-overflow: ellipsis; + overflow: hidden; + padding-left: 10px; + color: #918576; + font-weight: bold; + padding-right: 10px; + } + #url{ + width: 100%; + min-width: 60%; + } @@ -38,9 +55,17 @@ +