最新要闻
- 全球热讯:非油炸!吃欢天荞麦面皮10袋到手19.9元:麻酱、酸辣随便挑
- 世界今热点:ChatGPT版必应被华人小哥攻破:一句话“催眠”问出所有Prompt
- 世界热门:钙钛矿-硅光伏电池效率突破30%!可稳定工作30年
- 世界即时:公交车刹车提醒是2B请注意 当地回应:考虑不周将“改名”
- 环球热议:苹果忍不住反驳乔布斯女儿吐槽:iPhone 14比iPhone 13 Pro还要好
- 环球资讯:让地球“流浪”前 先来研究下这一个更现实的威胁
- 女子疑吃自热火锅去世:不排除急性中毒、家属索赔176万元
- 当前消息!最香的i9+RTX 4080游戏本!ROG枪神7超竞版仅需18999元起
- 全球热讯:泰国1月份纯电动车上牌量排行:比亚迪称王、国产车霸榜
- GTX 1060落魄了?《原子之心》1080P高画质需GTX 1080
- 《流浪地球2》全球爆火背后!《三体》导演:中国科幻的内核是文化自信
- 神十五航天员首次出舱视频公布:和地球同框 绝美
- 每日速看!方向盘助力失灵、AEB抽风!车主:百年凯迪拉克毁于LYRIQ 绝望
- 速递!Android 14来了:提升续航和流畅度
- 《狂飙》片头被指抄袭 网友放对比照跟国外一电影太相似:背后公司被扒
- 全球热点评!网民称《水浒》应从中小学课文中清除 毒害更多人:浙江官方回应了
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
环球时讯:【网关开发】8.Openresty 网关自定义健康检查的设计与实现
- 背景
- 设计
- 健康检查流程图
- 健康检查过程
- 核心代码
- down_checker 模块
- upstream_context 模块
- balance 模块
- 测试
- 主动健康
- 被动健康检查
- 总结与思考
- 共享内存保存检测列表
- 提高健康检查效率
背景
使用Openresty作为网关进行动态节点IP负载均衡时,要求网关有能力在负载均衡之前摘除掉有问题的节点。所以网关需要一定的健康检查能力。
设计
如果每一个网关节点都对服务节点进行探活,假设每1s探活一次,网关节点有M个,服务节点有N个,那整个网络中每秒出现M*N条探活协议,而且大部分都是探活成功的结果,不仅浪费带宽,而且增加业务节点的压力。给出的设计方案是引入独立管理服务,进行所有节点的探活,当探活结果是up时不做操作,当结果是down时,说明服务节点可能存在问题,通过API的形式发送给Openresty,Openresty在对节点进行检测,干预负载均衡结果,如果网关探活发现节点已经恢复,再将该节点加入到可被负载均衡的列表中。
(资料图)
健康检查流程图
健康检查过程
- manager服务用来管理各个服务的节点,包括配置健康检查信息,写入ETCD等
- manager服务进行主动健康检查,定期请求服务节点,如果发现节点异常, 通过API发送给Openresty的down_checker模块
- down_checker模块管理所有down的节点,定期向server node发送健康检查协议。
- down_checker模块发现节点异常(down),通知upstream_context模块,将该节点移除负载均衡列表
- down_checker模块发现节点正常(up), 从管理的down节点列表移除,通知upstream_context模块,将该节点加入负载均衡列表
- balance模块进行负载均衡时会从upstream_context中获取负载均衡列表。
- 当balance模块进行复杂均衡时如果发现节点异常,则通知down_checker模块进行监控,实现被动健康检查功能。
核心代码
一些依赖模块在以前的博客中都有详细讲解lua绑定委托 delegateevents插件使用自定义负载均衡代码仓库:https://github.com/zhaoshoucheng/openresty/blob/main/pkg/lua_script/upstream/down_peer_checker.lua
down_checker 模块
数据结构
function _M.new() return setmetatable({ interval = 1, -- 检测间隔时间 watches = {}, -- 检测列表 map on_peer_up = delegate.new(), -- 检测节点为up时调用的函数链 on_peer_added = delegate.new(), -- 添加检测节点调用函数链 on_peer_removed = delegate.new(), -- 移除检测节点调用函数链 }, _MT)end
一个Openresty有多个进程,但是只需要一个进程发送健康检查请求就可以,将结果通知给其他进程检测结果通过event通知__check_peer 发送http与tcp网络请求【网关开发】7.Openresty使用cosocket API 发送http与tcp网络请求
local function _check_peers_and_notify(self, tasks) for i = 1, #tasks do local ctx = tasks[i] local server_up = __check_peer(ctx) --TODO 简单策略:遇到一次健康检查成功则设置成up,没有对每次健康检查结果进行保存 if server_up then ctx.down = false events.post(self._events._source, self._events.notify, { name = ctx.name, peer = ctx.peer, }) end endend
遍历down节点列表,需要根据健康检查自身设置的时间间隔进行检测。
local function _do_check(self) -- get all peers to check this time local todo = { } local now = ngx.now() local i = 1 for watch_name, ctx in pairs(self.watches) do if ctx.next_check_date and ctx.next_check_date <= now then todo[i] = ctx local interval = ctx.ahc.interval if interval > 1000 then interval = interval / 1000 end ctx.next_check_date = now + (interval or 10) i = i + 1 end end local all_task_count = #todo if all_task_count == 0 then return end _check_peers_and_notify(self, todo)end
定时器检测,循环遍历检测列表
local function _tick_proc(p, self) local start = ngx.now() local ok, err = pcall(_do_check, self) local stop = ngx.now() local next_tick = self.interval - (stop - start) if next_tick <= 0.1 then next_tick = 0.1 end if not ok then ngx.log(ngx.ERR, "failed to run healthcheck cycle: " .. tostring(err)) end ok, err = ngx.timer.at(next_tick, _tick_proc, self) if not ok then if err ~= "process exiting" then ngx.log(ngx.ERR, "failed to create timer: "..tostring(err)) end endend
开始函数,注册event事件,所有进程都注册event事件处理函数,主进程用来进行健康检查,所有进程响应健康检查结果事件处理函数:
- notify事件 --> handle_notify处理函数
- 节点检测up时触发
- 调用on_peer_up函数链
- 移除watches监控列表
- 调用on_peer_removed 函数链
2.add_watch事件 --> handle_add_watch处理函数
- 添加watches监控列表
- 调用on_peer_added函数链
3.remove_watch事件 --> handle_remove_watch处理函数
- 移除watches监控列表
- 调用on_peer_removed 函数链
local function start(self, is_master) if self.__started then return end self._stop = false self.__started = true do -- register events local handle_notify = function(data, event, source, pid) if worker_exiting() then return end ngx.log(ngx.ERR, "handle_notify --> ahc events: "..require "cjson.safe".encode(data)) _notify_server_up(self, data.name, data.peer) end local handle_add_watch = function(data, event, source, pid) if worker_exiting() then return end _set_watch_context(self, data.name, data.ahc, data.peer) ngx.log(ngx.ERR, "handle_add_watch --> added events: "..require "cjson.safe".encode(data)) self.on_peer_added(self, data.name, data.peer) end local handle_remove_watch = function(data, event, source, pid) if worker_exiting() then return end local name = data.name local ctx = self.watches[name] if not ctx then return end self.watches[name] = nil ngx.log(ngx.ERR, "handle_remove_watch --> added events: "..require "cjson.safe".encode(data)) self.on_peer_removed(self, name, ctx.peer, false) end self._events = events.event_list("down_peer_checker", "notify", "add_watch", "remove_watch") events.register(handle_notify, self._events._source, self._events.notify) events.register(handle_add_watch, self._events._source, self._events.add_watch) events.register(handle_remove_watch, self._events._source, self._events.remove_watch) end if is_master then ngx.timer.at(0, _tick_proc,self) endend
add_watch 跟openresty多进程有关,不一定哪个进程会处理manager发送的API,所以需要event通知所有进程更新自己的watches列表
local function add_watch(self, watch_name, ahc, peer) events.post(self._events._source, self._events.add_watch, { name = watch_name, peer = { ip = peer.ip, port = peer.port, }, ahc = ahc })end
upstream_context 模块
相关代码:https://github.com/zhaoshoucheng/openresty/blob/main/pkg/lua_script/upstream/upstream_context.luaupstream_context之前没有引入健康检查功能,所以需要提供函数让down_checker去更新自身信息
生成负载均衡列表,会收到节点的信息up或down选择
local function process_upstream_nodes(nodes) -- 增加down标记 local ret = { } local def = { } for i = 1, #nodes do local d = nodes[i] if d.state ~= "up" then goto continue end local id = d.ip.."\0"..tostring(d.port) local ew = ret[id] if ew then ret[id] = (d.weight or 1) + ew def[id].weight = ret[id] else ret[id] = d.weight or 1 def[id] = d end ::continue:: end return ret, defend
更新函数
local function _update_node_state(self, name ,peer, status) for i = 1, #self._ups.nodes do local d = self._ups.nodes[i] if d.ip == peer.ip or d.port == peer.port then self._ups.nodes[i].state = status return end end ngx.log(ngx.ERR, "can"t find peer when dpc up: "..name)endlocal function dpc_on_added(self, name, peer) -- local sctx = _get_server_context(self, peer, true) -- sctx.dpc_state = "down" _update_node_state(self, name, peer, "down") local _, _all_nodes = process_upstream_nodes(self._ups.nodes) self._all_nodes = _all_nodesendlocal function dpc_on_up(self, name, peer) _update_node_state(self, name, peer, "up") local _, _all_nodes = process_upstream_nodes(self._ups.nodes) self._all_nodes = _all_nodes self._prefered_balancer = nilend
balance 模块
初始化down_checker模块,并且注册upstream_context的函数调用链(包括debug代码,模拟manager API调用)
local function _handle_down_peer_watched(dpc, watch_name, peer) local _, _, upname = watch_name:find("(.+)-") if upname then local uctx = get_upstream_context(upname) if uctx then uctx:dpc_on_added(watch_name, peer) end else ngx.log(ngx.ERR, "unexpected upstream name: "..tostring(upname)) endendlocal function _handle_down_peer_becomes_up(dpc, watch_name, peer) local _, _, upname = watch_name:find("(.+)-") if upname then local uctx = get_upstream_context(upname) if uctx then uctx:dpc_on_up(watch_name, peer) end else ngx.log(ngx.ERR, "unexpected upstream name: "..tostring(upname)) endendlocal function debug_down_watcher(p) local debug_ctx = down_watcher:debug_ctx() down_watcher:add_watch(__watch_name("server_test1", debug_ctx.peer), debug_ctx.ahc, debug_ctx.peer)endfunction _M.init(is_master) down_watcher = require(module_name.."down_peer_checker").new() down_watcher.on_peer_added:add_delegate2(_handle_down_peer_watched) down_watcher.on_peer_up:add_delegate2(_handle_down_peer_becomes_up) down_watcher:start(is_master) -- debug代码,模拟manager 发送API,通知down信息 if is_master then ngx.timer.at(1, debug_down_watcher) endend
被动健康检查
function _M.do_balance(ups_name)··· local sn, sc = ngx_balancer.get_last_failure() if not sn then -- first call local ok, err = ngx_balancer.set_more_tries(3) if err and #err > 0 then ngx.log(ngx.WARN, err) end key, idx = b:find(ctx.balance_key) if not key then ngx.log(ngx.ERR, "failed to get upstream endpoint") ngx.exit(502) return end else -- 被动健康检查 down_watcher:add_watch(__watch_name(ups_name, ctx.latest_peer), uctx._ups.health_check, ctx.latest_peer) key, idx = b:next(ctx.latest_idx) ngx.log(ngx.WARN, "rebalancing: "..sn..", "..tostring(sc)) end···end
测试
主动健康
1.关闭服务2.触发debug,模拟API调用,client请求信息,观察结果3.启动服务4.client请求信息,观察结果event更新负载均衡到up节点启动服务之后,健康检查成功,event通知负载均衡到不同节点
被动健康检查
1.关闭服务2.client请求信息,观察结果3.打开服务4.client请求信息,观察结果触发一次502,并用新节点替换,和API一致,进行event通知再次请求则直接负载均衡到正常节点,不会经过一次502打开服务后效果和主动健康检查的结果一致,这里不再赘述。
总结与思考
本文主要讲述了Openresty作为网关实现对动态节点的健康检查管理,只要讲解整个架构设计和核心代码,有些细节代码还需要去git上查看还需要补充一些技术细节
共享内存保存检测列表
现在的watches是local的临时变量,reload之后就没了,所以需要维护共享内存shm,来保存现有的全部需要监的服务节点,在初始化时,从shm中构建watches
提高健康检查效率
现在的健康检查是每次线性的对watches列表进行遍历,如果列表过多或单次健康检查服务阻塞,就会影响到其他的健康检查过程,所以需要ngx.thread.spawn增加轻量级线程去并行处理。
-
环球时讯:【网关开发】8.Openresty 网关自定义健康检查的设计与实现
背景使用Openresty作为网关进行动态节点IP负载均衡时,要求网关有能力在负载均衡之前摘除掉有问题的节点...
来源: -
记录--千万别让 console.log 上生产!用 Performance 和 Memory 告诉你为什么
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助很多前端都喜欢用console log调试,先...
来源: 环球时讯:【网关开发】8.Openresty 网关自定义健康检查的设计与实现
每日焦点!【0基础学爬虫】爬虫基础之爬虫的基本介绍
记录--千万别让 console.log 上生产!用 Performance 和 Memory 告诉你为什么
省选集训2023年2月9日T2
全球热讯:非油炸!吃欢天荞麦面皮10袋到手19.9元:麻酱、酸辣随便挑
世界今热点:ChatGPT版必应被华人小哥攻破:一句话“催眠”问出所有Prompt
世界热门:钙钛矿-硅光伏电池效率突破30%!可稳定工作30年
世界即时:公交车刹车提醒是2B请注意 当地回应:考虑不周将“改名”
环球热议:苹果忍不住反驳乔布斯女儿吐槽:iPhone 14比iPhone 13 Pro还要好
Entity Framework 教程_编程入门自学教程_菜鸟教程-免费教程分享
全球热文:【Spring】Bean注册注解
【当前独家】算法学习笔记(17): 快速傅里叶变换(FFT)
世界要闻:化繁为简|AIRIOT智慧水务信息化建设解决方案
环球资讯:让地球“流浪”前 先来研究下这一个更现实的威胁
女子疑吃自热火锅去世:不排除急性中毒、家属索赔176万元
当前消息!最香的i9+RTX 4080游戏本!ROG枪神7超竞版仅需18999元起
全球热讯:泰国1月份纯电动车上牌量排行:比亚迪称王、国产车霸榜
GTX 1060落魄了?《原子之心》1080P高画质需GTX 1080
环球关注:一步一腳印的 iOS App 上架和更新流程
当前快看:学习笔记——尚好房项目(项目介绍、环境搭建、配置依赖关系)
[数据结构] 二叉树的层次遍历
全球实时:JVM sandbox 实现热修复示例
《流浪地球2》全球爆火背后!《三体》导演:中国科幻的内核是文化自信
神十五航天员首次出舱视频公布:和地球同框 绝美
每日速看!方向盘助力失灵、AEB抽风!车主:百年凯迪拉克毁于LYRIQ 绝望
速递!Android 14来了:提升续航和流畅度
《狂飙》片头被指抄袭 网友放对比照跟国外一电影太相似:背后公司被扒
环球资讯:剖析字节案例,火山引擎 A/B 测试 DataTester 如何“嵌入”技术研发流程
Docker安装使用Kafka
每日动态!机器学习-KNN
全球热点评!网民称《水浒》应从中小学课文中清除 毒害更多人:浙江官方回应了
24岁生日当天崩了!腾讯QQ回应:服务器挤爆了 现已恢复
【全球报资讯】酒剑仙拿狙蚌埠住了 《仙剑奇侠传》五位角色入驻《和平精英》
如何注册 ChatGPT ,OpenAI
每日头条!A/B测试教程_编程入门自学教程_菜鸟教程-免费教程分享
环球即时看!24亿巨制大片 《速度与激情10》开启预售 片长130分钟
天天热点!魅族20 Pro外观偷跑:矩阵三摄 纯白机身太吸睛
世界今日报丨年轻人别以赚钱为目标!张朝阳称别把考试太当回事:不一定非上好大学
天天即时:中国在土耳其建造电站强震中未受损:稳定保障救援电力供应
实时焦点:微软公布ChatGPT版Bing不到48小时:申请用户量已超百万
天天热推荐:01-数据结构与算法-目录索引
环球快消息!keycloak~再说session和token
学习笔记——redis集群(定义、集群连接、查看集群、节点分配方式、插槽、集群中录入值、查询集群中的值、故障恢复)
滴滴一面:order by 调优10倍,思路是啥?
投诉不断 极氪被爆出现大规模动力故障 官方回应:会升级
焦点讯息:昆虫学硕士因表演双节棍获得工作 2000万粉大V感慨:掌握一门手艺很重要
当前报道:手机QQ崩了:显示无网络 你消息接收正常吗?
【环球新要闻】Moment推出1.55X变形镜头:iPhone也能拍出电影级超宽照片
十八罗汉分别叫什么?十八罗汉排名及顺序
马前泼水指的是什么生肖?马前泼水这个故事是什么意思?
巴黎恋人的结局是什么?巴黎恋人演员表
手净欲摸杯是什么意思?手净欲摸杯的出处是哪里?
环球观点:Linux 命令大全:2万字实现Linux自由
20088乐队现在怎么样?20088乐队现在怎么样了?
milo显示器是什么牌子?milo显示器怎么样?
ec文件是什么的简称?ec文件怎么打开?
神舟笔记本如何下载安装软件?神舟笔记本如何下载驱动?
tplink路由器怎么设置端口映射?tplink路由器怎么重新设置密码?
冰箱电磁阀怎么判断好坏?冰箱电磁阀的颜色代表什么?
票房榜前10稳了!《流浪地球2》总票房突破35亿 官方公布月球美术设计
每日信息:丰田皇冠遭车主集体投诉:空调管短了 漏水漏风
腾讯严惩《和平精英》外挂 一大批玩家一觉醒来发现被封号10年
高速特斯拉自动驾驶 驾驶员座位上睡觉!网友:保险赔吗?
世界实时:女子应聘人事被要求身高1米63以上 追问HR被回怼:不自信就不用了解了
最新资讯:keycloak~JWT没有被持久化_是因为你对方法论理解不到位
快喝不起了!农夫山泉涨价:纯净水、矿泉水啥区别、到底哪个好?
天天微头条丨在ChatGPT眼里 未来的汽车竟长这模样
天天快报!ChatGPT引发失业恐慌?这20种工作要避开:含医生、快递员
天天新动态:果然“超级奶爸”!李想晒六口全家福:期待五胎到来
订单充足不愁卖 国产特斯拉Model Y入门版涨价:贵了2000
环球滚动:学习笔记——redis持久化之RDB、AOF
BigDecimal加减乘除运算整合工具类
天天新资讯:4年还完20万欠款!夫妻回应剪掉名下所有信用卡 告别卡奴引网友感叹
天天热文:Win11又出严重bug:Intel用户程序崩溃 AMD躲过一劫
世界热点!1600人失业 老牌互联网巨头雅虎裁员20%:离职补偿未定
世界讯息:开窍!iPhone 15摄像头终于要升级:苹果设计让人抓狂 背部凸起更严重
环球视讯!3499元爆火!真我GT Neo5 1T版抢购一空:2023年旗舰射门员
世界最资讯丨日本国产大飞机失败:三菱重工不服输 自研新一代战机
天天看点:读Java实战(第二版)笔记06_新的日期和时间API
世界时讯:NVIDIA发布GeForce 528.49驱动:首发支持史上最强移动显卡
全球实时:网友50000元攒机 到底是不是大冤种?
今日热闻!基于高层次综合器(Vivado HLS)的硬件优化[原创www.cnblogs.com/helesheng]
你同意?张朝阳:《流浪地球2》跟好莱坞还是没法比
【天天时快讯】奇葩!哈尔滨机场一旅客为逃避安检把活蜗牛藏嘴里
环球热议:Google放大招对抗ChatGPT:结果低级答错题 市值蒸发1000亿
微头条丨单枪匹马也能拍大片!这次又让大疆给拿捏了
快资讯:史上最强AMD显卡!撼迅正式发布水冷RX 7900 XTX 还是单插槽
Spring配置类理解(Lite模式和Full模式)
环球速讯:JAVA中如何判断一个ResultSet结果集是否为空
【天天速看料】MYSQL脱敏 || 给开发人员限制权限,保证mysql数据库数据安全
重点聚焦!小白也能做应用(二)之fusion app增加B站视频页面
每日观点:法国调香师夸国产花露水清新还美丽 要卖450元 网友:六神YYDS
MATLAB 实现点云累计-坐标系转换-目标范围点云提取(附代码与代码注释)
【全球快播报】面向对象知识点汇总(小白必会)
(一)浅谈人工智能:ChatGPT
《蚁人3》女儿凯茜中文预告公布 首映礼美艳图赏
环球热消息:【一句话】@Configuration和@Component的区别
世界看热讯:《分布式技术原理与算法解析》学习笔记Day06
焦点消息!ASP.NET Core+Element+SQL Server开发校园图书管理系统(完)
全球看点:if else 代码优化实战