Tars微服务框架 在从腾讯开源出去的过程中,运营体系被剥离了两个很重要的能力,一个是容器管理,一个是监控告警。
为了让开源的Tars重新拥有这两项能力,而能力的支持尽量对Tars本身的侵入性小,我前段时间分别做了一个tars和k8s生命周期融合的插件、一个tars grafana插件,来分别支持容器管理和监控告警。后续看看能不能整理后开源出来吧。
此文主要讲讲grafana告警插件,因为开发的过程中还是踩了不少坑,先回忆一下,记录一些要点,供未来的自己或网友参考。
技术选型背景
首先必须得承认,grafana是一个非常优秀的看板&监控开源项目。最开始我本来是想用Prometheus来做这个告警的,后来发现Prometheus自带看板比较差,官方也采用了grafana这个项目,深入了解之后发现grafana更加契合tars这种,已经有了上报数据,没有告警能力的情况。
理论上来说,数据不需要重复做上报/收集了,这样Prometheus的意义就失去了一大半;而grafana则更好是读取数据源,配置告警项,完美。
然而后来的开发过程中发现,项目本身的优秀,并不代表对开发者友好。它的文档给开发工作带来了太多的阻碍了。最终设计:
无法配置告警的场景
文档中并没有描述:
- 带模板变量的Panel无法配置告警
- 应用了Transform的Panel无法配置告警
轻飘飘的两个特性,却会在开发过程中造成血案,因为文档中压根没有提及(至少截止v7.3版本未提及)这两点特性,只有在付出了大量工作量后,才能发现这俩特性,导致之前的方案被推翻
说干就干,一开始基于tars的mysql表写了一堆sql,以及针对时间序列数据格式的转换。Dashboard做完之后,才发现依赖模板变量的mysql数据源方式行不通。
转换方向,后来采用自己开发后端数据源插件的方案,第一版接口返回了比较通用的格式,在Panel中使用Transform来转换数据格式,做完后才发现应用了Transform的Panel无法配置告警。
插件后端读取前端的配置数据
插件配置有两块,一块是后端数据源配置
另一块是Panel查询配置
这两个配置在前端设置后,golang后台如何获取配置的值呢?其中Panel查询配置,在脚手架工程代码中能比较容易的看到。而后端数据源配置,试了下面几种渠道都没找到,印象深刻:
- 找遍google、baidu
- 翻遍官网文档
- 加了四五个grafana技术交流群
- 咨询公司内曾经做过插件开发的同事
均没有得到正确答案。最终解决的方法是,看后端插件SDK的代码 + 加log定位,找到了如何读取这个配置。 入口并不深,但是对于首次接触的开发者来说,真的不好找。
// 返回 datasource.ServeOpts.结构对象
func newDatasource() datasource.ServeOpts {
// 创建插件的manager对象(instance manager)
// 当实例第一次被创建或者数据源配置更改时,传入 `NewInstanceManger` 的函数 newDataSourceInstance 被调用
im := datasource.NewInstanceManager(newDataSourceInstance)
//创建 data source结构对象
ds := &TarsDatasource{
im: im,
}
//创建并返回sdk的datasource.ServeOpts结构对象,传入datasource对象作为查询和监控检查的handler
return datasource.ServeOpts{
QueryDataHandler: ds,
CheckHealthHandler: ds,
}
}
func (td *TarsDatasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
}
func (td *TarsDatasource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
}
func newDataSourceInstance(setting backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
}
贴一下关键代码。
真正的方式是在QueryData或者CheckHealth函数里边,通过req.PluginContext.DataSourceInstanceSettings.JSONData
和req.PluginContext.DataSourceInstanceSettings. DecryptedSecureJSONData
来获取。入口不深,但是藏在PluginContext里边,文档又没有描述,天知道呢?
可能有人会奇怪,其实生命周期函数已经传递了这个DataSourceInstanceSettings
参数。为何第一时间没发现呢? 这又涉及到了下一个环环相扣的坑。
插件后端的生命周期不生效
首先,官网本身并没有对插件生命周期很细致的描述。下面是脚手架工程中的函数注释:
// 这个函数描述的是第一次实例化或者配置变化时被调用,但是貌似并不会真的被调用
func newDataSourceInstance(setting backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
PluginConfigObj.SetConfigBySettings(&setting)
TarCheckIns.StartCheckTarsDashboard()
return &instanceSettings{
httpClient: &http.Client{},
}, nil
}
这个函数其实 并不会 生效,这也是为啥第一时间死活找不到如何获取数据源配置。
用协程启动Webhook监听失败
尝试在插件加载起来的时候,同时开启供发送自定义方式告警的Webhook。然而很蛋疼的发现,main函数入口、datasource.Serve(newDatasource())
入口逻辑中,用协程启动端口监听都不可行,插件进程拉起后会立即被杀掉。
这种奇葩的现象,文档中更不可能说明原因了。最终给放到了CheckHealth
中去做首次拉起,以及一个定时任务中去做check拉起。无奈。
本文链接:https://www.zoucz.com/blog/2020/12/10/2c882220-3a3c-11eb-90b5-eb40e9720ed0/