商业版的性能监控平台确实强大,但是对于很多初创公司来说,一般不会选择昂贵的商业监控平台,更多的是选用开源的监控系统,比如Zabbix。但是无论多么强大的开源监控平台,基本都不能满足所有的监控需求,比如没有APM监控,不方便监控mysql、Postgresql等数据库,所以集成化开发是一种可行的选项,只要做好前期技术选型,选好要被集成的监控工具,我们就可以迈出第一步。
由于一直对Telegraf + Influxdb + Grafana有比较多的实践经验,并且这种监控组合已经被很多人大量的采用,原因是轻量化、部署快捷、自由配置监控面板、丰富的图形化展现,最最重要一点是Telegraf能配置出多达几十种监控模型(并且Telegraf的监控插件还在不断扩展中),提供一下官网的Telegraf监控配置说明:https://github.com/influxdata/telegraf/tree/release-1.9/plugins/inputs,细看就能发现其对大量监控指标的支持(包括支持docker的监控)。除了Telegraf,结合Jmxtrans还可以对所有Java服务进行全面的监控(参考我的另一篇文章https://blog.csdn.net/smooth00/article/details/90399528),如果需要有APM监控,那选用Skywalking是最明智的,原因是它具有良好的扩展性,并且还在不断演绎和发展中,只要解决好数据存储的问题,就可以被我们所用(关于这块可以参考我的文章https://blog.csdn.net/smooth00/article/details/96479544)。
以下是我根据这些设想编制的架构图,整体来说已经按照这个图在一步步的实现:
由于是集成的,所以平台的整体性能将取决于Influxdb、Grafana、Skywalking本身的性能,但开源技术的好处就是可以无限扩展,Influxdb和Skywalking都支持高可用的集群化部署,想做多大的生意就看你愿意装多大的门店了。另外监控平台的数据传输性能,也会受制于推拉模式原理的限制,如下图所示:
这两种模式的的特点如下:
推模式(Push):是指由监控客户端主动将监控数据推送给监控服务器。Push模式的实时性和数据一致性较好,但是效率较低。Push操作的频率一般由设定好的时间间隔触发,一旦时间间隔设置不当,可能会造成丢失监控数据的现象,或者是推送的数据过多,前者影响了监控系统的准确性,而后者则增加了通信开销。
拉模式(Pull):是指由监控服务器端采用轮询的方式通知客户端,将被请求的监控数据项发送给服务器端。Pull模式的针对性强,能够满足个性化需求,并可以减少通信开销,但是一致性和实时性一般。如果轮询的次数频繁,以及需要轮询的客户端较多,则服务器端的压力就会变大。
毫无疑问的是我们所采用的telegraf + influxdb;jmxtrans + influxdb;skywalking 三个监控都是基于推模式(Push),好处就是实时性和数据一致性好,适合于在压测时的监控(这也是为什么我采用它们来集成到监控平台,因为本人就是个性能测试工程师,关注的当然是监控的准确性和实效性)。但是这样很可能就不太适用于大批量服务器部署情况下的运维监控了,因为推模式需要在大量客户端中配置数据发送的时间间隔,这本身会很麻烦,时间设小了通信开销太大,数据库的写入压力过大,时间设大了可能又不满足监控的个性需求;相对来说拉模式适合于运维监控,因为运维监控都是7*24小时监控,时间粒度不大基本上不用频繁轮询,通信开销可控,数据库的写入压力较小,监控平台的稳定性自然就高。所以以上的架构设计,对于运维性监控可能不够满足,在实践中还需要加入通过远程来配置各个监控代理的Push时间间隔的功能,这就加大了操作的麻烦度。从开源集成来说,如果要采用拉模式(Pull),通过Prometheus + exporter的模式(与传统的数据采集组件不同的是,exporter并不向中央服务器发送数据,而是等待中央服务器主动前来抓取)可以实现。不过从安装部署来看,面对大量不同类exporter组件的部署和配置,不少人还是会心生恐惧,所以集成telegraf + influxdb的方式虽然不是最好的选择,但就眼下来说,却是最经济的选择(不过网上有人愿意基于Prometheus开发自已的exporter,能驾驭就是好,开发自己的监控平台无需排斥任何一种开源技术)。
另外以上架构还有个有问题是不好解决的,那就是如何管理监控的报警。作为监控平台的核心功能之一,报警和预警无疑是衡量监控平台好坏的点。Grafana本身可以配置报警功能,但这种报警是被动式的(就是dashboards中查询到的值超过了阀值才触发报警),谈不上好,但至少能用,可是专业性有点强,一般人还配不明白;另外就是Skywalking也有告警模块,功能不直观,需要在application.yml配置文件中配(配置参考官网说明),支持通过webhooks来发送notify、go-wechat、mail。看到这,我们也明白了,报警功能差异化大根本集成不到一块,对于易用性和扩展性上来说,这块暂时无解,除非能介入到数据层,独立开发出一套分析报警的功能,那这个工作量就大大超过了原来的预计,失去了集成平台的意义了。
说了这么多,也展示一下集成后的界面效果:
1、监控模型管理
通过上传监控模板 (监控代理的配置文件+使用说明),自动集成到telegraf、jmxtrans、skywalking agent的包中生成zip压缩文件,以提供下载,由于下载的包中已经带有配好的配置文件和启动脚本及初始化配置文件的脚本。所以在远程启动监控代理时,就会自动配置好,并开启监控进程(好处当然就是增强了易用性,因为一般人是配不明白这些配置文件的)。
创建监控包来说最大的工作量还在于使用大量批处理脚本,就以Windws下创建Telegraf服务来说,需要调用SetACL修改注册表权限(以便WMI能远程调用服务),需要以最高权限注册服务,所以脚本就很复杂,如下所示:
::::::::::::::::::::::::::::::::::::::::::::
:: Elevate.cmd - Version 4
:: Automatically check & get admin rights
::::::::::::::::::::::::::::::::::::::::::::
@echo off
CLS
ECHO.
ECHO =============================
ECHO Running Admin shell
ECHO =============================
:init
setlocal DisableDelayedExpansion
set cmdInvoke=1
set winSysFolder=System32
set "batchPath=%~0"
for %%k in (%0) do set batchName=%%~nk
set "vbsGetPrivileges=%temp%\OEgetPriv_%batchName%.vbs"
setlocal EnableDelayedExpansion
:checkPrivileges
NET FILE 1>NUL 2>NUL
if '%errorlevel%' == '0' ( goto gotPrivileges ) else ( goto getPrivileges )
:getPrivileges
if '%1'=='ELEV' (echo ELEV & shift /1 & goto gotPrivileges)
ECHO.
ECHO **************************************
ECHO Invoking UAC for Privilege Escalation
ECHO **************************************
ECHO Set UAC = CreateObject^("Shell.Application"^) > "%vbsGetPrivileges%"
ECHO args = "ELEV " >> "%vbsGetPrivileges%"
ECHO For Each strArg in WScript.Arguments >> "%vbsGetPrivileges%"
ECHO args = args ^& strArg ^& " " >> "%vbsGetPrivileges%"
ECHO Next >> "%vbsGetPrivileges%"
if '%cmdInvoke%'=='1' goto InvokeCmd
ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "%vbsGetPrivileges%"
goto ExecElevation
:InvokeCmd
ECHO args = "/c """ + "!batchPath!" + """ " + args >> "%vbsGetPrivileges%"
ECHO UAC.ShellExecute "%SystemRoot%\%winSysFolder%\cmd.exe", args, "", "runas", 1 >> "%vbsGetPrivileges%"
:ExecElevation
"%SystemRoot%\%winSysFolder%\WScript.exe" "%vbsGetPrivileges%" %*
exit /B
:gotPrivileges
setlocal & cd /d %~dp0
if '%1'=='ELEV' (del "%vbsGetPrivileges%" 1>nul 2>nul & shift /1)
::::::::::::::::::::::::::::
::START
::::::::::::::::::::::::::::
REM 把需要运行的脚本放到下面
::判断远程注册服务是否开启
for /f "skip=3 tokens=4" %%i in ('sc query RemoteRegistry') do set "zt=%%i" &goto :next
:next
if /i "%zt%"=="STOPPED" (
sc config RemoteRegistry start= auto
net start RemoteRegistry
regsvr32 %SystemRoot%\system32\wbem\wbemdisp.dll
echo "start RemoteRegistry Server"
)
::获取WMI的administrator远程控制权限
set rootkey="HKEY_CLASSES_ROOT\CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}"
if /i "%PROCESSOR_ARCHITECTURE%"=="AMD64" (
"%~dp0SetACL\64bit\SetACL.exe" -on %rootkey% -ot reg -actn setowner -ownr "n:administrator" -rec yes -silent
if errorlevel 0 echo OK: Set Owner
"%~dp0SetACL\64bit\SetACL.exe" -on %rootkey% -ot reg -actn ace -ace "n:administrator;p:full;m:grant;i:so,sc" -op DACL:p_c -rec yes -silent
if errorlevel 0 echo OK: Set Privilege
) else (
"%~dp0SetACL\32bit\SetACL.exe" -on %rootkey% -ot reg -actn setowner -ownr "n:administrator" -rec yes -silent
if errorlevel 0 echo OK: Set Owner
"%~dp0SetACL\32bit\SetACL.exe" -on %rootkey% -ot reg -actn ace -ace "n:administrator;p:full;m:grant;i:so,sc" -op DACL:p_c -rec yes -silent
if errorlevel 0 echo OK: Set Privilege
)
set rootkey=
::创建telegraf监控服务
sc create telegraf binPath= "\"%~dp0telegraf.exe\" -config \"%~dp0telegraf.conf\""
pause
2、监控节点管理
首先就是新增或修改节点,把需要监控的节点信息配置好,而这些配置信息将会作为同步到监控代理配置文件的依据:
然后在节点管理界面,点击启用或配置,相关的IP、端口、节点名称等信息就会自动通过远程执行脚本的方式,替换到监控代理的配置文件中,并完成代理的启动。
启动完后,通过监控【视图】(配置了动态router实现链接)可以看到监控的结果(Grafana面板示例):
以下为Skywalking监控面板示例(Skywalking UI做了Router和数据过滤改造,只显示当前节点的监控数据):
再放一张炫酷一点的,这就是Skywalking的魅力:
3、监控数据管理
这块还没开发,思路就是通过Java连接influxdb、ES、Mysql,对监控的数据进行清理,比如监控节点删除后,相关的关联数据可以做个删除操作,或者修改influxdb的数据保留策略(例如保留最近2天的数据)。
4、Vue Router配置
由于涉及链接到grafana(不同类型的监控配置了不同的面板)和Skywalking UI,所以需要配置Router。主要有两种方式,一种是菜单的形式调用。比如菜单的URL配置为http://${skywalking}/和http://${grafana}/d/PGoagxIWk/postgresql-server?orgId=1,在${skywalking}和${grafana}作为参数变量进行替换,节选代码如下:
// url以http[s]://开头, 通过iframe展示
if (isURL(menuList[i].url)) {
route['path'] = `i-${menuList[i].menuId}`
route['name'] = `i-${menuList[i].menuId}`
// route['meta']['iframeUrl'] = menuList[i].url
if (menuList[i].url.match(/\$\{grafana\}/)) {
route['meta']['iframeUrl'] = menuList[i].url.replace(/\$\{grafana\}/, grafanaUrl)
} else if (menuList[i].url.match(/\$\{skywalking\}/)) {
route['meta']['iframeUrl'] = menuList[i].url.replace(/\$\{skywalking\}/, skywalkingUrl)
} else {
route['meta']['iframeUrl'] = menuList[i].url
}
} else {
try {
route['component'] = _import(`modules/${menuList[i].url}`) || null
} catch (e) {}
}
routes.push(route)
另一种是以iframe的形式,动态的调用Router:
5、一键启动
为什么要集成,除了方便使用,还有个原因当然是为了方便部署,无论是在linux下,还是windows下,都要求无障碍部署。
(1)要求平台的前端niginx要自动安装部署,自动修改配置文件,自动将dist页面文件拷入到html目录;windows自带有7zip解压zip安装文件的组件。
(2)后端以jar服务启动,windows下要求以JavaService.exe创建widnows服务并自启动,另外windows下启动服务要通过vbs等操作获取管理员权限启动。
(3)管理平台的数据库环境以mysql或postgresql ,做成一键部署(可以将带初始化数据的库文件一起打入安装包,这样再次安装解压数据库时就不需要导入初始数据了),linux下是tar.gz的二进制安装文件,windows下是zip绿色包文件。
(4)influxdb和grafana也是一键部署,基于官网的tar.gz或zip包解压运行,可以先将初始数据打入安装包中。
(5)skywalking官网的集成包,就带有一键启动,只需要做少量改动,将ES或tcp h2的启动也加入到一键启动中(需要加个端口启动判断,必须等数据库端口启动后,再启动OAP服务,否则OAP服务启动后会再次关闭)。
(6)有了一键启动,还要有一键杀进程及卸载服务的功能。并且要避免重复启动进程。
虽然可以按以上要求做成一键启动监控平台,但还算不上真正的一键部署,除非加入配置的一步步输入提示,自动安装JRE及环境变量等基础环境,但这样一来安装包的大小将很大,对于集成系统来说,这是很难理想化的,毕竟各个模块也都推荐分布式部署,非要做成单机版一键安装,有点本末倒置。
未完待续......(后续涉及到监控数据管理功能的开发,和整合所有监控节点的健康状态展示,由于工作量较大,还没能力在短期内落实)