百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

通过 Consul+OpenResty 实现无reload动态负载均衡

off999 2025-02-16 22:27 16 浏览 0 评论

上篇文章使用 consul-template模板方式,来实现了nginx动态负载均衡的实现,但是会有一些问题,如果后端服务经常变动,那nginx需要重新reload,会有一些性能损耗,今天再分享另外一种不需要reload的方式即可实现动态负载均衡

上一篇地址:有兴趣的可以看一下 Nginx利用Consul实现动态负载均衡

1. 准备工作

由于需要使用到lua的一些第三方包,以前都是手动下载包,这次使用lua包管理器LuaRocks来管理第三方包

1.1安装LuaRocks

Bash
 #下载
 wget https://luarocks.org/releases/luarocks-3.9.1.tar.gz --no-check-certificate
 #解压
  tar -zxvf luarocks-3.9.1.tar.gz 
 #编译 安装 我的openresty安装目录在 默认安装目录/usr/local/openresty 
 ./configure --prefix=/usr/local/openresty/luajit --with-lua=/usr/local/openresty/luajit  --with-lua-include=/usr/local/openresty/luajit/include/luajit-2.1
 #安装
 make && make install
 #将可执行文件移动到/usr/bin目录中(此步骤可省) 方便在哪都可以运行
 mv  luarocks /usr/bin/
 

1.2 安装 openresty中的lua扩展依赖 lua-resty-http

lua-resty-http 是Openresty的http客户端 是基于cosocket 实现的,也是可以实现同步非阻塞的,你懂的吧? 推荐使用,但是到现在为止 它是在init_by_lua和init_worker_by_lua下不能使用的,所以只能使用luasocket,但是这个是阻塞的,效率不高,慎用!!

Bash
 #安装lua-resty-http
 luarocks install lua-resty-http
 #安装 luasocket,可能需要安装gcc 
 yum install gcc (如果需要则安装)
 luarocks install luasocket

1.3 修改nginx.conf配置,添加lua自定义模块路径和定义共享内存大小

 #vim /usr/local/openresty/nginx/conf/nginx.conf
 #在http块下添加内容如下:
  #配置dns解析
     #设置共享内存大小 这里的位置一定要放在加载lua文件前
     lua_shared_dict upstream_list 10m;
  #配置lua自定义模块路径,我把lua文件都放在了lua_script目录下(这个可以自定义)
     lua_package_path "/usr/local/openresty/nginx/lua_script/?.lua;;";
     
 

2 编写自定义lua模块

  • 创建upstreams.lua文件
 local http=require "socket.http"
 local cjson= require "cjson"
 local ltn12=require "ltn12"
 local _M={}
 -- 更新列表
 function _M:update_upstreams()
  local resp ={}
  http.request{url="http://10.10.100.3:8500/v1/catalog/service/go-server",sink=ltn12.sink.table(resp)}
  local resp=table.concat(resp)
   local resp=cjson.decode(resp)
 
  local upstreams ={}
  for i,v in ipairs(resp) do
    upstreams[i]={ip=v.ServiceAddress,port=v.ServicePort}
  end
  local s =ngx.shared.upstream_list
   ngx.shared.upstream_list:set("go-server",cjson.encode(upstreams))
 end
 -- 获取负载列表
 function _M:get_upstreams()
         local upstreams_str=ngx.shared.upstream_list:get("go-server")
         local tmp_upstreams=cjson.decode(upstreams_str)
         return tmp_upstreams
 end
 return _M
 
  • nginx.conf的配置如下(我这里写到了一个新conf文件中)
#第一次初始化
init_by_lua_block {
local upstreams=require("upstreams")
        upstreams.update_upstreams()
}
#定时更新
init_worker_by_lua_block {
        local upstreams =require("upstreams")
        local resty_lock=requrie("resty.lock")

        local handle=nil
        handle=function()
                -- 这里可以使用resty.lock来做下并发控制
        		local lock,err=resty_lock:new("my-lock")
        		if lock then
        			upstreams.update_upstreams()
        			lock:unlock()
        		end
                
                ngx.timer.at(5,handle)
        end
        ngx.timer.at(5,handle)
        #在定时更新时,也可以做些健康检查的动作
}
upstream go-server {
        server 0.0.0.1 down; #占位符
        balancer_by_lua_block {
         local balancer =require("ngx.balancer")
         local upstreams=require("upstreams")
         local tmp_upstreams =upstreams.get_upstreams()
         local ip_port=tmp_upstreams[math.random(1,table.getn(tmp_upstreams))]
         balancer.set_current_peer(ip_port.ip,ip_port.port)
        }
         local tmp_upstreams =upstreams.get_upstreams()
         local ip_port=tmp_upstreams[math.random(1,table.getn(tmp_upstreams))]
         balancer.set_current_peer(ip_port.ip,ip_port.port)
        }
}
server {
  listen       8001;
  server_name  localhost;
  location /test {
        default_type text/html;
        proxy_pass http://go-server;

}


  error_page 404 /404.html;
      location = /40x.html {
  }
  error_page 500 502 503 504 /50x.html;
      location = /50x.html {
  }
}
  • 其他问题
  • 在主动拉取列表时,是可以对服务做健康检查的,这里没有实现
  • 另一个问题,由于定时拉取,所以更新是不及时的,有延迟,但是 也可以解决, nginx可以暴露接口,让服务主动推送也是可以的
  • 这里均衡算法是有问题的 ,生产环境还需要重新设计
  • 我这里由于consul中设置的是 故障检查失败后30s才删除服务,所以会导致 网站有短暂的不可访问,解决办法:
  • 1 缩短故障检查失败后删除时间间隔,
  • 2 在定时器中做健康检查,发现异常,直接删除缓存中的数据

总结:

实现nginx无reload 即可更新配置的的要点

需要利用lua_shared_dict 参数来实现多个进程间共享数据,

通过 定时器 ngx.timer.at 实现定时更新数据

相关推荐

一键打包,随时运行,Python3项目虚拟环境一键整合包的制作(Venv)

之前我们介绍了如何使用嵌入式Python3环境给项目制作一键整合包,在使用嵌入式Python环境时,通常是作为另一个应用程序的一部分,而Python3虚拟环境是为了在开发过程中隔离项目所需的...

PyInstaller 是一个将 Python 代码打包成可执行文件的工具

PyInstaller是一个将Python代码打包成可执行文件的工具。它可以将Python代码打包成Windows、Mac、Linux等平台下的可执行文件,使得你可以将Python应...

知识储备之用py2app将Python代码打包成MacOS可用的APP

自己电脑上有完整的python环境,所以偶尔写个小工具什么的都很easy,直接命令行run一波就OK,但是如果需要再朋友的电脑上运行,帮别人写了一个小工具,他没有运行环境,就很麻烦。不能让人家也从ho...

使用PyInstaller将Python文件打包成Windows系统可执行文件

官网PyInstaller官方网站:http://www.pyinstaller.org/国内镜像库PyInstallerGitee:https://gitee.com/mirrors/pyinst...

松勤技术精选:Python打包exe,换电脑也可直接运行哦!

为什么要打包exe有的时候只需要让别人运行某种功能,传输文件以及代码是需要别人配置好一定的环境才可以操作,而打包成exe文件就可以直接运行文件。pyinstaller打包python中毕竟常用的打包方...

111.Python——基于pipenv打包PaddlePaddle的GUI项目

飞桨PaddlePaddle是百度的深度学习框架,用来做一些项目还是非常不错。但是打包就是一件非常麻烦的过程。在文中有讲过打包问题。29.Python程序打包成可执行文件——常见疑难问题解决办法。本文...

「Python自学笔记」Beeware初体验之Python全平台应用打包

内容更新地址:【Python自学笔记】Beeware初体验,Python如何实现全平台应用打包(exeapkios)_xiaoqiangclub的博客-CSDN博客第一个应用安装环境这里的环境是W...

Python项目pyinstaller打包工具提示词整理出来了,太酷了

Python项目pyinstaller打包工具的提示词整理出来了,下面是完整的提示词请开发一个PythonGUI程序,功能是Python项目打包工具,具有以下特点:1.界面要求:使用PyQt5开发...

Python GUI开发:打包PySide2应用(spyder打包python)

之前的文章我们介绍了怎么使用PySide2来开发一个简单PythonGUI应用。这次我们来将上次完成的代码打包。我们使用pyinstaller。注意,pyinstaller默认会将所有安装的pack...

用Docker打包Python应用的关键要点与实践

引言在微服务架构和云原生时代,Docker已成为应用打包与部署的标准工具。本文将通过一个完整示例,介绍如何用Docker高效打包Python应用,并提炼出关键实践要点。一、Dockerfile基础结构...

精品收藏!Python 程序封装!打包成exe程序!

在Windows操作系统中,我们常用的桌面软件都是带有操作界面的软件,那么Python编写的程序如何才能让用户方便使用呢?因此,程序打包也成为用户的需求,下面详细介绍一下如何进行Python的程序打包...

用python开发的APP程序如何打包成APK安装文件

要将Python开发的APP程序打包成APK安装文件,可以使用第三方工具PyInstaller和Buildozer。下面是一个简单的步骤指南:安装PyInstaller和Buildozer:使用pip...

python打包按部就班(python打包安装文件)

一步一步安装软件包1,pywin32python.exe-mpipinstall--upgradepip更新pippipinstallPyInstaller安装打包工具编写最简单的hel...

爆强!直接把 Python 编写的图形程序打包为安卓 APP

请大家多多关注点赞哦如果想使用Python语言编写图形界面程序,那么有不少的框架可以提供支持,比如Tkinter、QtforPython、WxPython等等。不过这些框架都是只能创建桌面图...

PyOxidizer:将 Python 应用打包成单一可执行文件的神器

三、PyOxidizer基本使用使用PyOxidizer打包应用的基本流程如下:1.创建新项目首先,我们使用pyoxidizerinit命令创建一个新的PyOxidizer项目:py...

取消回复欢迎 发表评论: