- PVSM.RU - https://www.pvsm.ru -

Дружим Prometheus с Caché

Prometheus [1] – одна из систем мониторинга, адаптированных под сбор time series данных [2].
Она достаточно проста в инсталляции и первоначальной настройке. Имеет встроенную графическую подсистему для отображения данных PromDash [3], однако сами же разработчики рекомендуют использовать бесплатный сторонний продукт Grafana [4]. Prometheus умеет мониторить много чего («железо», контейнеры, различные СУБД), однако в данной статье хотелось бы остановиться на реализации мониторинга инстанса Caché [5] (точнее, инстанс будет Ensemble, но метрики будем брать кашовые). Кому интересно — милости просим под кат.
Дружим Prometheus с Caché - 1 [6]

В нашем простейшем случае Prometheus и Caché будут жить на одной машине (Fedora Workstation 24 x86_64). Версия Caché:

%SYS>write $zv
Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2016.1 (Build 656U) Fri Mar 11 2016 17:58:47 EST

Инсталляция и настройка

Качаем с офсайта [7]подходящий дистрибутив Prometheus и сохраняем в каталог /opt/prometheus.

image

Распаковываем архив, правим имеющийся шаблонный конфиг согласно нашим нуждам и стартуем Prometheus. По умолчанию, Prometheus будет писать логи своей работы прямо в консоль, поэтому мы перенаправим записи о его активности в лог-файл.

Запускаем Prometheus

# pwd
/opt/prometheus
# ls
prometheus-1.4.1.linux-amd64.tar.gz
# tar -xzf prometheus-1.4.1.linux-amd64.tar.gz
# ls
prometheus-1.4.1.linux-amd64 prometheus-1.4.1.linux-amd64.tar.gz
# cd prometheus-1.4.1.linux-amd64/
# ls
console_libraries consoles LICENSE NOTICE prometheus prometheus.yml promtool
# cat prometheus.yml
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.

scrape_configs:
  - job_name: 'isc_cache'
    metrics_path: '/metrics/cache'
    static_configs:
    - targets: ['localhost:57772']

# ./prometheus > /var/log/prometheus.log 2>&1 &
[1] 7117
# head /var/log/prometheus.log
time=«2017-01-01T09:01:11+02:00» level=info msg=«Starting prometheus (version=1.4.1, branch=master, revision=2a89e8733f240d3cd57a6520b52c36ac4744ce12)» source=«main.go:77»
time=«2017-01-01T09:01:11+02:00» level=info msg=«Build context (go=go1.7.3, user=root@e685d23d8809, date=20161128-09:59:22)» source=«main.go:78»
time=«2017-01-01T09:01:11+02:00» level=info msg=«Loading configuration file prometheus.yml» source=«main.go:250»
time=«2017-01-01T09:01:11+02:00» level=info msg=«Loading series map and head chunks...» source=«storage.go:354»
time=«2017-01-01T09:01:11+02:00» level=info msg=«23 series loaded.» source=«storage.go:359»
time=«2017-01-01T09:01:11+02:00» level=info msg="Listening on :9090" source=«web.go:248»

Конфиг prometheus.yml описывается на языке YAML [8], не любящем табуляций, использовать нужно только пробелы. Выше мы указали, что метрики будем тянуть с адреса http://localhost:57772 [9] и опрашивать будем приложение /metrics/cache (имя приложения выбрано произвольно), т.е. конечный адрес для сбора метрик будет http://localhost:57772/metrics/cache [10]. К каждой метрике будет дописываться метка «job=isc_cache». Метка – очень грубо говоря, это аналог WHERE для SQL. В нашем случае использоваться она не будет, но для числа серверов, больше одного, очень даже сгодится. Например, имена серверов (и/или инстансов) можно сохранять в метках и в дальнейшем метками параметризировать запросы для отрисовки графиков. Проверим, что Prometheus заработал (выше в выводе мы видим порт, который он прослушивает — 9090):

image

Открылся веб-интерфейс, стало быть, Prometheus работает. Однако метрик Caché он пока что, естественно, не видит (проверим, нажав Status → Targets):

image

Подготовка метрик

Наша задача – сделать так, чтобы по адресу http://localhost:57772/metrics/cache [10] можно было стянуть метрики в понятном для Prometheus виде [11]. Будем использовать REST-возможности Caché [12] в силу их простоты. Сразу отметим, что Prometheus «понимает» только метрики числовые, так что строковые метрики экспортировать не будем. Для получения тестовых метрик будем использовать API класса SYS.Stats.Dashboard [13]. Эти метрики используются самой Caché для отображения Системной панели инструментов:

image

Пример того же самого в Терминале

%SYS>set dashboard = ##class(SYS.Stats.Dashboard).Sample()
%SYS>zwrite dashboard
dashboard=<OBJECT REFERENCE>[2@SYS.Stats.Dashboard]
+----------------- general information — | oref value: 2
| class name: SYS.Stats.Dashboard
| reference count: 2
+----------------- attribute values — | ApplicationErrors = 0
| CSPSessions = 2
| CacheEfficiency = 280.03
| DatabaseSpace = «Normal»
| DiskReads = 2317
| DiskWrites = 329
| ECPAppServer = «OK»
| ECPAppSrvRate = 0
| ECPDataServer = «OK»
| ECPDataSrvRate = 0
| GloRefs = 740953
| GloRefsPerSec = «166.00»
| GloSets = 60947
| JournalEntries = 403

Песочницей будет служить область USER. Для начала создадим REST веб-приложение /metrics. Для хоть какой-то безопасности укажем вход в приложение по паролю, также укажем, что соответствовать этому веб-приложению будет некий ресурс, назовем его PromResource. В ресурсе закроем публичный доступ. То есть сделаем следующее:

%SYS>write ##class(Security.Resources).Create("PromResource","Resource for Metrics web page","")
1

Настройки нашего веб-приложения:

image

Нам нужен будет пользователь, имеющий возможность использовать этот ресурс. Также пользователь должен иметь права на чтение рабочей базы (в нашем случае, USER) и запись в нее. Помимо этого, ему понадобится право на чтение системной базы CACHESYS, поскольку ниже в коде реализации мы будем переходить в область %SYS. Будем следовать стандартной схеме, т.е. создадим роль PromRole c этими возможностями, после чего создадим пользователя PromUser с этой ролью. Пароль выберем, например, "Secret":

%SYS>write ##class(Security.Roles).Create("PromRole","Role for PromResource","PromResource:U,%DB_USER:RW,%DB_CACHESYS:R")
1
%SYS>write ##class(Security.Users).Create("PromUser","PromRole","Secret")
1

Именно этого пользователя PromUser мы укажем для аутентификации в конфиге Prometheus. После чего перечитаем конфиг путем посылки процессу сервера сигнала SIGHUP.

Более безопасный конфиг

# cat /opt/prometheus/prometheus-1.4.1.linux-amd64/prometheus.yml
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.

scrape_configs:
  - job_name: 'isc_cache'
    metrics_path: '/metrics/cache'
    static_configs:
    - targets: ['localhost:57772']
    basic_auth:
      username: 'PromUser'
      password: 'Secret'

#
# kill -SIGHUP $(pgrep prometheus) # or kill -1 $(pgrep prometheus)

Теперь Prometheus может успешно пройти аутентификацию для использования веб-приложения с метриками.

Метрики нам будет отдавать класс-обработчик REST-запросов my.Metrics.

Вот его реализация

Class my.Metrics Extends %CSP.REST
{

Parameter ISCPREFIX = "isc_cache";

Parameter DASHPREFIX = {..#ISCPREFIX_"_dashboard"};

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Url="/cache" Method="GET" Call="getMetrics"/>
</Routes>
}

/// Output should obey the Prometheus exposition formats. Docs:
/// https://prometheus.io/docs/instrumenting/exposition_formats/
/// 
/// The protocol is line-oriented. A line-feed character (n) separates lines. 
/// The last line must end with a line-feed character. Empty lines are ignored.
ClassMethod getMetrics() As %Status
{
	set nl = $c(10)
	do ..getDashboardSample(.dashboard)
	do ..getClassProperties(dashboard.%ClassName(1), .propList, .descrList)
	
	for i=1:1:$ll(propList) {
		set descr = $lg(descrList,i)
		set propertyName = $lg(propList,i)
		set propertyValue = $property(dashboard, propertyName)
		
		// Prometheus supports time series database 
		// so if we get empty (for example, backup metrics) or non-digital metrics 
		// we just omit them.
		if ((propertyValue '= "") && ('$match(propertyValue, ".*[-A-Za-z ]+.*"))) {
			set metricsName = ..#DASHPREFIX_..camelCase2Underscore(propertyName)
			set metricsValue = propertyValue
			
			// Write description (help) for each metrics.
			// Format is that the Prometheus requires.
			// Multiline descriptions we have to join in one string.
			write "# HELP "_metricsName_" "_$replace(descr,nl," ")_nl
			write metricsName_" "_metricsValue_nl
		}
	}
	
	write nl
	quit $$$OK
}

ClassMethod getDashboardSample(Output dashboard)
{
	new $namespace
	set $namespace = "%SYS"
	set dashboard = ##class(SYS.Stats.Dashboard).Sample()
}

ClassMethod getClassProperties(className As %String, Output propList As %List, Output descrList As %List)
{
	new $namespace
	set $namespace = "%SYS"
	
	set propList = "", descrList = ""
	set properties = ##class(%Dictionary.ClassDefinition).%OpenId(className).Properties
	
	for i=1:1:properties.Count() {
		set property = properties.GetAt(i)
		set propList = propList_$lb(property.Name)
		set descrList = descrList_$lb(property.Description)
	}
}

/// Converts metrics name in camel case to underscore name with lower case
/// Sample: input = WriteDaemon, output = _write_daemon
ClassMethod camelCase2Underscore(metrics As %String) As %String
{
	set result = metrics
	set regexp = "([A-Z])"
	set matcher = ##class(%Regex.Matcher).%New(regexp, metrics)
	while (matcher.Locate()) {
		set result = matcher.ReplaceAll("_"_"$1")
	}
	
	// To lower case
	set result = $zcvt(result, "l")
	
	// _e_c_p (_c_s_p) to _ecp (_csp)
	set result = $replace(result, "_e_c_p", "_ecp")
	set result = $replace(result, "_c_s_p", "_csp")
	
	quit result
}
}

В консоли проверим, что наши труды не прошли зря (добавлен ключ --silent, чтобы curl не мешал своим прогресс-баром):

Проверяем выгрузку метрик

# curl --user PromUser:Secret --silent -XGET 'http://localhost:57772/metrics/cache' | head -20
# HELP isc_cache_dashboard_application_errors Number of application errors that have been logged.
isc_cache_dashboard_application_errors 0
# HELP isc_cache_dashboard_csp_sessions Most recent number of CSP sessions.
isc_cache_dashboard_csp_sessions 2
# HELP isc_cache_dashboard_cache_efficiency Most recently measured cache efficiency (Global references / (physical reads + writes))
isc_cache_dashboard_cache_efficiency 439.56
# HELP isc_cache_dashboard_disk_reads Number of physical block read operations since system startup.
isc_cache_dashboard_disk_reads 2605
# HELP isc_cache_dashboard_disk_writes Number of physical block write operations since system startup
isc_cache_dashboard_disk_writes 1021
# HELP isc_cache_dashboard_ecp_app_srv_rate Most recently measured ECP application server traffic in bytes/second.
isc_cache_dashboard_ecp_app_srv_rate 0
# HELP isc_cache_dashboard_ecp_data_srv_rate Most recently measured ECP data server traffic in bytes/second.
isc_cache_dashboard_ecp_data_srv_rate 0
# HELP isc_cache_dashboard_glo_refs Number of Global references since system startup.
isc_cache_dashboard_glo_refs 1593830
# HELP isc_cache_dashboard_glo_refs_per_sec Most recently measured number of Global references per second.
isc_cache_dashboard_glo_refs_per_sec 131.00
# HELP isc_cache_dashboard_glo_sets Number of Global Sets and Kills since system startup.
isc_cache_dashboard_glo_sets 132003

Теперь можно проверить и в интерфейсе Prometheus:

image

Вот и список наших метрик:

image

Не будем останавливаться на их просмотре в самом Prometheus. Желающие могут выбрать нужную метрику и нажать кнопку “Execute”. Выбрав вкладку “Graph”, можно увидеть и график (показана эффективность кэша):

image

Визуализация метрик

Для графического отображения поставим себе Grafana [14]. Для данной статьи была выбрана инсталляция из тарболла. Но вариантов инсталляции много, от пакетов до контейнера. Проделаем указанные шаги (предварительно только создадим каталог /opt/grafana и перейдем в него):

image

Конфиг пока оставим как есть. И в последнем шаге мы стартуем Grafana в фоновом режиме. Лог работы Grafana перенаправим в файл, как и в случае с Prometheus:

# ./bin/grafana-server > /var/log/grafana.log 2>&1 &

Веб-интерфейс Grafana по умолчанию доступен на порту 3000. Логин/пароль: admin/admin.

image

Как подружить Prometheus с Grafana описано здесь [15]. Если своими словами, то – добавляем новый Data Source с типом Prometheus. В качестве доступа direct/proxy выбираете свой вариант:

image

Затем добавляем Дашбоард с нужными нам панелями. Тестовая заготовка Дашбоарда имеется в общем доступе [16]. Там же лежит и код класса для сбора метрик. Дашбоард можно просто импортировать в свою Grafana (Dashboards → Import):

image

После импорта получим вот такую картину:

image

Сохраним Дашбоард:

image

Выбор временного диапазона и период обновления выбираются вверху справа:

image

Примеры работы мониторинга

Протестируем мониторинг обращения к глобалам:

USER>for i=1:1:1000000 {set ^prometheus(i) = i}
USER>kill ^prometheus

Видим, что число ссылок на глобалы в секунду возросло, тогда как эффективность кэша упала (глобала ^prometheus в кэше еще не было):

image

Проверим использование лицензий. Создадим примитивную CSP-страницу PromTest.csp в области USER:

<html>
<head><title>Prometheus Test Page</title></head>
<body>Monitoring works fine!</body>
</html>

И посетим ее энное число раз (приложение /csp/user предполагаем незапароленным):

# ab -n77 http://localhost:57772/csp/user/PromTest.csp [17]

Увидим такую картину с лицензиями:

image

Краткие выводы

Как видим, внедрение подобного мониторинга не составляет большого труда. Уже на начальном этапе мы можем получить важные сведения о работе системы, как то: использование лицензий, эффективность кэша глобалов, наличие ошибок приложений. Для примера был взят класс SYS.Stats.Dashboard [18], однако не меньшего внимания достойны и другие классы пакетов SYS, %SYSTEM, %SYS. Также никто не ограничивает в фантазии и возможности написания своего класса, выдающего по запросу метрики именно вашего приложения, например, число документов того или иного типа. Некоторые полезные метрики планируется вынести в отдельный шаблон для Grafana.

To be continued

Если данная тема интересна, продолжение будет следовать. Что в планах:

  1. Подготовка шаблона для Grafana с метриками работы демона записи. Неплохо бы сделать некий графический аналог утилиты ^mgstat [19], во всяком случае, для части ее метрик.
  2. Пароль на веб-приложение – это хорошо, но хотелось бы проверить возможность использования сертификатов.
  3. Использование Prometheus, Grafana и некоторых экспортеров для Prometheus уже в виде Docker-контейнеров.
  4. Использование сервисов обнаружения для автоматического добавления новых инстансов Caché в мониторинг Prometheus. Тут также хотелось бы показать на практике такую удобную вещь Grafana, как шаблоны. Это что-то вроде динамических панелей, когда в зависимости от выбранного сервера показываются только его метрики, но все это на одном и том же Дашбоарде.
  5. Alert Manager Prometheus.
  6. Конфигурационные настройки Prometheus, касающиеся времени хранения данных, а также возможности по оптимизации для систем с большим числом метрик и малым интервалом их сбора.
  7. Разные нюансы, которые всплывут по ходу дела.

Ссылки

В процессе подготовки данной статьи был посещен ряд полезных мест и просмотрено некоторое количество видео:

Спасибо дочитавшим до этой строки!

Автор: InterSystems

Источник [26]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/intersystems-cache/231802

Ссылки в тексте:

[1] Prometheus : https://prometheus.io/

[2] time series данных: https://en.wikipedia.org/wiki/Time_series_database

[3] PromDash: https://prometheus.io/docs/visualization/promdash/

[4] Grafana: http://grafana.org

[5] Caché: http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls

[6] Image: https://habrahabr.ru/company/intersystems/blog/318940/

[7] офсайта : https://prometheus.io/download/

[8] YAML: https://ru.wikipedia.org/wiki/YAML

[9] http://localhost:57772: http://localhost:57772

[10] http://localhost:57772/metrics/cache: http://localhost:57772/metrics/cache

[11] виде: https://prometheus.io/docs/instrumenting/writing_exporters/

[12] REST-возможности Caché: http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GREST

[13] SYS.Stats.Dashboard: http://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?PAGE=CLASS&LIBRARY=%25SYS&CLASSNAME=SYS.Stats.Dashboard

[14] Grafana: http://grafana.org/download/

[15] здесь: https://prometheus.io/docs/visualization/grafana/

[16] общем доступе: https://github.com/myardyas/prometheus

[17] http://localhost:57772/csp/user/PromTest.csp: http://localhost:57772/csp/user/PromTest.csp

[18] SYS.Stats.Dashboard: https://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?PAGE=CLASS&LIBRARY=%25SYS&CLASSNAME=SYS.Stats.Dashboard

[19] ^mgstat: https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_mgstat#GCM_C173763

[20] Сайт проекта Grafana: http://grafana.org/

[21] Блог компании Selectel: https://blog.selectel.ru/monitoring-servisov-s-prometheus/

[22] Блог одного из разработчиков Prometheus по имени Brian Brazil: https://www.robustperception.io/blog/

[23] Туториал на сайте DigitalOcean: https://www.digitalocean.com/community/tutorials/how-to-use-prometheus-to-monitor-your-ubuntu-14-04-server

[24] Немного видео от компании Robust Perception: https://www.youtube.com/channel/UCtiFWOeRSTP3M6QUnTEKwpw

[25] Много видео с конференции, посвященной Prometheus: https://www.youtube.com/channel/UC4pLFely0-Odea4B2NL1nWA/videos

[26] Источник: https://habrahabr.ru/post/318940/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best