Добрый день! Данная статья является продолжением статьи "Дружим Prometheus с Caché". Мы рассмотрим вариант визуализации результатов работы утилиты ^mgstat. Эта утилита предоставляет статистику производительности Caché, а именно, число вызовов глобалов и рутин, локальное и по ECP, длину очереди демона записи, число блоков, записанных на диск и считанных с диска, объем ECP-трафика и прочее. Запускаться ^mgstat может как отдельно (интерактивно или джобом), так и при работе другой утилиты оценки производительности ^pButtons.
Изложение материала хотелось бы разбить на две части: в первой графически показать непосредственно статистику, собираемую ^mgstat, а во второй — рассмотреть, как именно эта статистика собирается. Если коротко, то используются $zu-функции. Однако к большинству собираемых параметров есть и объектный интерфейс через классы пакета SYS.Stats. И далеко не все параметры, которые можно собрать, показываются в ^mgstat. В дальнейшем мы попробуем все их отобразить на Grafana-дашбоардах. В этот же раз покажем только то, что нам предоставляет сам ^mgstat. Кроме того, попробуем на вкус Docker-контейнеры.
Ставим Docker
В первой части рассказывается, как инсталлировать Prometheus и Grafana из тарболлов. Покажем, как можно запустить тот же мониторинговый сервер, используя возможности Docker. Демонстрационная хост-машина:
# uname -r
4.8.16-200.fc24.x86_64
# cat /etc/fedora-release
Fedora release 24 (Twenty Four)
Будут задействованы еще две виртуальные машины (192.168.42.131 и 192.168.42.132) в среде VMWare Workstation Pro 12.0, обе с Caché на борту. Их мы и будем мониторить. Версии:
# uname -r
3.10.0-327.el7.x86_64
# cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.2 (Maipo)
…
USER>write $zversion
Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2016.2 (Build 721U) Wed Aug 17 2016 20:19:48 EDT
На хост-машине поставим Docker и запустим его:
# dnf install -y docker
# systemctl start docker
# systemctl status docker
● docker.service — Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: active (running) since Wed 2017-06-21 15:08:28 EEST; 3 days ago
...
Запускаем Prometheus в Docker-контейнере
Загрузим последний образ Prometheus:
# docker pull docker.io/prom/prometheus
Если мы посмотрим на Docker-файл, то увидим, что образ читает конфиг из своего файла /etc/prometheus/prometheus.yml, а собранные метрики сохраняет в каталог /prometheus:
…
CMD [ "-config.file=/etc/prometheus/prometheus.yml",
"-storage.local.path=/prometheus",
...
При запуске Prometheus в Docker-контейнере укажем конфигурационный файл и базу данных для метрик брать с хост-машины. Это позволит нам «пережить» рестарт контейнера. Создадим на хост-машине каталоги для Prometheus:
# mkdir -p /opt/prometheus/data /opt/prometheus/etc
Создадим конфигурационный файл Prometheus:
# cat /opt/prometheus/etc/prometheus.yml
global:
scrape_interval: 10sscrape_configs:
- job_name: 'isc_cache'
metrics_path: '/mgstat/5' # Tail 5 (sec) it's a diff time for ^mgstat. Should be less than scrape interval.
static_configs:
- targets: ['192.168.42.131:57772']
- targets: ['192.168.42.132:57772']
basic_auth:
username: 'PromUser'
password: 'Secret'
Теперь можно запустить контейнер с Prometheus:
# docker run -d --name prometheus
--hostname prometheus -p 9090:9090
-v /opt/prometheus/etc/prometheus.yml:/etc/prometheus/prometheus.yml
-v /opt/prometheus/data/:/prometheus
docker.io/prom/prometheus
Проверим, что он запустился нормально:
# docker ps --format "{{.ID}}: {{.Command}} {{.Status}} {{.Names}}"
d3a1db5dec1a: "/bin/prometheus -con" Up 5 minutes prometheus
Запускаем Grafana в Docker-контейнере
Для начала качаем себе последний образ:
# docker pull docker.io/grafana/grafana
Затем запускаем его, указав, что базу данных Grafana (по умолчанию, это SQLite) будем хранить на хост-машине. Также делаем линк на контейнер с Prometheus, чтобы можно было из контейнера с Grafana ссылаться на контейнер с Prometheus:
# mkdir -p /opt/grafana/db
# docker run -d --name grafana
--hostname grafana -p 3000:3000
--link prometheus
-v /opt/grafana/db:/var/lib/grafana
docker.io/grafana/grafana
# docker ps --format "{{.ID}}: {{.Command}} {{.Status}} {{.Names}}"
fe6941ce3d15: "/run.sh" Up 3 seconds grafana
d3a1db5dec1a: "/bin/prometheus -con" Up 14 minutes prometheus
Используем Docker-compose
Оба контейнера у нас запущены по одному. Более удобным способом запуска сразу нескольких контейнеров представляется использование Docker-compose. Поставим его, остановим текущие оба контейнера, сконфигурируем их запуск через Docker-compose и запустим заново.
# docker stop $(docker ps -a -q)
# docker rm $(docker ps -a -q)
# mkdir /opt/docker-compose
# cat /opt/docker-compose/docker-compose.yml
version: '2'
services:
prometheus:
image: docker.io/prom/prometheus
container_name: prometheus
hostname: prometheus
ports:
- 9090:9090
volumes:
- /opt/prometheus/etc/prometheus.yml:/etc/prometheus/prometheus.yml
- /opt/prometheus/data/:/prometheus
grafana:
image: docker.io/grafana/grafana
container_name: grafana
hostname: grafana
ports:
- 3000:3000
volumes:
- /opt/grafana/db:/var/lib/grafana
# docker-compose -f /opt/docker-compose/docker-compose.yml up -d
# # Выключить и удалить оба контейнера можно командой:
# # docker-compose -f /opt/docker-compose/docker-compose.yml down
# docker ps --format "{{.ID}}: {{.Command}} {{.Status}} {{.Names}}"
620e3cb4a5c3: "/run.sh" Up 11 seconds grafana
e63416e6c247: "/bin/prometheus -con" Up 12 seconds prometheus
Постинсталляционные процедуры
После запуска Grafana в первый раз нужно еще сделать две вещи: поменять пароль админа на веб-интерфейс (по умолчанию, логин/пароль — это admin/admin) и добавить Prometheus в качестве источника данных. Это можно сделать либо из веб-интерфейса, либо путем прямого редактирования базы данных Grafana SQLite (она по умолчанию лежит в файле /opt/grafana/db/grafana.db), либо путем REST-запросов.
-H "Content-Type:application/json"
-d '{"oldPassword":"admin","newPassword":"TopSecret","confirmNew":"TopSecret"}'
Если пароль был изменен успешно, придет ответ:
{"message":"User password changed"}
Ответ типа:
curl: (56) Recv failure: Connection reset by peer
означает, что сервер Grafana еще не до конца стартовал и нужно подождать еще немного, после чего повторить предыдущую команду. Подождать можно, например, так:
# until curl -sf admin:admin@localhost:3000 > /dev/null; do sleep 1; echo "Grafana is not started yet";done; echo "Grafana is started"
После успешной смены пароля добавим источник данных Prometheus:
# curl -XPOST "admin:TopSecret@localhost:3000/api/datasources"
-H "Content-Type:application/json"
-d '{"name":"Prometheus","type":"prometheus","url":"http://prometheus:9090","access":"proxy"}'
Если источник данных был добавлен успешно, придет ответ:
{"id":1,"message":"Datasource added","name":"Prometheus"}
Создаем аналог ^mgstat
^mgstat пишет вывод в файл и в интерактивном режиме на терминал. Нам вывод в файл не нужен. Поэтому с помощью Студии создадим и скомпилируем в области USER программу ^mymgstat.int, с урезанным кодом ^mgstat.
mgstat(dly)
/*
Edited version of ^mgstat for Prometheus monitoring
Changes:
- Variables cnt, reqname and pagesz are deleted as well as all code connected to them;
- Output procedure was overwritten;
- Unused procedures were deleted.
*/
;
;
n dly
d init
d loop
q
init
s prefix="isc_cache_mgstat_"
s $zt="initerr" ; for class errors mainly??? the vers exist in 4.1
d GetVersionInfo(.Majver,.Minver,.OS)
i Majver<5 w "Sorry, this won't work on this version of Cache",! q // not supported on pre-5.0 systems.
s (odly,dly)=$g(dly,2) i dly>10 s dly=10
; set common memory offsets
s jrnbase=$ZU(40,2,94),maxval4=4294967295
s wdwchk=$ZU(40,2,146),wdphaseoff=$ZU(40,2,145)
s wdcycle=$ZU(79,1),stilen=$zu(40,0,1),szctrs=1
s (globufs,glostr)=$v($ZU(40,2,135),-2,stilen)/512 f i=1:1:5 { s tmp=$v($ZU(40,2,135)+(i*stilen),-2,stilen)*(2**(1+i))/1024,globufs=globufs+tmp,glostr=glostr_"^"_tmp } s globufs=globufs_"MB:"_glostr
if Majver>2008||((Majver=2008)&&(Minver>1)) { s roustr=$tr($system.Util.RoutineBuffers(),",","^"),roubufs=0 f i=1:1:$l(roustr,"^") { s roubufs=roubufs+$p(roustr,"^",i) } s roubufs=roubufs_"MB:"_roustr }
else {
i (Majver=5)&&(Minver<1) { s rbufsiz=32,rbstr=",routinebuffersize=assumed 32K" } else { s rbufsiz=$v($zu(40,2,164),-2,4)+2401024,rbstr=",routinebuffersize="_rbufsiz_"K" }
s roubufs=$fn($V($zu(40,2,26),-2,stilen)*rbufsiz/1024,"",0)_"MB"_rbstr
}
s ncpus=$system.Util.NumberOfCPUs()
if Majver>2000 { // really > 5.2
s sznames="Global,ObjClass,Per-BDB",sztag="Gbl,Obj,BDB",szstr=$$GetSzctr(sznames) // seize statistics
if Majver>2008 {
if Majver>2009 {
s szctrs=$zu(69,74) ;0 for off, 1 for on - new in 2010.x - chg for API in 2011
}
s $zt="initcpuerr"
s ncpus=ncpus_":"_$$GetArchChipsCores() ;Arch^Chips^Cores
initcpuerr ;
k n
s $zt=""
}
} else {
s szstr="4,2,14",sztag="Gbl,Rou,Obj" // 5.2 and lower - glo,rou,obj
}
i szstr="" { s nszctrs=0 } else { s nszctrs=szctrs*$l(szstr,",") }
s numsz=nszctrs*3 // Sz, Nsz, Asz for each one.
; decide on offsets where they move between versions...
i (Majver=5)&&(Minver<1) {
;5.0 specific - no zu190!!! - oldstyle gather() and wd info
s getwdq="getwdinf50()",maxvalglo=maxval4,glocnt=11,gmethod=0,roubase=$zu(40,2,1)
s bdb0off=$ZU(40,2,128),bdbbase=$V($ZU(40,2,21),-2,"P"),bdbsiz=$ZU(40,29,0),wdqsizoff=$ZU(40,29,2),off=$V(bdb0off,-2,4),vwlocn=bdbbase+wdqsizoff
s ppgstats=0
} else {
s getwdq="getwdinfzu()",numbuff=$zu(190,2),ijulock=1,glocnt=$l($zu(190,6,1),","),gmethod=1
s ppgstats=glocnt'<20
i $zu(40,0,76)=4 { s maxvalglo=maxval4 } else { s maxvalglo=18446744073709551610 }
; wij only appears in >= 5.1... but handled by glocnt
; routine cache misses appears in >= 2007.1 but handled by glocnt
i glocnt>14 s glocnt=14
}
s ecpconncol=glocnt+numsz+2,alen=ecpconncol+5,maxeccon=$system.ECP.MaxClientConnections() i 'maxeccon s alen=ecpconncol-1
q
initerr
; handle init errs
q
loop
d gather(.oldval,gmethod)
h dly
d gather(.newval,gmethod)
d diffandfix()
d output
gather(array,usezu)
i usezu {
s zustats1=$zu(190,6,1) ; glostat
For i=1:1:glocnt S array(i)=$P(zustats1,",",i)
} else { ; old (5.0) glostat, gloref,glorefclient,logrd,phyrd,phywr,gloset,glosetclient,roulines
for i=1:1:glocnt s array(i)=$v((i-1)*4+roubase,-2,4) ;;;incomplete!!???10/22
}
d @getwdq,getwdp()
s i=glocnt,array($i(i))=$v(jrnbase,-2,4) ; jrnwrites
for jsz=1:1:nszctrs { s j=$p(szstr,",",jsz),szstat=$zu(162,3,j),array($i(i))=$p(szstat,","),array($i(i))=$p(szstat,",",2),array($i(i))=$p(szstat,",",3) }
i maxeccon s estats=$p($system.ECP.GetProperty("ClientStats"),",",1,21),array($i(i))=+$system.ECP.NumClientConnections(),array($i(i))=$p(estats,",",2),array($i(i))=$p(estats,",",6),array($i(i))=$p(estats,",",7),array($i(i))=$p(estats,",",19),array($i(i))=$p(estats,",",20)
i ppgstats s array($i(i))=$p(zustats1,",",20),array($i(i))=$p(zustats1,",",21)
q
diffandfix() ; note - this does not work if someone zeroed the counters manually
f i=1:1:glocnt {
i newval(i)<oldval(i) {
s dispval(i)=(maxvalglo-oldval(i)+newval(i))dly
i dispval(i)>1000000000 s dispval(i)=newval(i)dly
} else {
s dispval(i)=(newval(i)-oldval(i))dly
}
s oldval(i)=newval(i)
}
s rdratio=$s(dispval(8)=0:0,1:$num(dispval(7)/dispval(8),2))
s grratio=$s(dispval(6)=0:0,1:$num(dispval(5)/dispval(6),2))
i maxeccon s dispval(ecpconncol)=newval(ecpconncol)
f i=glocnt+1:1:ecpconncol-1,ecpconncol+1:1:alen+$s(ppgstats:2,1:0) {
i newval(i)<oldval(i) {
s dispval(i)=(maxval4-oldval(i)+newval(i))dly
i dispval(i)>1000000000 s dispval(i)=newval(i)dly
} else {
s dispval(i)=(newval(i)-oldval(i))dly
}
s oldval(i)=newval(i)
}
if nszctrs>0 {
f i=glocnt+2:3:glocnt+numsz-1 {
i 'dispval(i) {
s (dispval(i+1),dispval(i+2))="0"
} else {
s dispval(i+1)=$num(dispval(i+1)/dispval(i)*100,2)
s dispval(i+2)=$num(dispval(i+2)/dispval(i)*100,2)
}
}
}
q
output
s nl=$c(10)
w prefix_"global_refs "_dispval(5)_nl
w prefix_"remote_global_refs "_dispval(6)_nl
w prefix_"global_remote_ratio "_grratio_nl
w prefix_"physical_reads "_dispval(8)_nl
w prefix_"read_ratio "_rdratio_nl
w prefix_"global_updates "_dispval(10)_nl
w prefix_"remote_global_updates "_dispval(11)_nl
w prefix_"routine_refs "_dispval(1)_nl
w prefix_"remote_routine_refs "_dispval(2)_nl
w prefix_"routine_loads_and_saves "_dispval(3)_nl
w prefix_"remote_routine_loads_and_saves "_dispval(4)_nl
w prefix_"physical_writes "_dispval(9)_nl
w prefix_"write_daemon_queue_size "_wdqsz_nl
w prefix_"write_daemon_temp_queue "_twdq_nl
w prefix_"write_daemon_phase "_wdphase_nl
i glocnt>12 w prefix_"wij_writes "_dispval(13)_nl
i glocnt>13 w prefix_"routine_cache_misses "_dispval(14)_nl
w prefix_"journal_writes "_dispval(glocnt+1)_nl
s icnt=1
f i=1:1:numsz {
; global/rou/obj nseize/aseize are nodisp-100+
; and start at dispval(glocnt+2) and go up...
s rsc=$p(sztag,",",i)
w prefix_rsc_"seizes "_dispval(i+glocnt+1)_nl
s icnt=icnt+1
}
s ecpnames=$lb("act_ecp","add_blocks","purge_buffers_local","purge_server_remote","bytes_sent","bytes_received")
s icnt=0,ecnt=1
f i=glocnt+numsz+2:1:alen {
; ECP are nodisp 19-24 and start at glocnt+numsz+1 and go up...
w prefix_$lg(ecpnames,ecnt)_" "_dispval(i)_nl
s icnt=icnt+1
s ecnt=ecnt+1
}
i $d(ijulock) {
w prefix_"write_daemon_pass "_wdpass_nl
w prefix_"iju_count "_ijucnt_nl
w prefix_"iju_lock "_ijulock_nl
}
s ppgnames=$lb("process_private_global_refs","process_private_global_updates")
i ppgstats {
; PPG are nodisp 28,29 and start at alen+1
f i=0,1 w prefix_$lg(ppgnames,i+1)_" "_dispval(alen+i+1)_nl
}
w nl
q
getwdinfzu()
s twdq=0 f b=1:1:numbuff { s twdq=twdq+$p($zu(190,2,b),",",10) }
s wdinf=$zu(190,13),wdpass=$p(wdinf,","),wdqsz=$p(wdinf,",",2),twdq=twdq-wdqsz i twdq<0 s twdq=0
s misc=$zu(190,4),ijulock=$p(misc,",",4),ijucnt=$p(misc,",",5)
q
getwdinf50()
s wdqsz=0,last=maxval4
f i=0:1:5 d q:off=maxval4
. s off=$V(bdb0off+(i*4),-2,4)
. q:(off=last)!(off=maxval4)
. s wdqsz=wdqsz+$V(vwlocn+off,-3,4)
. s last=off
Q
getwdp()
s wdphase=0 q:'$V(wdwchk,-2,4)
q:'wdphaseoff
s wdphase=$V(wdphaseoff,-2,4)
Q
GetArchChipsCores() private { ;Returns <Arch>^<# Chips>^<# Cores>
if $D(^oddDEF("%SYSTEM.CPU")) {
s n=##class(%SYSTEM.CPU).%New()
s Arch=n.Arch
s nChips=n.nChips
s nCores=n.nCores
} else {
; These are all here in case we want more later
Set Arch=$zu(204,1)
Set Model=$zu(204,2)
Set Vendor=$zu(204,3)
Set nThreads=$zu(204,4)
Set nCores=$zu(204,5)
Set nChips=$zu(204,6)
Set nThreadsPerCore=$zu(204,7)
Set nCoresPerChip=$zu(204,8)
Set MTSupported=$zu(204,9)
Set MTEnabled=$zu(204,10)
Set MHz=$zu(204,11)
}
quit Arch_"^"_nChips_"^"_nCores
}
GetVersionInfo(majver,minver,os) PRIVATE {
if $D(^oddDEF("%SYSTEM.CPU")) {
s majver=$System.Version.GetMajor()
s minver=$System.Version.GetMinor()
s os=$System.Version.GetCompBuildOS()
} else {
s zv=$ZV
s majver=$p($p($p(zv,") ",2)," ",1),".",1)
s minver=$p($p($p(zv,") ",2)," ",1),".",2)
If zv["Windows" {
Set os="Windows"
} elseif zv["UNIX" {
Set os="UNIX"
} elseif zv["VMS" {
Set os="VMS"
} else {
Set os="N/A"
}
}
}
GetSzctr(Longnames) private {
s allsznames=$zu(162,0)_",",zuctr=""
f i=1:1:$l(Longnames,",") {
s ctr=$p(Longnames,",",i)
continue:(ctr="")||(ctr="Unused")
s nctr=$l($e(allsznames,1,$find(allsznames,ctr)),",")-1
continue:nctr=0
i zuctr="" {
s zuctr=nctr
} else {
s zuctr=zuctr_","_nctr
}
}
quit zuctr
}
Чтобы можно было вызвать программу ^mymgstat через REST, делаем для нее в области USER класс-обертку.
Class my.Mgstat Extends %CSP.REST
{
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Url="/:delay" Method="GET" Call="getMgstat"/>
</Routes>
}
ClassMethod getMgstat(delay As %Integer = 2) As %Status
{
// By default, we use 2 second interval for averaging
do ^mymgstat(delay)
quit $$$OK
}
}
Создаем ресурс, пользователя и веб-приложение
Теперь, когда у нас есть класс, отдающий метрики, мы можем создать RESTfull веб-приложение. Как и в первой статье, присвоим этому веб-приложению ресурс и создадим пользователя, который сможет этим ресурсом воспользоваться и от имени которого Prometheus будет собирать метрики. Дадим пользователю еще права на определенные базы. По сравнению с первой статьей, добавлено право на запись в базу CACHESYS (чтобы избежать ошибки <UNDEFINED>loop+1^mymgstat *gmethod") и добавлена возможность использовать ресурс %Admin_Manage (чтобы избежать ошибки <PROTECT>gather+10^mymgstat *GetProperty,%SYSTEM.ECP"). Проделаем указанные шаги на двух виртуальных серверах, 192.168.42.131 и 192.168.42.132. Предварительно, естественно, зальем наш код, программу ^mymgstat и класс my.Mgstat, в область USER на том, и на другом сервере (код есть на github).
# wget https://github.com/myardyas/prometheus/raw/master/mgstat/cos/mymgstat.xml
# wget https://github.com/myardyas/prometheus/raw/master/mgstat/cos/Mgstat.xml
#
# # Если на серверах нет доступа к Интернету, скопируйте программу и класс локально, а затем воспользуйтесь scp.
#
# csession <instance_name> -U user
USER>do $system.OBJ.Load("/tmp/mymgstat.xml*/tmp/Mgstat.xml","ck")
USER>zn "%sys"
%SYS>write ##class(Security.Resources).Create("PromResource","Resource for Metrics web page","")
1
%SYS>write ##class(Security.Roles).Create("PromRole","Role for PromResource","PromResource:U,%Admin_Manage:U,%DB_USER:RW,%DB_CACHESYS:RW")
1
%SYS>write ##class(Security.Users).Create("PromUser","PromRole","Secret")
1
%SYS>set properties("NameSpace") = "USER"
%SYS>set properties("Description") = "RESTfull web-interface for ^mymgstat"
%SYS>set properties("AutheEnabled") = 32 ; See description
%SYS>set properties("Resource") = "PromResource"
%SYS>set properties("DispatchClass") = "my.Mgstat"
%SYS>write ##class(Security.Applications).Create("/mgstat",.properties)
1
Проверяем доступность метрик с помощью curl
# curl --user PromUser:Secret -XGET http://192.168.42.131:57772/mgstat/5
isc_cache_mgstat_global_refs 347
isc_cache_mgstat_remote_global_refs 0
isc_cache_mgstat_global_remote_ratio 0
…
# curl --user PromUser:Secret -XGET http://192.168.42.132:57772/mgstat/5
isc_cache_mgstat_global_refs 130
isc_cache_mgstat_remote_global_refs 0
isc_cache_mgstat_global_remote_ratio 0
...
Проверяем доступность метрик из Prometheus
Prometheus у нас слушает порт 9090. Сначала проверяем состояние Targets:
Затем смотрим на любую из метрик:
Отображаем одну метрику
Покажем теперь одну метрику, например, isc_cache_mgstat_global_refs, в виде графика. Нам нужно будет добавить панель и вставить в нее график. Идем в Grafana (http://localhost:3000, логин/пасс — admin/TopSecret) и добавляем панель:
Добавляем график:
Редактируем его, нажав «Panel title», затем «Edit»:
Указываем в качестве источника данных Prometheus и выбираем нашу метрику isc_cache_mgstat_global_refs. Разрешение выберем 1/1:
Даем имя графику:
Добавляем легенду:
Нажимаем сверху кнопку «Save» и даем имя дашбоарду:
Получаем что-то такое:
Отображаем все метрики
Аналогично накинем остальные метрики. В их числе будут две текстовые метрики — Singlestat. Получим такой дашбоард (показаны верхняя и нижняя части):
Сразу мешают два нюанса:
— скроллы в легенде (с увеличением числа серверов скроллить придется дольше);
— отсутствие данных в Singlestat-панелях (которые, естественно, предполагают единственное значение). У нас сервера два, вот и значения два.
Добавляем использование шаблона
Попробуем победить данные замечания введением шаблона инстансов. Для этого нам понадобится создать переменную, хранящую значение инстанса, и немного подредактировать запросы к Prometheus, согласно имеющимся правилам. То есть, вместо запроса "isc_cache_mgstat_global_refs" нам следует написать "isc_cache_mgstat_global_refs{instance="[[instance]]"}", предварительно создав переменную instance.
Создаем переменную:
В запросе к Prometheus указываем выбирать значения меток instance из каждой метрики. В нижней части наблюдаем, что значения наших двух инстансов определились. Нажимаем кнопку «Add»:
В верхней части дашбоарда появилась переменная с вариантами значений:
Теперь добавим использование этой переменной в запросы для каждой панели на дашбоарде, то есть, запросы типа "isc_cache_mgstat_global_refs" превратим в "isc_cache_mgstat_global_refs{instance="[[instance]]"}". Получим такой дашбоард (возле легенд имена инстансов оставлены специально, для проверки):
Singlestat-панели уже работают:
Скачать шаблон данного дашбоарда можно на github. Процедура его импорта в Grafana описана в первой части.
Напоследок сделаем сервер 192.168.42.132 ECP-клиентом для 192.168.42.131 и посоздаем глобалы для порождения ECP-трафика. Видим, что мониторинг ECP-клиента работает:
Итоги
Мы можем заменить отображение результатов работы утилиты ^mgstat в Excel он-лайн отображением в виде довольно симпатичных графиков. Минусом является то, что для этого нужно использовать альтернативную версию ^mgstat. В принципе, код исходной утилиты может меняться, что нами не учитывается. Однако мы получаем удобство наблюдения за происходящим в Caché.
Спасибо за внимание!
Продолжение следует ...
P.S.
Демо-стенд (для одного инстанса) доступен для просмотра здесь. Логин/пароль — operator/PromOperator.
Автор: InterSystems