解读golang plugin热更新尝试
作者:呵大官人 发布时间:2024-05-22 10:09:28
当我们在使用php开发的时候,基本不需要关心热更新这件事的,因为PHP本身已经帮我处理好了,只需要提交代码,PHP重新解释一遍即可。而go则是静态语言,编译后得到的是直接被机器执行的,所有代码已经翻译成相对应的机器指令并且在运行时已经加载到内存,不能动态更新。那么如果想热更新就成了件麻烦的事,但是作为后端开发人员,很渴望支持这种功能,毕竟在线上能新增功能、修复bug客户端完全无感知是多么完美的事。
本文暂不讨论http这种无状态服务更新,网上能搜索到很多文章关于如何利用fd继承实现优雅重启。这里主要讨论使用golang 1.8新增的plugin来实现业务的更新,并且业务是类似游戏的有状态服务。官方文档中对plugin的描述比较简单,他可以动态的加载so和执行导出的方法,并且仅仅提供了两个方法:打开模块和提取符号,甚至连关闭都没有(-_-)。
一个程序包含两部分:数据和算法,那么既然是有状态服务,数据部分肯定不能动,那么热更就只能动算法部分了。这时我们需要一个容器,将这两部分隔离开,一方面是存储数据,另一方面要动态加载so。隔离了数据和算法,只要数据存在,我们就可以随意更新算法了。在开始编码之前,要先解决几个问题:
1、同一个so文件只会被打开一次
2、每个so有一个pluginpath用来标识是否重复,如果两个so文件不一样,但pluginpath一样还是会报错
3、不同so文件定义的结构体不能使用类型断言进行转换
对于上面的问题,有如下解决方案:
1、每次生成的so带一个版本号比如game.1001.so
2、编译的时候新增--ldflags="-pluginpath=xxx"参数
3、使用unsafe进行转换(下面还会有注意事项)
代码地址:https://github.com/scgywx/myplugin
1、编译engine,这就是我们上面说的容器,他负责数据存储和so的加载与执行。
sh build.sh
2、编译第1个版本so(注意后面有个参数)
sh build_so.sh 1
3、将src/logic/main.go里面的modelVersion和modelName分别改成1002和game2(这里主要是测试两个版本的内容区别)
4、编译第2个版本so
sh build_so.sh 2
5、运行容器
./engine
6、浏览器输入127.0.0.1:12345/hello,会看到如下显示(这是使用的第一个版本so)
hello test, this is golang plugin test!, version=1001, name=game1, oldversion=0, oldName=
7、浏览器输入127.0.0.1:12345/load?name=plugin2.so(这里输出done,就说明加载so成功了)
8、再次输入127.0.0.1:12345/hello,会看到如下显示。
hello test, this is golang plugin test!, version=1002, name=game2, oldversion=1001, oldName=game1
到这里,我们的热更新效果已经达成,但是还是有一些限制
1、每个so不能单独保存数据,因为当另一个so加载后,前面so的数据是没办法访问到,并且由于so不能被关闭,可能会出现多个so引用同一个变量,gc没办法释放,所以需要透过容器来共享数据,那么我们就不能在模块内使用全局变量来保存数据。
2、go里面两个类型即使一样,也不能直接转换,所以两个so内定义的结构体也不能直接转换,要使用unsafe.Pointer来进行强转(见src/logic/main.go),既然是强转,那么两个版本的so使用的结构体定义就不能有区别,否则转换后数据可能会出现异常,也就是说热更新不能修改结构体。
本文只是技术尝试,没有线上验证,还有多少坑还不知道,热更新不是必须,如若支持,便是好事。。
来源:https://my.oschina.net/scgywx/blog/1796358


猜你喜欢
- 需求是小程序做头部做导航分类的效果顶部用 scroll-view 组件横向滚动,类似tab选项卡的效果,内容用类似模板方式引用,可重复利用&
- 学习自然语言的最好方法就是溶入相应的语言环境在交流中学习,学习一种编程语言的最好方法就是看例程。为了帮助大家建立wml应用的第一印象,所以请
- 一:脚本需求利用Python3查询网站权重并自动存储在本地数据库(Mysql数据库)中,同时导出一份网站权重查询结果的EXCEL表格数据库类
- 这里以安装简单的nonebot库为例子欧克,简明扼要,拿走点赞哟:大家想要的豆瓣源如下:因为有几个,但在这里还是建议使用国内的豆瓣源,本人感
- 如何调用多个不同的ip接口灵感来源:项目的登录登出权限是调A的ip下面的接口,其他的功能调的接口是B的ip下面的接口思路:其实就是多写几个r
- 本文实例为大家分享了mysql 5.6.17 安装教程简单版,供大家参考,具体内容如下1.linux版mysql下载(建议不要下5.7,安装
- 摘要:本篇文章介绍了ORACLE数据库的新特性—分区管理,并用例子说明使用方法。 关键词:ORACLE,分区 一、 分区概述: 为了简化数据
- 1、Mysql errono 1005 : 主外键不是完全一致 , 请检查如下几点: a、字段是否存在 b、类型是否一致(注意unsigne
- 本文实例为大家分享了python实现桌面托盘气泡提示的具体代码,供大家参考,具体内容如下# -*- encoding:utf-8 -*- #
- 我们知道Excel有一个match函数,可以做数据匹配。比如要根据人名获取成绩而参考表sheet1的内容如下:要根据sheet1匹配每人的成
- python3的多行输入问题因为在OJ上做编程,要求标准输入,特别是多行输入。特意查了资料,自己验证了可行性。if __name__ ==
- 一、使用dotnet add package 命令行实现首先可以去这个网站:https://www.nuget.org/ 查找想要添加的引用
- 从 Google 的一个细节说起:整个虚线框都是“Next”的可点击区域。看似不经意,却直接提升了细节的可用性。其它页码也巧妙地和上面的字母
- <?php function getIPLoc_sina($queryIP){ $url =
- 摘要: 三次握手,四次挥手意思是tcp建立连接时需要三次交互来完成,A发起连接A --- SYN --> BA
- 废话不多说了,直接把我写的timeit函数分享给大家,具体内容如下:/** * Compute the delay to execute a
- 前言上网浏览网页的时候,看见好的内容免不了要使用复制粘贴,但是我们看到的内容、心里想要的内容和实际粘贴后的内容往往不一致。数据的获取始于复制
- 前言本文代码基于 python3.6 和 pygame1.9.4。俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一
- 引用body标签有两做法: 第一种:使用DOM Core 即引用某个给定文档的第一个(也是仅有的一个)body标签 document.get
- 本文实例讲述了Python3.5 Json与pickle实现数据序列化与反序列化操作。分享给大家供大家参考,具体如下:1、Json:不同语言