码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • Openresty(二十二)ngx.balance和balance_by_lua终结篇


    一  灰度发布铺垫

    ①  init_by_lua*

    init_by_lua   

    init_by_lua_block

    1. 特点: 在openresty 'start'、'reload'、'restart'时执行,属于'master init' 阶段
    2. 机制: nginx 'master' 主进程'加载配置文件'时,运行全局Lua VM级别上的参数指定的'Lua代码'
    3. 场景: 想对于应用'做一次全局性'的初始化

    1. 案例1: init阶段'已经加载'的模块会放在'package.loaded'中,供'后续阶段'直接使用
    2. 备注: 在'初始化时'候加载过了,已经在 package.loaded '表'里

    案例2: ' lua_shared_dict' 和 'ngx.shared'的'set、get'方法结合使用

      

    当配置重载时,init_by_lua* 不会清空其内的lua_shared_dict共享数据

    1. 注意事项: 只能使用'print'、'ngx.log' API 和 'lua_shared_dict' 指令
    2. 推荐: 在'init_by_lua'中调用'require()'来加载自己的模块文件
    3. 特点:
    4. 1) require()会在全局Lua注册的'package.loaded表'中缓存Lua模块
    5. 2) 所以在'整个Lua虚拟机实例中'你的模块将'只会加载一次'
    6. 补充: 'init_by_lua*'中master进程'执行'lua代码

    1. 案例3: 阻塞'I/O'调,执行'shell'命令 --> '特殊场景'
    2. 1、在这个'上下文'中,你可以保守使用'lua库'完成阻塞I/O调用
    3. 2、因为在'master进程'的阻塞调用在服务的启动过程中是完全'没问题'的
    4. 3、进一步说在'配置加载'阶段,Nginx核心就是'阻塞 I/O 方式'处理的
    5. 场景: 采用在'init阶段'调用'shell'命令

    lua执行系统命令方法os.execute和io.popen      init_by_lua_file不能连接redis

    注意: 此处的'content'是'字符串',需要自己重新解析成字典,可以存入变量,也可以存在共享内存中

    init_by_lua_file 

    说明: '推荐'使用'init_by_lua_file'

    ②  init_worker_by_lua*

    说明: ​官方对'init_worker_by_lua*'并没有'API'的限制

    init_worker_by_lua

    init_worker_by_lua_block

    1. 1、在'每个'nginx worker进程启动时调用'指定'的lua代码
    2. 2、用于启动一些'定时'任务:比如'心跳'检查,定时'拉取'服务器配置等等
    3. 强调:此处的任务是'跟Worker进程数量'有关系的,不要'重复'了,那么如何'避免'重复呢?

     ngx.worker.id判断某个worker进行初始化

    说明: 使用ngx.timer可以'突破' init_worker_by_lua 中'不能使用 cosocket' 的限制

    如何在 init_worker_by_lua 阶段连接redis/mysql/dns    redis连接池封装

    ③   lua_shared_dict

    ④   ngx.shared.DICT

    ngx.shared共享内存操作

    二   灰度发布案例

    建议: 配置'指令'和'代码'解耦,这里暂时'不讲究'了

    ①  业务流程图

    1. canary --> gray --> '灰度'
    2. LBM: 做'配置下发'的时候,UI侧会有一个'gray灰度'开关按钮,在upstream生成对应的'代码'片段
    3. 形如:
    4. upstream {
    5. server 127.0.0.1:80;
    6. balance_by_lua 'lua/gray.lua'
    7. }
    8. 备注: 这里暂时'不讨论 upstream{}'内的健康检查
    9. ​
    10. 再次强调: 同一个'schema'集群内选举灰度节点,也即'集群内'灰度引流,而不是'集群间'引流

    1. 补充:
    2. 1、一般会将'灰度策略'先写入'DB',例如'mysql'中
    3. 2、利用'bgr灰度插件'解析从'redis'拉取的'灰度'策略,返回'灰度节点'信息
    4. 3、init_worker_by*的'功能'
    5. 1) 从'redis'中拿灰度策略,放到'ngx.shared本地缓存'中
    6. 2) 启动定时任务,定时'异步'拉取'灰度'策略

    ②  相关参考

    openresty+Lua+Redis灰度发布     高性能软件负载OpenResty整合Reids集群配置

    关于openresty的全局初始化问题   基于openresty/lua-resty-redis 二次封装的工具库

    Lua Redis 使用   Java Redis 预热数据    openresty定时任务    限制定时任务耗尽资源

    k8s灰度发布

    1. +++++++++++++ "题外话" +++++++++++++
    2. 1、一般会'将nginx的配置信息'写到'数据库'中,然后通过nginx+consul-template 做'配置渲染'
    3. 假定: mysql中的 'region'、'集群名'能唯一的决定一个'集群'的配置信息
    4. 附加: 其中'upstream_id'是其一个'field'字段
    5. 2、利用每个'upstream_id'的schmea的'不能'重复的特性
    6. 应用: 根据'upstream_id'获取'后端服务器'列表
    7. 补充: 后端服务器列表的信息在'对应服务配置'注册LB,做'配置下发'的时候已经'写入'数据库

    ③  代码雏形1

    1. 说明: 通过'init_worker_by_block' + 'ngx.timer.every' 实现定时'拉取'redis配置数据
    2. 实现: 管理面将策略'下发'到redis后,openresty '定时[5min]'从redis中'拉取'数据

    1. 遗留: redis'资源池'如何'复用'?
    2. nacos能实现'灰度发布'吗?
    3. 灰度用户请求中'打上'标签: 'gray=true'

    ④  灰度策略管理面

    1. 说明: 一般会通过'UI'将策略下发到'redis'中,这里我们'模拟'手动将'key'写到缓存数据库中
    2. 关键: redis 'key' 组成,一般会通过':'分割,分割的'每一个字段'都是一个'维度'特征信息
    3. 模拟'key': 这里'假定'key是'uuid:ip'形式,讲解一种'简单'的形式,key的'组成'反映'特征'形式
    4. 常见: $upstream_id:$tenant --> 保证这个'key'的唯一性
    5. 模拟'value': 'ip:port'形式,要'与'upstream关联[存储在'mysql'中],选取'某个server 节点'
    6. 补充: 业界喜欢称一个'upstream'为一个'schema'
    7. 后续设计: UI侧可以设置'多种灰度特征策略',然后选取'灰度'节点信息
    8. 也即: 在'后台管理系统中'添加'ip'、'用户名'灰度白名单后
    9. +++++++++++++++ "典型案例" +++++++++++++++
    10. 灰度策略配置'UI'侧设计:
    11. 1、'region'、'集群名称'、LB类型 进行 '灰度'策略的下发
    12. 2、对应'server'块的'域名'、'端口'、'location'信息

    OpenResty的Redis模块踩坑记录   openresty操作redis,null处理    redis连接池

    1. 1、'遍历'key
    2. 2、key的'设计',到底是'hash'结构,还是'其它'数据结构?

    ⑤   灰度机制

    1. 1、'优先'从'本地缓存'中去取
    2. local cacheip = cache_ngx:get('gray_key')
    3. 2、本地缓存中'不存在',去'redis缓存服务中'去取,然后加载到'本地'缓存
    4. 检查'redis缓存中的键'是否存在 --> if redis_client.exists(key):
    5. if cacheip == "" or cacheip == nil or cacheip == ngx.null then
    6. 3、通过本地'ngx.shared 一级'缓存 和 redis'二级'缓存

    高并发灰度策略    小破站诡异0问题    openresty最佳实践   灰度发布

    ⑥  代码雏形2

    细节: balance_by_lua 会 '忽略' upstream中的'server'配置
    

    1. 用到的'两个'指令: ​​access_by_lua_file 和 ​​balancer_by_lua_file
    2. 1、在'前一个指令'中获取'租户'信息选择'灰度'节点;
    3. 2、在'第二个指令'中根据获取的信息'执行'负载均衡,进行'转发';

    不依赖于balance_by_lua实现灰度发布

    1. # 另外一种方式 --> 这种'不依赖'于'balance_by_lua'做判断
    2. upstream default_route {
    3. ...
    4. }
    5. location /gray {
    6. set $backend 'default_route';
    7. rewrite_by_lua_file 'lua/gray.lua'; # 获取灰度节点的'逻辑'
    8. proxy_pass http://$backend;
    9. }
    10. 强调: 如果使用 'content_by_lua' 这个命令,就'无法'在进行'proxy_pass'了,会'冲突'

    openresty实现灰度发布 

    利用 proxy_pass 及lua指令 set_by_lua 动态修改当前 upstream 变量实现灰度发布

    ngx_balancer.set_more_tries设置不生效,导致无限重试

    OpenResty balancer_by_lua负载均衡原理解析    Openresty专栏     跨域

    OpenResty火焰图性能分析工具安装     Nginx调试工具Coredump    Lua性能优化

    ⑦   lua/gray.lua 灰度插件

    1. 考虑: 如果'不是灰度白名单',则要使用原来的'负载均衡'策略
    2. --> '如何解决呢?' --> '重点'
    3. 最佳实践: 自定义'负载均衡'算法
    4. 引申:在'配置'注册的阶段,如果使用'灰度'策略,那么后续如何'取消'呢?

    ⑧  lua/gray_access.lua  灰度策略命中

    1. 重点: 从redis读取'租户'信息,如果有就'存'到 ​​ngx.ctx​​ 中
    2. -- 太'累'了,九不往这里贴代码了,后续有时间再补充

    ⑨   测试

    思考:用户如何将用户'特征'信息传递过来? --> 'request Header'、'查询参数'

    ⑩  题外话

    local http = require("resty.http")  -->  http'相关'模块

    深入理解ngx.log

     lua_code_cache

    openresty 项目问题汇总

    nginx主动加载配置文件

    openresty性能对比 

    1. lua_load_resty_core on|off
    2. 自v0.10.16版本起'该指令'就在本模块'失效'了
    3. 当前resty.core模块会在'Lua VM初始化'的时候被'强制加载',不需要再显示'require'加载
    4. lua + nginx可以'作为网关'进行 '限流'、'流控'和'多级缓存'使用
  • 相关阅读:
    动态代理模式下UndeclaredThrowableException的产生
    基于JAVA上虞烟草物流配送系统计算机毕业设计源码+数据库+lw文档+系统+部署
    docker Desktop开启远程访问端口
    CentOS常见的命令
    GLIBC中的Symbol Versioning
    基于单片机的高精度心理测试仪设计
    QCN6274 vs QCA9880: Comparison of SOC and wireless communication chips
    基于降阶扩张状态观测器的逆变系统重复控制设计
    【编程题】【Scratch四级】2021.12 森林运动会
    什么是分布式锁?几种分布式锁分别是怎么实现的?
  • 原文地址:https://blog.csdn.net/wzj_110/article/details/132939891
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号