【Go研究】Go语言脚本化的可行性——yaegi项目体验

0x01 背景------云计算中脚本化困境

作为云基础设施管理中,大量需要跟文件系统、容器等相关的操作,这些操作实现通常用脚本来实现。

现在探讨下,这些脚本为什么一定要用脚本语言来实现,以及目前实现中的常见的问题。

常见的两个场景:安装与升级。

安装过程的特点是,涉及大量的文件拷贝、服务启停、配置文件更新。升级的过程也类似,升级过程还要考虑热升级过程中对业务的影响,相对更加复杂。

另外一个特点是对内的,这两种运维性质的操作是一种通用的机制类活动,所有参与到一个产品中的团队和服务都要考虑,但各种业务服务可能有不同的操作,所以要求这种机制具备足够的扩展性和灵活性。

所以这种特点要求此类活动,有通用机制+扩展插件组成。通用机制有专门的团队提供和维护,扩展性插件由各业务自己负责。

而扩展性的插件可以如下的实现方式:

  1. 直接使用脚本,也是目前大规模使用的。
  2. 使用某种DSL实现。
  3. 使用二进制,即各业务提供自己的二进制,由框架在合适的时机调用。

先分析下第3种的问题。第3种一般来说没什么可挑剔的。但对使用的语言的要求,要求它足够高效率,而且容易移植到其他的Linux环境中。如果放在云环境下,似乎很难找到合适的。大家一开始想到的就是Go语言,但Go编译后的二进制体积过大。升级又通常要求多个版本共存,对存储有很大的压力,直接使用Go语言有点尴尬。

使用脚本呢?目前在用的,但也有一些问题。最常用的脚本语言是Bash Shell,这种语言少量的代码还可以维护,代码量大了之后,就会遇到很问题。

  1. 语法过于灵活,跟常用的Go这种语言相比,上手容易,写出稳健的代码比较难。
  2. 坑很多。即使用了shellcheck工具,也很难发现所有问题。
  3. 处理yaml/json/ini这种配置文件比较麻烦,需要借助jq/yq这种工具。

那么自然想到使用Python语言。但Python也有自己的问题。

  1. pypi上的软件包需要rpm化,才能统一管理,依赖某个库,就要先把库打到整包中才能使用,打包比较繁琐。
  2. rpm包容易产生依赖地狱,可能与OS强相关的一些库冲突。

假如能将Go直接作为一种脚本执行,是不是就可以完美解决其他脚本语言的问题了呢。

一种直接的想法,是将Go直接集成到运行环境中,go run就可以了,但go run有一个编译过程,有时候很慢,这点生产环境下肯定不行。

0x02 Go 脚本化的可能性

从社区中了解到了https://github.com/traefik/yaegi这个项目。基本的使用方法可以从官方文档中看到,不用额外的实验也知道初步看是具备以下能力:

  1. 可以直接解释执行一个只引用了标准库的.go文件。
  2. 也可以作为module引用到一个项目中,动态解释了执行Go语句。

先不说项目本身的稳定性,但距离一个真正可用的脚本化语言还有以下疑问:

  1. 能否快捷的引用其他的第三方库,比如yaml的读写。
  2. 能否建立一个定制化的公共库,如日志、事务等。

它是通过如下方式引用的引用标准库:

  1. 将所有标准库的代码中导出的函数整理在了stdlib目录下。

  2. 然后将通过Symbols map保存这些导出函数、类型的反射对象。

    func init() {
    Symbols["runtime/runtime"] = map[string]reflect.Value{
    // function, constant and variable definitions
    "BlockProfile": reflect.ValueOf(runtime.BlockProfile),
    ...
    }
    }

不难猜出,它是通过这样的方式实现脚本中的动态调用标准库函数。

先来实验下yaml读写。demo示例见https://github.com/go-yaml/yaml/tree/v3,由于提前看了下yaegi的实验,看起来它是支持加载其他库的,只要它能在GOPATH下找到这些源码。

将readme中的demo保存下,直接使用yaegi运行。

run: demo.go:7:2: import "gopkg.in/yaml.v3" error: package location /mnt/data/code/lean/go not in GOPATH

直接报了错。

按照要求的路径,将yaml.v3 git clone到指定的路径 $GOPATH/src/gopkg.in/yaml.v3下,再次运行,成功了,跟直接使用go运行它没区别。

$ yaegi run demo.go
--- t:
{Easy {2 [3 4]}}

...

同时也尝试了将go可执行文件重命名,unset掉GOROOT,也能正常地运行这个demo.go文件,说明真的可以完全无go工具链执行.go文件了。

0x03 初步的分析结论

yaegi的能力非常强大,可以满足基本的脚本化要求。而且可以引入第3方库,当然前提是这些三方库没有过于复杂的依赖关系。有了这样基本的能力,其他的规范化的日志、文件事务这些都不是问题。

当然考虑实际工程化的需求,yaegi还有一些可优化和不确定的地方:

  1. 支持将那些三方库预编译到yaegi中。yaegi本身就具备的能力,稍微扩展下就行了。
  2. 能支持指定多个源码文件,执行其中的main函数。这个不支持问题也不大,强制使用方把其他依赖的放到GOPATH下就行了。
  3. 不确定复杂一些的脚本在运行的时候解析过程是否耗时较长。

yaegi本身的稳定性应该不错,大概看了下,基本上利用Go本身的ast解析能力,主要部分是实现了一个interpeter,具体的分析还结合实现和项目的issue进行分析。

相关推荐
Linux520小飞鱼22 分钟前
F#语言的网络编程
开发语言·后端·golang
weixin_3992642927 分钟前
QT c++ 样式 设置 标签(QLabel)的渐变色美化
开发语言·c++·qt
吾当每日三饮五升3 小时前
C++单例模式跨DLL调用问题梳理
开发语言·c++·单例模式
猫武士水星4 小时前
C++ scanf
开发语言·c++
BinaryBardC4 小时前
Bash语言的数据类型
开发语言·后端·golang
Lang_xi_4 小时前
Bash Shell的操作环境
linux·开发语言·bash
Pandaconda4 小时前
【Golang 面试题】每日 3 题(二十一)
开发语言·笔记·后端·面试·职场和发展·golang·go
捕鲸叉5 小时前
QT自定义工具条渐变背景颜色一例
开发语言·前端·c++·qt
想要入门的程序猿5 小时前
Qt菜单栏、工具栏、状态栏(右键)
开发语言·数据库·qt
_院长大人_5 小时前
使用 Spring Boot 实现钉钉消息发送消息
spring boot·后端·钉钉