Мониторинг IBM WebSphere Application Server (WAS) с помощью Proto Observability

Сбор метрик и логов IBM WebSphere Application Server (WAS) traditional через PerfServlet и PMI.

На этой странице:

Сбор метрик 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.earperfservlet, 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 или AllApplySave. Перезапустите сервер приложений.

Через 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.

Конфигурация ProtoOBP агента

Если агент запускается в виде службы на хосте

  1. Создайте файл /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
    
  2. Перезапустите агента: 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 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)
urlibm_was_can_connect и service checkURL PerfServlet’а (http://…/wasPerfTool/servlet/perfservlet)
provideribm_was_jdbc_*Имя JDBC-провайдера (Derby JDBC Provider (XA))
dataSourceibm_was_jdbc_*Имя источника данных (jdbc/built-in-derby-datasource)
web_applicationibm_was_servlet_session_*Имя веб-приложения (PerfServletApp#perfServletApp.war)
thread_poolibm_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 / …_gaugegaugeKiBСуммарный объём памяти JVM (heap)
ibm_was_jvm_used_memory / …_gaugegaugeKiBИспользованная память JVM
ibm_was_jvm_free_memory / …_gaugegaugeKiBСвободная память JVM
ibm_was_jvm_process_cpu_usage / …_gaugegaugepercentИспользование CPU процессом JVM (%)
ibm_was_jvm_up_time / …_gaugegaugesecondВремя работы JVM (сброс = рестарт)

Пулы потоков (Thread Pools)

Группа thread_pools. Несут лейбл thread_pool (WebContainer, Default, ORB.thread.pool, server.startup, …).

Имя метрикиТипЕдиницаОписание
ibm_was_thread_pools_pool_sizegaugethreadСреднее число потоков в пуле
ibm_was_thread_pools_active_countgaugethreadЧисло одновременно активных потоков
ibm_was_thread_pools_active_timegaugemillisecondСреднее время нахождения потока в активном состоянии
ibm_was_thread_pools_percent_usedgaugepercentСредний % использования пула (от сконфигурированного максимума)
ibm_was_thread_pools_percent_maxedgaugepercentСредний % времени, когда заняты ВСЕ потоки пула
ibm_was_thread_pools_create_countgaugethreadСколько всего потоков создано
ibm_was_thread_pools_destroy_countgaugethreadСколько всего потоков уничтожено
ibm_was_thread_pools_declaredthread_hung_countgaugethreadСколько потоков объявлено «зависшими» (hung)
ibm_was_thread_pools_concurrent_hung_thread_countgaugethreadСколько потоков «зависло» в данный момент
ibm_was_thread_pools_cleared_thread_hang_countgaugethreadСколько «зависаний» было снято (поток ожил)

JDBC connection pools

Группа jdbc. Несут лейблы provider, dataSource.

Имя метрикиТипЕдиницаОписание
ibm_was_jdbc_pool_sizegaugeРазмер пула соединений
ibm_was_jdbc_free_pool_sizegaugeconnectionЧисло свободных managed-соединений в пуле
ibm_was_jdbc_managed_connection_countgaugeconnectionВсего managed-соединений (free + shared + unshared)
ibm_was_jdbc_connection_handle_countgaugeconnectionСколько соединений сейчас используется (handles)
ibm_was_jdbc_percent_usedgaugepercent% пула, который сейчас используется
ibm_was_jdbc_percent_maxedgaugepercent% времени, когда заняты ВСЕ соединения пула
ibm_was_jdbc_wait_timegaugemillisecondСреднее время ожидания выдачи соединения
ibm_was_jdbc_use_timegaugemillisecondСреднее время удержания соединения
ibm_was_jdbc_jdbc_timegaugemillisecondСреднее время выполнения в JDBC-драйвере (драйвер + сеть + БД)
ibm_was_jdbc_waiting_thread_countgaugethreadЧисло потоков, ожидающих соединение
ibm_was_jdbc_allocate_countgaugeconnectionВсего выделено managed-соединений с момента создания пула
ibm_was_jdbc_return_countgaugeconnectionВсего возвращено managed-соединений
ibm_was_jdbc_create_countgaugeconnectionВсего создано managed-соединений
ibm_was_jdbc_close_countgaugeconnectionВсего уничтожено managed-соединений
ibm_was_jdbc_fault_countgaugeЧисло «фолтов» в пуле (например, таймаутов)
ibm_was_jdbc_prep_stmt_cache_discard_countgaugeСколько prepared-statement’ов вытеснено LRU-алгоритмом из кэша

Сессии сервлетов (Servlet Session Manager)

Группа servlet_session. Несут лейбл web_application.

Имя метрикиТипЕдиницаОписание
ibm_was_servlet_session_create_countgaugesessionСколько сессий создано
ibm_was_servlet_session_invalidate_countgaugesessionСколько сессий инвалидировано
ibm_was_servlet_session_timeout_invalidation_countgaugesessionСколько сессий инвалидировано по таймауту
ibm_was_servlet_session_live_countgaugesessionСколько сессий сейчас в кэше в памяти
ibm_was_servlet_session_active_countgaugesessionСколько сессий «активны» (обрабатывается запрос с этой сессией)
ibm_was_servlet_session_life_timegaugemillisecondСреднее время жизни сессии
ibm_was_servlet_session_no_room_for_new_session_countgaugeСколько раз отказано в создании сессии (превышен лимит, при AllowOverflow=false)
ibm_was_servlet_session_activate_non_exist_session_countgaugerequestЗапросы к уже несуществующей (протухшей) сессии
ibm_was_servlet_session_affinity_break_countgaugerequestЗапросы к сессии, последний доступ к которой был из другого приложения (failover / кривой plug-in)
ibm_was_servlet_session_cache_discard_countgaugesessionСколько сессий вытеснено из кэша (LRU; только для persistent-сессий)
ibm_was_servlet_session_external_read_sizegaugeРазмер прочитанных данных сессии из persistent-store
ibm_was_servlet_session_external_read_timegaugemillisecondВремя чтения данных сессии из persistent-store
ibm_was_servlet_session_external_write_sizegaugerequestРазмер записанных данных сессии в persistent-store
ibm_was_servlet_session_external_write_timegaugemillisecondВремя записи данных сессии в persistent-store
ibm_was_servlet_session_session_object_sizegaugeРазмер in-memory сессий в байтах (только сериализуемые атрибуты)
ibm_was_servlet_session_time_since_last_activatedgaugemillisecondВремя между предыдущим и текущим access-timestamp сессии

Доступность

Имя метрикиТипОписание
ibm_was_can_connectgauge1 — агент смог получить и распарсить XML с PerfServlet, 0 — нет. Дополнительно публикуется service check ibm_was_can_connect.

Ключевые метрики для дашбордов и алертов

Доступность

  • ibm_was_can_connect == 0 (или service check ibm_was_can_connect в CRITICAL) — PerfServlet недостижим: сервер упал, приложение PerfServletApp не запущено, PMI выключен или сеть до агента не работает.
  • Отсутствие свежих серий по instance — то же самое (агент не получает метрик).

Насыщение пулов потоков

  • ibm_was_thread_pools_percent_maxed per thread_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 стабильно высокие per dataSource — пул на пределе.
  • 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}"}]}]'

Проверка

В выводе agent status должен быть раздел Logs Agent со статусом running и источник ibm_was (service websphere) с ненулевым BytesRead:

docker exec protoobp-agent agent status \
  | sed -n '/^==== Logs Agent ====/,/^====/p'