golang插件化方案

简介:

背景

业务线的活动,每一次新活动都做独立项目开发,有大量重复代码,并且浪费数据服务的连接资源;排序服务也许要经常添加业务代码,目前是停服务发布……这些场景为了开发维护效率、稳定性、安全性和性能都使用了Go语言。Go是静态编译语言,在具体的动态场景该如何实现应用级别的持续交付呢?

基于k8s,nginx网关,队列回溯消费等工具的实现也可以实现不同程度的持续交付,但是持续交付的要求越高,搭建平台和维护的成本也越高。

从应用开发本身出发,可以考虑插件化

插件使用场景特点

可以热更新式扩展应用程序的功能列表
应对多变的业务需求,方便功能上下线

对于任意的go应用,能进行增量架构、代码分发以及代码上下线

插件设计标准

  • 性能:调用插件要尽可能的快;对于任务插件,使用单独的工作空间(协程、线程、进程的池子化处理),大的、慢的、长期运行的插件,要少调用

  • 稳定性:插件依赖的发布平台要少发布,交互API的设计要做好抽象,上下文的环境变量非必须不添加,减少升级需求,甚至能支持多个实例互备热升级

  • 可靠性:如果有失效、崩溃的可能,必须有快速、简单、完整的恢复机制;业务插件的执行不能影响依赖的发布平台的守护进程或者线程的稳定

  • 安全性:应该通过代码签名之类的手段防篡改

  • 扩展性:支持插件热更新和上下线,下线需要健康检查,公共库插件至少能热加载

  • 复用性:业务插件不要太多一次性的上下线

  • 易用性:提供使用简单、功能正交的API,业务插件能够获取依赖的发布平台的上下文和调用公共库

2、GO的插件方式

动态链接库plugin,官方文档

语言本身支持,插件和主程序原生语法交互

  • 进程隔离:无,单进程

  • 主程序调用插件:一切预协定object(包括function、channel)

  • 插件感知主程序上下文:主程序预定义类型参数object(包括function、channel)

  • stream支持:单向,基于channel

  • 插件发现:主程序循环扫描插件目录并维护状态;通过第三方文件diff工具维护,例如git

  • 上线:能

  • 下线:不能

  • 更新:不能

  • 通信:进程内

  • 序列化:不需要

  • 性能:高

Go plugin判断两个插件是否相同是通过比较pluginpath实现的,如果没有指定pluginpath,则由内部的算法生成, 生成的格式为plugin/unnamed-“ + root.Package.Internal.BuildID 。这种情况下,如果两个插件的文件名不同,引用包不同,或者引用的cgo不同,则会生成不同的插件,同时加载不会有问题。但是如果两个插件的文件名相同,相关的引用包也相同,则可能生成相同的插件,即使插件内包含的方法和变量不同,实现也不同。判断插件相同,热加载不会成功,也就意味着老插件不支持覆盖更新。

最好在编译的指定pluginpath,同时方便版本跟踪。目前生产环境建议一些公共库无服务依赖的函数,例如算法库之类的。

1go build -ldflags "-pluginpath=plugin/hot-$(date +%s)" -buildmode=plugin -o so/Eng.so eng/greeter.go通信+序列化
  • 进程隔离:有,多进程,provider+comsumer

  • 主程序调用插件:provider模式调用插件进程中预协定method;consumer模式消费插件进程中的预协定参数object(包括function、除了channel)

  • 插件感知主程序上下文:provider模式消费主程序的预定义参数object(包括function、除了channel);consumer模式调用主程序中预定义method

  • stream支持:不支持

  • 插件发现:主程序循环扫描插件目录并维护状态;通过第三方文件diff工具维护,例如git

  • 上线:能

  • 下线:能

  • 更新:能

  • 通信:支持stdin/stdout、pipe、unix socket、tcp、http、jsonrpc

  • 序列化:gob,protobuf, json, xml

  • 性能:中/偏高

基于Go的net/rpc库,无法支持主程序和插件之间的streaming数据交互,有golang的官方包[issue1]和[issue2]直接建议。另外,每一个插件都要开一个进程,因此要注意通信序列化的性能消耗和进程管理,默认使用stdin/stdout建立连接,如下图,一个plugin和主程序之间有两条单向连接。

可以上成产环境,要做好资源管理。

45cdc4e370dcf1e5770d1b4827ef08855849a1b1

hashicorp/go-plugin,github仓库

  • 进程隔离:有,多进程,server+client

  • 主程序调用插件:一切协议预协定object

  • 插件感知主程序上下文:一切协议预协定object

  • stream支持:单向和双向,基于http/2

  • 插件发现:主程序循环扫描插件目录并维护状态;通过第三方文件diff工具维护,例如git

  • 上线:能

  • 下线:能

  • 更新:能

  • 通信:支持grpc

  • 序列化:protobuf

  • 性能:中/偏高

基于Google的grpc库,按照微服务的流程定义proto文件,能通信就能互相调用。知名团队出品。可以上成产环境,要做好资源管理。

67631f6e6507d2aefcfd28e86be9e6b5fa3d8942

go-mangos/mangos,github仓库

  • 进程隔离:有,多进程,provider+comsumer

  • 主程序调用插件:一切预协定object

  • 插件感知主程序上下文:一切预协定object

  • stream支持:单向,基于mq

  • 插件发现:主程序循环扫描插件目录并维护状态;通过第三方文件diff工具维护,例如git

  • 上线:能

  • 下线:能

  • 更新:能

  • 通信:支持mq

  • 序列化:未知

  • 性能:中/偏高

基于消息队列协议通信,nanomsg和ZeroMQ一类的规范包含一组预定义的通信拓扑(称为“可扩展性协议”),涵盖许多不同的场景:Pair,PubSub,Bus,Survey,Pipeline和ReqRep。Mangos是该协议的golang实现,能够灵活方便支地持两个插件交流。

可以上成产环境,要走大量的基础建设开发。

嵌入式脚本语言

一般都是进程内内嵌第三方语言的解释器,需要考虑解释器的工作线程资源的重复利用。

3fbfc88b36c784a3a31571971c75bf75a5fff01a

  • 进程隔离:无,单进程,解释器有goroutine开销

  • 主程序调用插件:一切语言协定object

  • 插件感知主程序上下文:一切语言协定object

  • stream支持:看语言是否支持channel互通

  • 插件发现:主程序循环扫描插件目录并维护状态;通过第三方文件diff工具维护,例如git

  • 上线:能

  • 下线:能

  • 更新:能

  • 通信:无

  • 序列化:无

  • 性能:中

go-like脚本语言,agora和七牛qlang

agora和qlang都是go语法的动态脚本语言,都好几年没维护了,建议不要用在生产环境,其中Qlang还有用户提[issue]觉得不稳定。

其他脚本语言,js-otto、go-lua5.1、go-lua5.2

otta支持目前受欢迎的js语法,star比较多,协定了大部分go原生支持的类型,不包括channel和goroutine,没有提供解释器的工作空间池子化管理,需要开发者使用goroutine和解释器的interrupt接口自行实现,但是从issue和TODO来看,也不适合生产环境。

gopher-lua支持lua5.1语法,和go交互的object类型比较完备,协定了大部分go原生支持的类型,包括channel和goroutine,有提供解释器的工作空间池子化管理,可以上生产环境。

go-lua支持lua5.2语法,目前不建议上生产环境。

3、思考

  1. 主程序需要怎样设计才能给业务插件预定义完美的上下文呢?例如线程池、redis连接池、mysql连接池、rocketmq、外部服务依赖等等

  2. 公共库插件和业务插件是否适合不同的插件方式?公共库插件方便为业务插件增加提供上下文吗?


原文发布时间为:2018-08-13
本文来自云栖社区合作伙伴“ Golang语言社区”,了解相关信息可以关注“ Golang语言社区”。
相关文章
|
Shell 测试技术 Go
Golang基于Gitlab CI/CD部署方案
持续集成 (Continuous integration)是一种软件开发实践,即团队开发成员经常集成它们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
2949 0
|
16小时前
|
数据采集 人工智能 搜索推荐
快速入门:利用Go语言下载Amazon商品信息的步骤详解
本文探讨了使用Go语言和代理IP技术构建高效Amazon商品信息爬虫的方法。Go语言因其简洁语法、快速编译、并发支持和丰富标准库成为理想的爬虫开发语言。文章介绍了电商网站的发展趋势,如个性化推荐、移动端优化和跨境电商。步骤包括设置代理IP、编写爬虫代码和实现多线程采集。提供的Go代码示例展示了如何配置代理、发送请求及使用goroutine进行多线程采集。注意需根据实际情况调整代理服务和商品URL。
快速入门:利用Go语言下载Amazon商品信息的步骤详解
|
2天前
|
存储 编译器 Go
Go语言学习12-数据的使用
【5月更文挑战第5天】本篇 Huazie 向大家介绍 Go 语言数据的使用,包含赋值语句、常量与变量、可比性与有序性
37 6
Go语言学习12-数据的使用
|
3天前
|
Java Go
一文带你速通go语言指针
Go语言指针入门指南:简述指针用于提升效率,通过地址操作变量。文章作者sharkChili是Java/CSDN专家,维护Java Guide项目。文中介绍指针声明、取值,展示如何通过指针修改变量值及在函数中的应用。通过实例解析如何使用指针优化函数,以实现对原变量的直接修改。作者还邀请读者加入交流群深入探讨,并鼓励关注其公众号“写代码的SharkChili”。
9 0
|
3天前
|
存储 缓存 Java
来聊聊go语言的hashMap
本文介绍了Go语言中的`map`与Java的不同设计思想。作者`sharkChili`是一名Java和Go开发者,同时也是CSDN博客专家及JavaGuide项目的维护者。文章探讨了Go语言`map`的数据结构,包括`count`、`buckets指针`和`bmap`,解释了键值对的存储方式,如何利用内存对齐优化空间使用,并展示了`map`的初始化、插入键值对以及查找数据的源码过程。此外,作者还分享了如何通过汇编查看`map`操作,并鼓励读者深入研究Go的哈希冲突解决和源码。最后,作者提供了一个交流群,供读者讨论相关话题。
14 0
|
4天前
|
Java Go
Go语言学习11-数据初始化
【5月更文挑战第3天】本篇带大家通过内建函数 new 和 make 了解Go语言的数据初始化过程
17 1
Go语言学习11-数据初始化
|
4天前
|
自然语言处理 安全 Java
速通Go语言编译过程
Go语言编译过程详解:从词法分析(生成token)到句法分析(构建语法树),再到语义分析(类型检查、推断、匹配及函数内联)、生成中间码(SSA)和汇编码。最后,通过链接生成可执行文件。作者sharkchili,CSDN Java博客专家,分享技术细节,邀请读者加入交流群。
22 2
|
5天前
|
Java Linux Go
一文带你速通Go语言基础语法
本文是关于Go语言的入门介绍,作者因其简洁高效的特性对Go语言情有独钟。文章首先概述了Go语言的优势,包括快速上手、并发编程简单、设计简洁且功能强大,以及丰富的标准库。接着,文章通过示例展示了如何编写和运行Go代码,包括声明包、导入包和输出语句。此外,还介绍了Go的语法基础,如变量类型(数字、字符串、布尔和复数)、变量赋值、类型转换和默认值。文章还涉及条件分支(if和switch)和循环结构(for)。最后,简要提到了Go函数的定义和多返回值特性,以及一些常见的Go命令。作者计划在后续文章中进一步探讨Go语言的其他方面。
10 0
|
6天前
|
JavaScript 前端开发 Go
Go语言的入门学习
【4月更文挑战第7天】Go语言,通常称为Golang,是由Google设计并开发的一种编程语言,它于2009年公开发布。Go的设计团队主要包括Robert Griesemer、Rob Pike和Ken Thompson,这三位都是计算机科学和软件工程领域的杰出人物。
14 1