Мониторинг IBM WebSphere Application Server (WAS) с помощью Proto Observability
На этой странице:
- Сбор метрик IBM WAS
- Сбор логов IBM WAS
Сбор метрик IBM WAS
Интеграция ibm_was собирает PMI-статистику (Performance Monitoring
Infrastructure) сервера приложений через PerfServlet — небольшое
веб-приложение, которое отдаёт PMI-счётчики в виде XML по HTTP:
http://<host>:9080/wasPerfTool/servlet/perfservlet
Это не JMX-интеграция: агент делает обычный HTTP-запрос и парсит XML.
Поэтому образу агента не нужен суффикс -jmx — JRE для этой интеграции
не требуется.
Поддерживается IBM WebSphere Application Server traditional (8.5.5 и 9.0.x).
Для WebSphere Liberty PMI через PerfServlet недоступен — там метрики
снимаются по-другому (через openmetrics-эндпоинт фичи mpMetrics); этот
вариант здесь не рассматривается.
Конфигурация IBM WAS
Нужно сделать две вещи: развернуть PerfServlet и убедиться, что PMI включён.
1. Развернуть приложение PerfServlet.
Файл PerfServletApp.ear поставляется вместе с WAS — он лежит в
${WAS_INSTALL_ROOT}/installableApps/PerfServletApp.ear (где
WAS_INSTALL_ROOT — корень установки, например /opt/IBM/WebSphere/AppServer).
Через админ-консоль: Applications → New Application → New Enterprise
Application → выбрать PerfServletApp.ear → в шагах мастера смапить
веб-модуль на нужный сервер приложений (Map modules to servers) и виртуальный
хост (Map virtual hosts for Web modules), оставив контекстный корень
/wasPerfTool. Достаточно развернуть на одном сервере домена.
Через wsadmin (jython). В standalone-профиле с единственным сервером проще
всего опереться на -usedefaultbindings — он сам смапит web-модуль
(имя модуля в PerfServletApp.ear — perfservlet, URI
perfServletApp.war,WEB-INF/web.xml) на server1 и default_host, а
контекстный корень /wasPerfTool возьмётся из application.xml внутри EAR:
import java.lang.System as System
ear = System.getProperty('was.install.root') + '/installableApps/PerfServletApp.ear'
AdminApp.install(ear, ['-appname', 'PerfServletApp', '-usedefaultbindings'])
AdminConfig.save()
# Если серверов несколько — добавьте явный
# -MapModulesToServers [[ perfservlet perfServletApp.war,WEB-INF/web.xml WebSphere:cell=<cell>,node=<node>,server=<server> ]]
Затем убедитесь, что по адресу http://<host>:9080/wasPerfTool/servlet/perfservlet
открывается XML-документ <PerformanceMonitor responseStatus="success" …> с
вложенными <Node> / <Server> / <Stat>.
2. Включить PMI.
В большинстве установок PMI включён по умолчанию (статистический набор
Basic). Чтобы собиралось больше счётчиков, поднимите уровень:
Monitoring and Tuning → Performance Monitoring Infrastructure (PMI) →
<имя_сервера> → отметить Enable Performance Monitoring Infrastructure
(PMI), выбрать набор статистики Extended или All → Apply → Save.
Перезапустите сервер приложений.
Через wsadmin:
# Персистентно — в конфиге сервера:
serverId = AdminConfig.getid('/Cell:DefaultCell01/Node:DefaultNode01/Server:server1/')
pmi = AdminConfig.list('PMIService', serverId)
AdminConfig.modify(pmi, [['enable', 'true'], ['initialSpecLevel', 'all']])
AdminConfig.save()
# И в рантайме (на запущенном сервере) — через PerfMBean:
perf = AdminControl.completeObjectName('type=Perf,*')
AdminControl.invoke(perf, 'setStatisticSet', '[extended]', '[java.lang.String]')
Официальный образ icr.io/appcafe/websphere-traditional настраивается на этапе
сборки: всё, что лежит в каталоге /work/config/ (файлы *.props —
properties-based config, и *.py — jython-скрипты wsadmin), применяется
скриптом /work/configure.sh к запущенному серверу, после чего конфиг
сохраняется в профиль. То есть нужно собрать производный образ:
Dockerfile:
FROM icr.io/appcafe/websphere-traditional:latest
# (необязательно) зафиксировать пароль администратора вместо случайного
COPY --chown=1001:0 PASSWORD /tmp/PASSWORD
# (необязательно) простой текстовый лог вместо HPEL/JSON
ENV ENABLE_BASIC_LOGGING=true
# скрипт деплоя PerfServlet + включения PMI
COPY --chown=1001:0 deploy-perfservlet.py /work/config/deploy-perfservlet.py
RUN env JVM_EXTRA_CMD_ARGS=-Xnoloa /work/configure.sh
deploy-perfservlet.py (jython, выполняется на запущенном сервере, поэтому
доступны и AdminConfig, и AdminControl):
import java.lang.System as System
# 1. установка PerfServlet (в single-server профиле -usedefaultbindings
# смапит web-модуль на server1 / default_host; ctx root /wasPerfTool —
# из application.xml внутри EAR)
ear = System.getProperty('was.install.root') + '/installableApps/PerfServletApp.ear'
AdminApp.install(ear, ['-appname', 'PerfServletApp', '-usedefaultbindings'])
AdminConfig.save()
# 2. PMI -> all (персистентно) + extended (рантайм)
serverId = AdminConfig.getid('/Cell:DefaultCell01/Node:DefaultNode01/Server:server1/')
pmi = AdminConfig.list('PMIService', serverId)
AdminConfig.modify(pmi, [['enable', 'true'], ['initialSpecLevel', 'all']])
AdminConfig.save()
perf = AdminControl.completeObjectName('type=Perf,*')
AdminControl.invoke(perf, 'setStatisticSet', '[extended]', '[java.lang.String]')
В реальном скрипте есть смысл добавить обнаружение имён cell/node/server и
обработку ошибок (имена DefaultCell01 / DefaultNode01 / server1 верны
только для standalone-профиля по умолчанию).
После docker run (или docker compose up) PerfServlet доступен на порту
9080.
Образ большой и грузится медленно
<code>websphere-traditional</code> — это «base»/developer-образ WAS traditional (~1.5–2 GB),
публикуется только под linux/amd64 (плюс ppc64le, s390x). Старт сервера
и прогон wsadmin-скриптов на этапе сборки занимают несколько минут — в
healthcheck’е закладывайте большой start_period, а в CI/CD — увеличенные
таймауты.
Application security и PerfServlet
В некоторых версиях/конфигурациях WAS для работы PerfServlet требуется включённая administrative/application security (в образеwebsphere-traditional админ-безопасность включена по умолчанию). Если запрос к
/wasPerfTool/servlet/perfservlet возвращает ошибку или пустой ответ — проверьте
настройки безопасности и то, что приложение PerfServletApp запущено
(Applications → Application Types → WebSphere enterprise applications).Конфигурация ProtoOBP агента
Если агент запускается в виде службы на хосте
Создайте файл
/etc/protoobp-agent/conf.d/ibm_was.d/conf.yaml:init_config: instances: - servlet_url: http://localhost:9080/wasPerfTool/servlet/perfservlet # service: websphere # тег service для метрик и логов # username: <user> # если PerfServlet за basic-auth # password: <password> # tls_verify: false # если PerfServlet за HTTPS с self-signedПерезапустите агента:
systemctl restart protoobp-agent.
По умолчанию интеграция собирает четыре группы счётчиков: jvm, jdbc,
servlet_session, thread_pools. Любую из них можно отключить параметром
collect_<группа>_stats: false (например, collect_jdbc_stats: false).
Дополнительные XML-атрибуты PMI можно вытащить через custom_queries.
Если агент запускается в виде Docker контейнера
Добавьте autodiscovery-лейблы к контейнеру WAS. В docker-compose.yaml:
labels:
com.protoobp.ad.check_names: '["ibm_was"]'
com.protoobp.ad.init_configs: '[{}]'
com.protoobp.ad.instances: '[{"servlet_url": "http://%%host%%:9080/wasPerfTool/servlet/perfservlet", "service": "websphere"}]'
%%host%% агент подставит сам — это IP контейнера WAS в docker network.
Контейнер агента
Контейнер агента должен находиться в той же docker network, что и WAS, и иметь смонтированный/var/run/docker.sock:/var/run/docker.sock:ro для autodiscovery
контейнеров. Образ агента — обычный, например protoobp-agent:7.40.3:
интеграция ibm_was работает по HTTP (PerfServlet/PMI), JMX не использует,
суффикс -jmx тут не нужен (в отличие от JMX-интеграций — ActiveMQ, Kafka,
Tomcat и т. п.).Проверка
Убедитесь, что проверка запустилась и собирает метрики:
docker exec protoobp-agent agent status | grep -A 11 "^ ibm_was"
Ожидаемый вывод — Instance ID помечен [OK], а Metric Samples за прогон
больше нуля:
ibm_was (2.3.0)
---------------
Instance ID: ibm_was:xxxxxxxxxxxxxxxx [OK]
Configuration Source: container:docker://...
Total Runs: 13
Metric Samples: Last Run: 74, Total: 816
Events: Last Run: 0, Total: 0
Service Checks: Last Run: 1, Total: 13
Average Execution Time : 44ms
Last Successful Execution Date : ...
Также можно открыть PerfServlet прямо в браузере или curl‘ом — должен
вернуться XML:
curl -s http://localhost:9080/wasPerfTool/servlet/perfservlet | head
# <?xml version="1.0" encoding="UTF-8"?>
# <!DOCTYPE PerformanceMonitor SYSTEM "/wasPerfTool/dtd/performancemonitor.dtd">
# <PerformanceMonitor responseStatus="success" version="9.0.5.27">
# <Node name="DefaultNode01">
# <Server name="server1">
# <Stat name="server"> ...
Собираемые метрики
Все метрики собираются по HTTP с PerfServlet и имеют тип gauge — содержат
мгновенное значение на момент сбора. (PMI-счётчики типа CountStatistic
интеграция отправляет как count, DoubleStatistic — как rate, но в наборе
по умолчанию таких среди перечисленных ниже нет.) Типы и единицы измерения —
согласно документации интеграции.
Лейблы
Добавляются агентом, ProtoOBP backend’ом и самой интеграцией:
| Лейбл | Где появляется | Значение / пример |
|---|---|---|
host | все метрики | Хост, на котором работает агент |
service | все метрики | Тег service (com.protoobp.tags.service, service: в конфиге или POBP_TAGS) |
env | все метрики | Тег env |
node | все метрики | Имя WAS-узла из XML PerfServlet’а (DefaultNode01) |
server | все метрики | Имя сервера приложений из XML (server1) |
url | ibm_was_can_connect и service check | URL PerfServlet’а (http://…/wasPerfTool/servlet/perfservlet) |
provider | ibm_was_jdbc_* | Имя JDBC-провайдера (Derby JDBC Provider (XA)) |
dataSource | ibm_was_jdbc_* | Имя источника данных (jdbc/built-in-derby-datasource) |
web_application | ibm_was_servlet_session_* | Имя веб-приложения (PerfServletApp#perfServletApp.war) |
thread_pool | ibm_was_thread_pools_* | Имя пула потоков (WebContainer, Default, Object Request Broker) |
docker_image, image_name, image_tag, short_image | все метрики (при autodiscovery) | Полный ref / имя / тег / короткое имя образа контейнера WAS |
JVM
Группа jvm. Для каждой метрики интеграция дополнительно публикует вариант с
суффиксом _gauge (исходные ibm_was_jvm_<имя> помечены как deprecated —
используйте _gauge-варианты).
| Имя метрики | Тип | Единица | Описание |
|---|---|---|---|
ibm_was_jvm_heap_size / …_gauge | gauge | KiB | Суммарный объём памяти JVM (heap) |
ibm_was_jvm_used_memory / …_gauge | gauge | KiB | Использованная память JVM |
ibm_was_jvm_free_memory / …_gauge | gauge | KiB | Свободная память JVM |
ibm_was_jvm_process_cpu_usage / …_gauge | gauge | percent | Использование CPU процессом JVM (%) |
ibm_was_jvm_up_time / …_gauge | gauge | second | Время работы JVM (сброс = рестарт) |
Пулы потоков (Thread Pools)
Группа thread_pools. Несут лейбл thread_pool (WebContainer, Default,
ORB.thread.pool, server.startup, …).
| Имя метрики | Тип | Единица | Описание |
|---|---|---|---|
ibm_was_thread_pools_pool_size | gauge | thread | Среднее число потоков в пуле |
ibm_was_thread_pools_active_count | gauge | thread | Число одновременно активных потоков |
ibm_was_thread_pools_active_time | gauge | millisecond | Среднее время нахождения потока в активном состоянии |
ibm_was_thread_pools_percent_used | gauge | percent | Средний % использования пула (от сконфигурированного максимума) |
ibm_was_thread_pools_percent_maxed | gauge | percent | Средний % времени, когда заняты ВСЕ потоки пула |
ibm_was_thread_pools_create_count | gauge | thread | Сколько всего потоков создано |
ibm_was_thread_pools_destroy_count | gauge | thread | Сколько всего потоков уничтожено |
ibm_was_thread_pools_declaredthread_hung_count | gauge | thread | Сколько потоков объявлено «зависшими» (hung) |
ibm_was_thread_pools_concurrent_hung_thread_count | gauge | thread | Сколько потоков «зависло» в данный момент |
ibm_was_thread_pools_cleared_thread_hang_count | gauge | thread | Сколько «зависаний» было снято (поток ожил) |
JDBC connection pools
Группа jdbc. Несут лейблы provider, dataSource.
| Имя метрики | Тип | Единица | Описание |
|---|---|---|---|
ibm_was_jdbc_pool_size | gauge | — | Размер пула соединений |
ibm_was_jdbc_free_pool_size | gauge | connection | Число свободных managed-соединений в пуле |
ibm_was_jdbc_managed_connection_count | gauge | connection | Всего managed-соединений (free + shared + unshared) |
ibm_was_jdbc_connection_handle_count | gauge | connection | Сколько соединений сейчас используется (handles) |
ibm_was_jdbc_percent_used | gauge | percent | % пула, который сейчас используется |
ibm_was_jdbc_percent_maxed | gauge | percent | % времени, когда заняты ВСЕ соединения пула |
ibm_was_jdbc_wait_time | gauge | millisecond | Среднее время ожидания выдачи соединения |
ibm_was_jdbc_use_time | gauge | millisecond | Среднее время удержания соединения |
ibm_was_jdbc_jdbc_time | gauge | millisecond | Среднее время выполнения в JDBC-драйвере (драйвер + сеть + БД) |
ibm_was_jdbc_waiting_thread_count | gauge | thread | Число потоков, ожидающих соединение |
ibm_was_jdbc_allocate_count | gauge | connection | Всего выделено managed-соединений с момента создания пула |
ibm_was_jdbc_return_count | gauge | connection | Всего возвращено managed-соединений |
ibm_was_jdbc_create_count | gauge | connection | Всего создано managed-соединений |
ibm_was_jdbc_close_count | gauge | connection | Всего уничтожено managed-соединений |
ibm_was_jdbc_fault_count | gauge | — | Число «фолтов» в пуле (например, таймаутов) |
ibm_was_jdbc_prep_stmt_cache_discard_count | gauge | — | Сколько prepared-statement’ов вытеснено LRU-алгоритмом из кэша |
Сессии сервлетов (Servlet Session Manager)
Группа servlet_session. Несут лейбл web_application.
| Имя метрики | Тип | Единица | Описание |
|---|---|---|---|
ibm_was_servlet_session_create_count | gauge | session | Сколько сессий создано |
ibm_was_servlet_session_invalidate_count | gauge | session | Сколько сессий инвалидировано |
ibm_was_servlet_session_timeout_invalidation_count | gauge | session | Сколько сессий инвалидировано по таймауту |
ibm_was_servlet_session_live_count | gauge | session | Сколько сессий сейчас в кэше в памяти |
ibm_was_servlet_session_active_count | gauge | session | Сколько сессий «активны» (обрабатывается запрос с этой сессией) |
ibm_was_servlet_session_life_time | gauge | millisecond | Среднее время жизни сессии |
ibm_was_servlet_session_no_room_for_new_session_count | gauge | — | Сколько раз отказано в создании сессии (превышен лимит, при AllowOverflow=false) |
ibm_was_servlet_session_activate_non_exist_session_count | gauge | request | Запросы к уже несуществующей (протухшей) сессии |
ibm_was_servlet_session_affinity_break_count | gauge | request | Запросы к сессии, последний доступ к которой был из другого приложения (failover / кривой plug-in) |
ibm_was_servlet_session_cache_discard_count | gauge | session | Сколько сессий вытеснено из кэша (LRU; только для persistent-сессий) |
ibm_was_servlet_session_external_read_size | gauge | — | Размер прочитанных данных сессии из persistent-store |
ibm_was_servlet_session_external_read_time | gauge | millisecond | Время чтения данных сессии из persistent-store |
ibm_was_servlet_session_external_write_size | gauge | request | Размер записанных данных сессии в persistent-store |
ibm_was_servlet_session_external_write_time | gauge | millisecond | Время записи данных сессии в persistent-store |
ibm_was_servlet_session_session_object_size | gauge | — | Размер in-memory сессий в байтах (только сериализуемые атрибуты) |
ibm_was_servlet_session_time_since_last_activated | gauge | millisecond | Время между предыдущим и текущим access-timestamp сессии |
Доступность
| Имя метрики | Тип | Описание |
|---|---|---|
ibm_was_can_connect | gauge | 1 — агент смог получить и распарсить XML с PerfServlet, 0 — нет. Дополнительно публикуется service check ibm_was_can_connect. |
Состав счётчиков и уровень PMI
Какие именно вложенные объекты (пулы потоков, источники данных, веб-приложения) попадут в выгрузку, зависит от уровня PMI (Basic / Extended / All) и от
того, что реально сконфигурировано/задеплоено на сервере. Чем выше уровень PMI,
тем больше счётчиков. Дополнительные XML-атрибуты, не входящие в набор по
умолчанию, можно подобрать через custom_queries в конфиге интеграции.Ключевые метрики для дашбордов и алертов
Доступность
ibm_was_can_connect == 0(или service checkibm_was_can_connectв CRITICAL) — PerfServlet недостижим: сервер упал, приложениеPerfServletAppне запущено, PMI выключен или сеть до агента не работает.- Отсутствие свежих серий по
instance— то же самое (агент не получает метрик).
Насыщение пулов потоков
ibm_was_thread_pools_percent_maxedperthread_poolблизок к100— пул (особенноWebContainer) исчерпан, запросы встают в очередь.ibm_was_thread_pools_declaredthread_hung_count> 0 илиibm_was_thread_pools_concurrent_hung_thread_count> 0 — есть «зависшие» потоки (долгие операции, дедлоки, медленные внешние вызовы).
Исчерпание JDBC connection pool
ibm_was_jdbc_percent_used/ibm_was_jdbc_percent_maxedстабильно высокие perdataSource— пул на пределе.ibm_was_jdbc_waiting_thread_count> 0 и/или растущийibm_was_jdbc_wait_time— потоки ждут соединение (узкое место — БД или размер пула).ibm_was_jdbc_fault_count> 0 — «фолты»/таймауты при выдаче соединений.
Сессии
- Растущий
ibm_was_servlet_session_live_count/active_countбез спада — возможна утечка сессий (не инвалидируются) → давление на heap. ibm_was_servlet_session_no_room_for_new_session_count> 0 — отказы в создании сессий (превышен лимит).
JVM
ibm_was_jvm_used_memory_gaugeстабильно близок кibm_was_jvm_heap_size_gauge— heap на пределе (рискOutOfMemoryError, длинные GC-паузы).- Высокий
ibm_was_jvm_process_cpu_usage_gauge— CPU bound. - Сброс
ibm_was_jvm_up_time_gaugeк нулю — сервер перезапустился.
Латентность веб-уровня
ibm_was_thread_pools_active_time(дляWebContainer) — рост = запросы обрабатываются дольше; коррелирует с насыщением пула и нагрузкой на JDBC.
Сбор логов IBM WAS
Логи WAS собираются ProtoOBP агентом и отправляются в бэкенд ProtoOBP. Здесь —
только специфичные для WAS настройки. Включение логов на стороне агента
(logs_enabled, logs_pobp_url) описано в
Получение данных логов.
WAS пишет логи в каталог ${WAS_PROFILE_ROOT}/logs/<имя_сервера>/ (для
standalone-профиля — <WAS_INSTALL_ROOT>/profiles/AppSrv01/logs/server1/).
В режиме basic logging это текстовые файлы SystemOut.log и SystemErr.log,
плюс native_stdout.log / native_stderr.log (вывод самой JVM). В режиме
HPEL (High Performance Extensible Logging — включён по умолчанию в образе
websphere-traditional) логи хранятся в бинарном репозитории
(logdata/, tracedata/) — их нельзя читать как обычные файлы; для сбора через
агента переключитесь на basic logging (ENABLE_BASIC_LOGGING=true в образе, или
Logging and Tracing → <сервер> → Change log detail levels / logViewer).
Конфигурация ProtoOBP агента
Если агент запускается в виде службы на хосте
Дополните уже существующий /etc/protoobp-agent/conf.d/ibm_was.d/conf.yaml
(тот же файл, в котором лежит instances:) блоком logs::
logs:
- type: file
path: /opt/IBM/WebSphere/AppServer/profiles/AppSrv01/logs/server1/SystemOut.log
source: ibm_was
service: websphere
log_processing_rules:
- type: multi_line
name: log_start_with_date
pattern: \[\d{1,2}/\d{1,2}/\d{2,4}
- type: file
path: /opt/IBM/WebSphere/AppServer/profiles/AppSrv01/logs/server1/SystemErr.log
source: ibm_was
service: websphere
log_processing_rules:
- type: multi_line
name: log_start_with_date
pattern: \[\d{1,2}/\d{1,2}/\d{2,4}
- type: file
path: /opt/IBM/WebSphere/AppServer/profiles/AppSrv01/logs/server1/native_stderr.log
source: ibm_was
service: websphere
Поправьте пути под свой профиль (PROFILE_NAME, SERVER_NAME). Если включён
HPEL — либо переключитесь на basic logging, либо настройте экспорт HPEL в текст
(logViewer.sh … -outLog …) и укажите этот файл в path:.
Перезапустите агента: systemctl restart protoobp-agent.
Если агент запускается в виде Docker контейнера
Шаг 1 — включите сбор логов в самом агенте через переменные окружения и смонтируйте директорию JSON-логов docker-демона:
services:
protoobp-agent:
environment:
POBP_LOGS_ENABLED: "true"
POBP_LOGS_CONFIG_USE_HTTP: "true"
POBP_LOGS_CONFIG_LOGS_POBP_URL: <protoobp-backend>:<port>
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
# Прямое чтение JSON-лог файлов docker-демона быстрее,
# чем тянуть их через Docker socket API.
- /var/lib/docker/containers:/var/lib/docker/containers:ro
Шаг 2 — добавьте лейбл com.protoobp.ad.logs к контейнеру WAS. При запуске с
ENABLE_BASIC_LOGGING=true образ websphere-traditional транслирует
SystemOut.log / SystemErr.log в stdout/stderr контейнера — агент их
подхватит:
services:
websphere:
labels:
com.protoobp.ad.logs: '[{"source": "ibm_was", "service": "websphere", "log_processing_rules": [{"type": "multi_line", "name": "log_start_with_date", "pattern": "\\[\\d{1,2}/\\d{1,2}/\\d{2,4}"}]}]'
Multi-line
ЗаписиSystemOut.log / SystemErr.log в basic-режиме начинаются с метки
времени в квадратных скобках вида [5/12/26 10:00:00:123 UTC] 0000004a ServletWrappe I …. Правило log_processing_rules с type: multi_line и
якорем \[\d{1,2}/\d{1,2}/\d{2,4} склеивает следующие за такой строкой строки
(Java stack traces, многострочные FFDC-подобные блоки) в одну логическую запись.
Без него каждая строка трейса попадёт в ProtoOBP как отдельная запись.Только нужные контейнеры
Если в агенте не задана переменнаяPOBP_LOGS_CONFIG_CONTAINER_COLLECT_ALL=true,
агент собирает логи только тех контейнеров, на которых есть лейбл
com.protoobp.ad.logs.Проверка
В выводе agent status должен быть раздел Logs Agent со статусом running
и источник ibm_was (service websphere) с ненулевым BytesRead:
docker exec protoobp-agent agent status \
| sed -n '/^==== Logs Agent ====/,/^====/p'