Goang | Plugin插件热更
热更新
动态脚本更新 (php)
短链接无状态服务器热更 (http)
长连接有状态,数据跟逻辑分离
- golang Plugin热更 (.so 动态库更新) —-逻辑热更
长连接有状态,在运维层面, 利用容器部署热更(docker, k8s)
- 服务不接受新连接,处理完剩余连接的逻辑,主动关闭。由已经更新过的服务接收新连接处理逻辑。
golang插件更新
下面代码实现的需求:
- 不修改主进程代码,不重新编译,在运行过程中 (包括不修改plugin.so文件名)
- 修改插件代码,重新编译插件,给主进程发送指令,主进程重新加载插件。
plugin文件必须main包
plugin
package main
import (
"fmt"
)
func PluginA() {
fmt.Println("Hello, I am PluginA!")
}
main文件
maing.go
package main
import (
"fmt"
"os"
"os/signal"
"plugin"
"pro2d/src/components/logger"
"syscall"
)
func LoadPlugin() {
p, err := plugin.Open("./plugin.so")
if err != nil {
fmt.Println(err)
return
}
s, err := p.Lookup("PluginA")
if err != nil {
fmt.Println("error lookup PluginA: ", err)
os.Exit(-1)
}
if x, ok := s.(func()); ok {
x()
}
}
func main() {
stopChan := make(chan os.Signal)
signal.Notify(stopChan, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
userChan := make(chan os.Signal)
signal.Notify(userChan, syscall.SIGUSR1, syscall.SIGUSR2)
LoadPlugin()
for {
select {
case <-stopChan:
fmt.Println("stop...")
return
case <-userChan:
fmt.Println("userChan recv...")
LoadPlugin()
}
}
}
Makefile文件
Makefile
IMGTIME := $(shell date "+%G%m%d_%H%M%S")
pname = plugin-$(IMGTIME).so
all:plugin build
./plumain
reall:plugin
ps -ef|grep plumain |grep -v grep | awk '{print $$2}' | xargs -I {} kill -USR1 {}
build:
go build -o ./plumain plumain.go
plugin:
go build --buildmode=plugin -o ./$(pname) ./*.go
rm -rf plugin.so && ln -s $(pname) plugin.so
.PHONY: all build plugin
Makefile文件中使用shell变量需要
$$
,比如上面awk '{print $$2}'
编译 & 运行
$ make
Hello, I am PluginA!
修改插件函数PluginA
内容
golang
package main
import (
"fmt"
)
func PluginA() {
fmt.Println("Hello, I am PluginB!")
}
给进程发送USR1自定义指令, 让程序重新加载plugin.so
$ make reall
ps -ef|grep plumain |grep -v grep | awk '{print $$2}' | xargs -I {} kill -USR1 {}
可以看到 进程输出
Hello, I am PluginB!
注意的点
plugin插件必须在main包下
golang文件会检测plugin.so文件是否已经加载。
- 解决办法1: 可以使用不同的文件名
- 解决办法2: 编译插件时可以指定编译参数
-ldflags -pluginpath="plugin/hot-1"
(不推荐)
怎么做到不修改plugin.so文件名字。
- 解决办法: 每次新插件的生成新的文件名。然后使用软连接连接到固定的 plugin.so 上。可以参考
Makefile
文件的make reall
- 解决办法: 每次新插件的生成新的文件名。然后使用软连接连接到固定的 plugin.so 上。可以参考
$ rm -rf plugin.so && ln -s $(pname) plugin.so
- golang的plugin只支持linux & macosx系统。
--完--
- 原文作者: 留白
- 原文链接: https://zfunnily.github.io/2022/03/reload/
- 更新时间:2024-04-16 01:01:05
- 本文声明:转载请标记原文作者及链接