最新要闻
- 焦点热议:年轻人的第一台影像旗舰!卢伟冰:Redmi Note 12 Pro系列绝对可以
- 天天观速讯丨东北大哥8小时狂炫40斤砂糖橘 网友提醒:当心变黄
- 全球报道:《魔兽世界》国服即将停运!最后一周超7千帐号开挂被封
- 世界看热讯:近千亿国产半导体公司卓胜微净利润暴降超50%:大家确实不爱换手机!你换没
- 全球速读:呆萌!66只考拉七代同堂齐送新春祝福
- 不是安卓!鸿蒙系统成大学教材 “鸿蒙之父”王成录参与 培养开发者
- 焦点热议:美国科技史上最大规模裁员开启:亚马逊、微软“毕业”均超万人
- 全球快播:25年历史的笔记本内存将被淘汰 新标准单条可达128GB 频率更快
- 环球最新:24年前经典重现!《轩辕剑叁:云和山的彼端》将推出Switch版本
- 世界微动态丨三亚已成全国最堵城市:国人扎堆去海南 能堵到你哭泣
- 焦点精选!零下30度 东北司机穿10斤棉裤冒雪下乡送年货:网友为劳动者正能量点赞
- 焦点播报:大年初一上映!《流浪地球2》要做中国科幻片天花板 特效拉满
- 全球今日报丨曾致苹果华人工程师身亡!FSD造假实锤:特斯拉技术大牛证实
- 短讯!强推Win11:微软即将停售Win10数字许可
- 全球速看:iPhone 14 Pro Max屏幕抽风出现死亡横线:iOS 16.3终于修复了
- 当前资讯!质量堪忧 退换货激增!AMD旗舰显卡RX7900 XTX游戏实测近3.5GHz 你买吗?
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
天天观速讯丨【网关开发】5.Openresty 自定义负载均衡与流量转发
- 背景
- 应用架构
- 实现
- 插件
- 配置文件
- 流量转发
- 负载均衡器
- 测试
- 总结
- 扩展
- ip_hash
- url_hash
背景
静态的nginx配置需要将负载均衡的服务节点信息都配置在配置文件中。现在微服务或云服务都会接入一些服务发现或者云控平台场景,经常需要更换节点,如果每次都要更新配置并且重启服务是无法接受的,所以需要网关提供动态扩展,实时更新自己负载均衡节点的能力,使用openresty网关需要使用lua扩展来实现自定义负载均衡的能力。
【资料图】
应用架构
实现
本文展示openresty如何开发,有一些结构体与细节可以直接去git上查看https://github.com/zhaoshoucheng/openresty/tree/main/pkg/lua_script使用插件地址:https://github.com/openresty/lua-resty-balancer"整体实现摸快配置文件摸快:nginx的conf配置文件lua-resty-balancer 插件:负载均衡器upstream_context : 从etcd中获取相应的服务节点,通过负载均衡类型,获取负载均衡器
插件
编译lua-resty-balancer插件简单,进入文件夹make就可以,然后会生成librestychash.so文件,将其放入到我们可以引入到的文件夹中例如
lua_package_cpath "/data/openresty/pkg/lua_script/?.so;;";
配置文件
upstream server_test1 {server 0.0.0.0:1234;balancer_by_lua_block { if etcd_source_module then require "upstream.balance".do_balance("server_test1") else ngx.exit(502) end }}
etcd_source_module etcd数据模块,负责从etcd中获取服务server_test1的IP,这里知识检查作用。do_balance 实现流量转发的模块函数
流量转发
local transform_data_simple = utils.transform_data_simplelocal module_name = (...):match("(.-)[^%.]+$")local upstream_context = require(module_name.."upstream_context")local conf = require(module_name.."config")local utils = require(module_name.."utils")local ngx_balancer = require "ngx.balancer"local cjson = require "cjson.safe"-- 从etcd中获取数据,通过transform_data_simple 转化数据local function get_upstream_context(name) local ctx = upstream_contexts[name] if not ctx then local ups = etcd_source_module:get_value(name) if not ups then return nil, "upstream configure not found: "..name end ups = transform_data_simple(ups) if ups then ctx = upstream_context.new(name, ups) upstream_contexts[name] = ctx end end return ctxendfunction _M.do_balance(ups_name) local ctx = ngx.ctx local uctx, err = get_upstream_context(ups_name) if not uctx then ngx.log(ngx.ERR, ups_name..", "..tostring(err)) ngx.exit(502) return end -- 获取负载均衡器 local b, err = uctx:get_prefered_balancer() if not b then ngx.log(ngx.ERR, "failed to get balancer: "..tostring(err)) ngx.exit(502) return end -- 上次失败的节点要在下次节点中避免选择 local key, idx 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 -- 根据上次的负载情况选择下次的节点 key, idx = b:next(ctx.latest_idx) ngx.log(ngx.WARN, "rebalancing: "..sn..", "..tostring(sc)) end ngx.log(ngx.ERR,"do_balance b"..cjson.encode(b)) -- 打印负载均衡器 -- 从所有节点中进行选择 local peer = uctx._all_nodes[key] ngx.log(ngx.ERR,"do_balance uctx._all_nodes"..cjson.encode(uctx._all_nodes)) -- 打印_all_node 信息 if not peer then ngx.log(ngx.ERR, "failed to get upstream endpoint: "..tostring(key)) ngx.exit(502) return end ctx.latest_peer = peer ctx.latest_key = key ctx.latest_idx = idx -- 流量转发函数 local ok, err = ngx_balancer.set_current_peer(peer.ip, peer.port) ngx.log(ngx.INFO, string.format(" do balance ip :%s point: %s", peer.ip, peer.port)) -- 打印目标节点 if not ok then ngx.log(ngx.ERR, string.format("error while setting current upstream peer %s: %s", peer.ip, err)) ngx.exit(500) return endend
看下_all_nodes的结构,map结构key值是传入负载均衡器的值,后面会有用到
2023/01/19 14:41:32 [error] 17588#0: *234587 [lua] balance.lua:66: do_balance(): do_balance uctx._all_nodes{"10.218.22.246\u00008090":{"state":"up","fail_timeout":3000,"weight":1,"ip":"10.218.22.246","max_fail":3,"port":8090},"10.218.22.239\u00008090":{"state":"up","fail_timeout":3000,"weight":1,"ip":"10.218.22.239","max_fail":3,"port":8090}} while connecting to upstream, client: 10.99.4.169, server: server_test.com, request: "GET /ping HTTP/1.1", host: "server_test.com:9090"
打印每一次获得负载均衡器
2023/01/19 14:45:32 [error] 17656#0: *234610 [lua] balance.lua:67: do_balance(): do_balance b{"gcd":1,"cw":1,"nodes":{"10.218.22.239\u00008090":1,"10.218.22.246\u00008090":1},"last_id":"10.218.22.239\u00008090","max_weight":1} while connecting to upstream, client: 10.99.4.169, server: server_test.com, request: "GET /ping HTTP/1.1", host: "server_test.com:9090"
负载均衡器
-- 获取负载均衡器local function get_prefered_balancer(self) local b = self._prefered_balancer local err = nil if not b then local nodes, _ = process_upstream_nodes(self._ups.nodes) local lb = self._ups.load_balance local err ngx.log(ngx.ERR,"get_prefered_balancer nodes"..cjson.encode(nodes)) -- 打印nodes数据 b, err = balancers.create(lb.type, nodes) if not b then return nil, err end self._prefered_balancer = b end return b, errend
不需要过度关注结构体的设计,用法场景不同,结构体自然不同,比较灵活,process_upstream_nodes目的就是选出目标所有可用的节点,可以结合健康检查结果,或者流量规则进行使用最终生成的nodes就是map的key,权重的结构。将其作为负载均衡插件的参数。
2023/01/19 14:29:14 [error] 17335#0: *234481 [lua] upstream_context.lua:78: get_prefered_balancer(): get_prefered_balancer nodes{"10.218.22.239\u00008090":1,"10.218.22.246\u00008090":1} while connecting to upstream, client: 10.99.4.169, server: server_test.com, request: "GET /ping HTTP/1.1", host: "server_test.com:9090"
选择负载均衡器,将提供的负载均衡器封装成函数
local roundrobin = require("resty.balancer.roundrobin")local chash = require("resty.balancer.chash")local iphash = require("resty.balancer.iphash")local urlhash = require("resty.balancer.urlhash")local _M = { }local function create(typ, ...) if typ == "roundrobin" or typ == "round_robin" then return roundrobin:new(...) elseif typ == "chash" then return chash:new(...) elseif typ == "iphash" or typ == "ip_hash" then return iphash:new(...) elseif typ == "urlhash" or typ == "url_hash" then return urlhash:new(...) else return nil, "unsupported balancer type: "..tostring(typ) endend_M.create = createreturn _M
测试
round_robin 测试
ip_hash 测试
总结
当然企业级工程不可能这么简单,这只是核心的细节。我试图将复杂的整体工程拆分成一个一个的小知识点来进行分析,学习。完善自己的知识体系。所以单单是看单个知识点都比较简单。尽量避免了一些复杂的结构体和复杂的业务场景来讲解架构与知识点,这样更加的容易理解。能把一件事情讲明白其实是一件很不容易的事情,如果有不解或者有误的地方欢迎沟通交流,有些细节代码也上传了github,欢迎查看。https://github.com/zhaoshoucheng/openresty/tree/main/pkg/lua_script
扩展
因为github插件上提供的都是基础功能round_robin和chash,其实其他负载均衡算法也可以在这上面进行扩展。或者实现自己的负载均衡算法。现在提供ip_hash 和 url_hash的写法
ip_hash
local module_name = (...):match("(.-)[^%.]+$")local chash = require(module_name.."chash")local setmetatable = setmetatablelocal _M = { _VERSION = "0.1" }local _MT = { __index = _M }function _M.new(_, nodes) return setmetatable({ _chb = chash:new(nodes) }, _MT)endfunction _M:reinit(nodes) self._chb:reinit(nodes)endfunction _M:set(...) self._chb:set(...)endfunction _M:find() return self._chb:find(ngx.var.remote_addr) -- TODO: use xff ?endfunction _M:next(...) self._chb:next(...)endreturn _M
url_hash
local module_name = (...):match("(.-)[^%.]+$")local chash = require(module_name.."chash")local setmetatable = setmetatablelocal _M = { _VERSION = "0.1" }local _MT = { __index = _M }function _M.new(_, nodes) return setmetatable({ _chb = chash:new(nodes) }, _MT)endfunction _M:reinit(nodes) self._chb:reinit(nodes)endfunction _M:set(...) self._chb:set(...)endfunction _M:find() return self._chb:find(ngx.var.uri)endfunction _M:next(...) self._chb:next(...)endreturn _M
天天观速讯丨【网关开发】5.Openresty 自定义负载均衡与流量转发
观点:100w人在线的 弹幕 系统,是怎么架构的?
焦点热议:年轻人的第一台影像旗舰!卢伟冰:Redmi Note 12 Pro系列绝对可以
天天观速讯丨东北大哥8小时狂炫40斤砂糖橘 网友提醒:当心变黄
全球报道:《魔兽世界》国服即将停运!最后一周超7千帐号开挂被封
世界看热讯:近千亿国产半导体公司卓胜微净利润暴降超50%:大家确实不爱换手机!你换没
全球速读:呆萌!66只考拉七代同堂齐送新春祝福
全球播报:非对称加解密算法SM2
世界简讯:从合并石子学区间DP
环球快播:Golang的基本数据类型-基本使用
不是安卓!鸿蒙系统成大学教材 “鸿蒙之父”王成录参与 培养开发者
焦点热议:美国科技史上最大规模裁员开启:亚马逊、微软“毕业”均超万人
全球快播:25年历史的笔记本内存将被淘汰 新标准单条可达128GB 频率更快
环球最新:24年前经典重现!《轩辕剑叁:云和山的彼端》将推出Switch版本
世界微动态丨三亚已成全国最堵城市:国人扎堆去海南 能堵到你哭泣
焦点精选!零下30度 东北司机穿10斤棉裤冒雪下乡送年货:网友为劳动者正能量点赞
焦点播报:大年初一上映!《流浪地球2》要做中国科幻片天花板 特效拉满
学习笔记——SpringMVC简介;SpringMVC处理请求原理简图;SpringMVC搭建框架
全球今日报丨曾致苹果华人工程师身亡!FSD造假实锤:特斯拉技术大牛证实
短讯!强推Win11:微软即将停售Win10数字许可
观天下!Win系统下实现任意exe静态免杀
全球速看:iPhone 14 Pro Max屏幕抽风出现死亡横线:iOS 16.3终于修复了
当前资讯!质量堪忧 退换货激增!AMD旗舰显卡RX7900 XTX游戏实测近3.5GHz 你买吗?
当前视点!还有5天关服 魔兽世界怀旧服免费玩 网易高管:出问题就找暴雪
低配版《黑神话:悟空》即将发售!新实机预告公布
“搭桥”运工具 波士顿动力机器人展示新技能:网友却不认账
佛诞是哪个国家的节日?佛诞日是农历的哪一天?
如来佛拈花一笑是什么意思?如来佛拈花一笑的故事
五常指的是哪五常?五常是什么时候建立的?
卫生衣是什么东西?卫生衣是什么季节穿的?
学习笔记——Spring声明式事务管理属性(隔离级别、事务超时、事务只读、事务回滚);Spring5新特性、新注解&整合log4j2;Spring5整合Juni
AIRIOT答疑第6期|如何使用二次开发引擎?
村的由来是什么?中国省市县区等级划分
思科路由器怎么进入设置界面?思科路由器配置命令大全
宝岛眼镜是哪里的品牌?宝岛眼镜怎么样?
开心消消乐什么时候上线的?开心消消乐怎么求助好友过关?
电脑重装系统后没有声音是怎么回事?电脑重装系统后没有声音怎么办?
b站在线人数在哪里看?b站在线人数怎么关闭?
国产芯的iPhone 14 Pro!乐视手机S1 Pro现货发售:仅899元
【当前热闻】嚣张!飞度女应急车道超车未果打砸后车被刑拘 受害车主回应
观速讯丨专为游戏优化!AYANEO OS掌机操作系统官宣2023年上线
国产科幻巨制!《流浪地球2》终极预告发布:大年初一上映
焦点要闻:红灯藏在成片红灯笼里引司机吐槽:差点6分没了
【天天播资讯】店主卖自制香肠遭男子10倍索赔 被法院驳回:网友大赞判决
世界视点!55天徒步跨越1600公里!沙特一观众获国际足联最佳球迷奖提名
【世界新视野】坐等分钱!全球205位富豪呼吁征收财富税:现在就向我们征税
全球首款独显掌机!AYANEO官宣NEXT 2将搭载锐龙7000系处理器
东芝高管放言:SSD硬盘永远无法取代机械硬盘
全球新资讯:Array 数组
读编程与类型系统笔记11_高级类型及其他
游戏对PC性能需求走向失控:16G内存已成最低要求
【世界时快讯】8900元!TP-Link最新Wi-Fi7路由器BE900上架 网速达24Gbps
观焦点:售价曝光!RTX 4060 Ti一塌糊涂 NV各种秀刀法:你会买?
新资讯:中金公司10大预测错9个:称电动车高景气 结果宁德时代年度最惨
世界速看:穷疯了?13岁儿女起诉父亲还压岁钱1.68万 官方回应压岁钱是个人私有财产
天天快报!“丑”出圈!蓝兔子邮票身价暴增 溢价幅度接近300%
过年租车7天起 日租价上涨近7倍:还定不到现车
【世界独家】西藏林芝一隧道出口雪崩 8人遇难:失联者家属称丈夫计划回家过年
全球要闻:近8年最大规模!微软正式宣布将裁员1万人
百事通!《阿凡达2》全球票房破19.28亿美元:成全球影史第六
观速讯丨CSS3选择器总结(表格)
年味十足!苹果发布iPhone兔年限定壁纸:苹果Logo变兔头
热门:“三体 脱水”登顶热搜 于和伟游戏刚上线游戏就下线
焦点速讯:“巨型屎山”QQ终于要史诗级重写!但是腾讯被骂惨了
口碑爆棚!冒险游戏改编剧《最后生还者》豆瓣开分9.2分
全球热推荐:AMD被大大看好:抢走Intel 30%市场!
【天天新视野】SpringBoot Wiki项目部署记录
环球微速讯:学习笔记——Spring声明式事务管理;Spring中支持事务管理;使用声明式事务管理;Spring声明式事务管理属性
世界热门:C. Equal Frequencies
全球播报:雷军:小米13用了昂贵的高硅负极电池才把容量做到4500mAh
世界简讯:Qt项目-翻金币游戏
lambda表达式基础
java-数组相关的算法(尚硅谷)
Pytorch-geometric: Creating Message Passing Networks 构建消息传递网络教程
把魔兽停服当庆典营销 网易《逆水寒》被曝涉嫌抄袭暴雪IP
当前热讯:《黑神话:悟空》定档:想玩记得升级电脑
快播:2022年预制菜销量大涨!之前有专家还说“我从来不吃”
7层WAF的一些记录
天天新动态:Numpy基本使用方法
[数据结构]单向链表插入排序(C语言)
世界报道:高铁站大厅没插座 客服:为了消防安全
滚动:你遇到过没?货车安装超亮后射灯:夜晚跟车根本看不清
时讯:首发2亿像素HP2!三星Galaxy S23 Ultra万元机皇来了
观察:口碑爆棚!剧版《三体》市占率16.51%排行第一
当前要闻:BC4-牛牛学说话之-浮点数
【独家焦点】关于可迭代对象、迭代器对象、生成器对象
环球快消息!AcWing 1077. 皇宫看守
年终会员大促:B站/芒果TV/腾讯视频/优酷/百度网盘3.6折起
三电机真恐怖!特斯拉Model S Plaid瞬间撕裂马力机张力带
焦点热讯:内置LED屏见过没?Naspec推出高端HDMI 2.1数据线
焦点要闻:美国一州提案禁售电动汽车 议员:就看不惯“禁售燃油车”的提议
环球热门:电动车新国标过渡期陆续到期 雅迪股价半月暴涨3成
vue3_ts_defineProps的使用
合作谈崩了 暴雪还想让网易当半年“备胎”?
特斯拉Model S之后:一改装公司推出福特电马灵车和礼宾车
今日讯!魅族Flyme牵手中国电信天翼终端!软硬件生态全面融合
学习笔记——定义切面优先级 ;Spring中的JdbcTemplate;JdbcTemplate的常用API
当前短讯!从0开始学Java 第一期 开发前的准备
小心吃官司 央视发布声明:2023兔年春晚内容别乱用
世界焦点!华硕发布Vivobook S 16 Flip笔记本:16寸3.2K OLED翻转屏