基于openresty的URL 断路器/熔断器 -- URL-fuse
时间:2022-07-24
本文章向大家介绍基于openresty的URL 断路器/熔断器 -- URL-fuse,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Intro
a configurable URL curcuit breaker for nginx/openresty
这是一个可灵活配置的URL断路器(熔断器), 基于 nginx openresty.
Why
我们不希望整体服务被个别接口的慢请求拖死. 因为慢请求会不断堆积, 使服务出现超时499或502, 最后504.
同时你也可以将糟糕的慢请求(比如15秒内连续10次5秒超时)做成服务健康报警, 这样能提前减少流量增加时的雪崩概率.
How
慢请求雪崩一般是网络IO问题, 也可能是 计算缓慢(Load 高或计算复杂)等原因,而这些服务一般通过 fastcgi/uwsgi/proxy/..返回内容, 所以内容生成(content_by_lua)前后时间差就是真实的执行时间, 它是从接受请求第一个字节到返回响应最后一个字符的时间段(ngx.now()-ngx.req.start_time).
当有连续多个请求时, 请求数量大于一个阀值则可以认为此 domain+path 的接口服务高风险 或失败请求.这里需要做熔断来降级此接口,防止雪崩扩大.
Design
Notice
- 为了能正常计算 程序的执行时间, REQUEST_TIMEOUT 要小于cgi/fastcgi/uwsgi/proxy_pass 的最大超时也小于 nginx 对应的超时时间. 否则执行时间计算不准确.
- 如果在熔断之前瞬间有大量请求打入 nginx, 则服务依然可能会雪崩.
- 具体配置请参考 nginx.conf.
Configure
http{
#... somethings
# url-fuse start
lua_package_path '/data1/ms/front/docker/config/openresty/?.lua;;'; --your directory of lua files
lua_shared_dict fuse_shard_dict 10m; --change for your case
init_worker_by_lua_block {
local fuse = require "url_fuse"
fuse:setup(function(this)
this.LIFETIME = 10
this.FAILS_LIMIT = 10
this.REQUEST_TIMEOUT =5
this.FUSED_DURATION = 5
end)
}
server {
listen 80;
root /data1/ms/front/;
location ~ ^/.*(.js|.css|.png|.gif|.jpg|favicon.ico)$ {
log_not_found off;
access_log off;
}
location / {
access_by_lua_block {
local fuse = require "url_fuse"
fuse:run_access()
}
log_by_lua_block {
local fuse = require "url_fuse"
fuse:run_log()
}
return 200 'hello';
}
}
#url-fuse end
}
support params
local config = {
dict = ngx.shared.fuse_shard_dict,
-- config start
REQUEST_TIMEOUT = 1, --in seconds
FUSED_DURATION = 10, --in seconds
FAILS_LIMIT = 10, --number of consecutive failures
LIFETIME = 15, -- expired counters will be discarded, in seconds
DEBUG = false,
GEN_BUCKET_ID = function(self)
return table.concat({ ngx.var.host, ngx.var.uri })
end,
ON_DEGRADED_CALLBACK = function(self)
ngx.status = 403
return ngx.exit(403)
end,
BEFORE_HALF_OPEN_CALLBACK = function(self)
end,
AFTER_HALF_OPEN_CALLBACK = function(self)
end,
VALIDATE_REQUEST = function(self)
--true is success
local elapsed = ngx.now() - ngx.req.start_time()
return elapsed < self.REQUEST_TIMEOUT
end,
}
usage:
local fuse = require "url_fuse"
fuse:setup(function(this) --set your params
this.LIFETIME = 10
--bla bla ...
end)
Test
ab -X 127.0.0.1:80 -c 1000 -n 10000 -k 'http://test.cn/a/'
# use nginx.conf
Server Software: openresty
Server Hostname: test.cn
Server Port: 80
Document Path: /a/
Document Length: 5 bytes
Concurrency Level: 1000
Time taken for tests: 0.250 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 10000
Total transferred: 1490000 bytes
HTML transferred: 50000 bytes
Requests per second: 40022.09 [#/sec] (mean)
Time per request: 24.986 [ms] (mean)
Time per request: 0.025 [ms] (mean, across all concurrent requests)
Transfer rate: 5823.53 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 4 13.1 0 64
Processing: 3 17 3.1 17 65
Waiting: 1 17 3.1 17 35
Total: 3 21 14.6 17 88
# use benchmark.nginx.conf, ( openresty with URL-fuse )
Server Software: openresty
Server Hostname: test.cn
Server Port: 80
Document Path: /a/
Document Length: 5 bytes
Concurrency Level: 1000
Time taken for tests: 0.252 seconds
Complete requests: 10000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 10000
Total transferred: 1490000 bytes
HTML transferred: 50000 bytes
Requests per second: 39737.26 [#/sec] (mean)
Time per request: 25.165 [ms] (mean)
Time per request: 0.025 [ms] (mean, across all concurrent requests)
Transfer rate: 5782.08 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 4 12.9 0 62
Processing: 3 17 3.0 18 63
Waiting: 1 17 3.0 18 36
Total: 3 22 14.5 18 87
openresty version:
bash-4.3# nginx -V
nginx version: openresty/1.17.8.2
built by gcc 5.3.0 (Alpine 5.3.0)
built with OpenSSL 1.0.2n 7 Dec 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/sinawap/nginx/nginx --with-cc-opt=-O2 --add-module=../ngx_devel_kit-0.3.1 --add-module=../echo-nginx-module-0.62 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2 --add-module=../set-misc-nginx-module-0.32 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.08 --add-module=../srcache-nginx-module-0.32 --add-module=../ngx_lua-0.10.17 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.33 --add-module=../array-var-nginx-module-0.05 --add-module=../rds-json-nginx-module-0.15 --add-module=../ngx_stream_lua-0.0.8 --with-ld-opt=-Wl,-rpath,/usr/local/sinawap/nginx/luajit/lib --with-threads --with-file-aio --with-http_realip_module --with-http_gzip_static_module --with-pcre-jit --with-ipv6 --with-http_stub_status_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_ssl_module
取多次均值: nginx : 40022 vs url-fuse: 39737, 性能损耗可忽略
源码: https://github.com/sunsky/URL-fuse
欢迎star/fork, 更欢迎指正问题.
本人 QQ: 374872684
参考:
https://github.com/openresty/lua-nginx-module
https://moonbingbing.gitbooks.io/openresty-best-practices/
- Canvas 图形组合方式
- HTML5 FileReader接口学习笔记
- 如何用BBED使Offline的数据文件Online
- Entity Framework4.3 Code-First基于代码的数据迁移讲解1.建立一个最初的模型和数据库 2.启动Migration(数据迁移)3.第一个数据迁移4.订制的数据迁移4.动态
- 轻松初探Python(六)—函数
- css3实现圆角边框渐变
- 设计模式专题(十二)——状态模式
- HTML5新增属性学习笔记
- HTML5标签学习笔记
- 设计模式专题(十三) ——备忘录模式
- 设计模式专题(十五) ——组合模式
- 设计模式专题(十六)——迭代器模式
- 设计模式专题(十七) ——单例模式
- 设计模式专题(十八) ——桥接模式
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- SpringBoot微服务架构项目--Union社交平台
- 如何衡量前端基建的效能价值?
- mbedtls | 移植mbedtls库到STM32裸机的两种方法
- 实用小技巧 | 用socket玩转http接口
- 深度学习之人脸识别模型--FaceNet
- Java常用的设计模式
- HW防守|应急溯源分析手册汇总篇
- Python进阶(一)
- Python版本的OpenCV安装
- CVE-2020-16875:Microsoft Exchange RCE复现
- 抢先学鸿蒙(HarmonyOS)2.0,你就是下一个大咖!
- Python高效编程之88条军规(2):你真的会格式化字符串吗?
- 搭建Typecho博客
- Python开发之Pandas的使用
- Python开发之numpy的使用