# 機能設計書 58-JMX

## 概要

本ドキュメントは、Apache Flink の JMX メトリクスレポーターの機能設計書である。flink-metrics-jmx モジュールが提供する JMX（Java Management Extensions）を通じたメトリクスエクスポート機能について、処理内容、設定方法、およびコードの構造を詳細に記載する。

### 本機能の処理概要

**業務上の目的・背景**：JMX は Java 標準の管理・監視インターフェースであり、多くのエンタープライズ監視ツール（JConsole, VisualVM, Nagios, Zabbix等）が JMX をサポートしている。Flink メトリクスを JMX 経由でエクスポートすることで、既存の Java 監視基盤との統合が容易になり、追加のインフラストラクチャなしでメトリクスを監視できる。

**機能の利用シーン**：
- JConsole や VisualVM でローカルにメトリクスを確認する場合
- 既存の JMX 監視ツールと統合する場合
- Java アプリケーションの標準的な監視方法を使用したい場合
- リモート JMX 接続でメトリクスを取得する場合

**主要な処理内容**：
1. JMXReporterFactory による JMXReporter インスタンスの生成
2. MBean としてメトリクスを MBeanServer に登録
3. JMX ドメイン名とオブジェクト名の生成
4. Counter, Gauge, Histogram, Meter 用の MBean インターフェース提供
5. メトリクス削除時の MBean 登録解除

**関連システム・外部連携**：
- Java MBeanServer（プラットフォーム MBeanServer）
- JMX クライアント（JConsole, VisualVM, 監視ツール）
- JMX リモートコネクタ

**権限による制御**：JMX セキュリティ設定に依存

## 関連画面

本機能は画面を持たないバックエンド機能である。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | - |

## 機能種別

監視・可観測性 / メトリクスレポーター

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| port | String | No | JMX RMI ポート（非推奨、JMXServerOptionsを使用） | ポート番号または範囲 |

### 入力データソース

- Flink Configuration（flink-conf.yaml）
- MetricConfig（レポーター設定）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| JMX MBean | ObjectName | JMX ドメイン名と属性を持つ MBean |
| Counter値 | long | getCount() で取得 |
| Gauge値 | Object | getValue() で取得 |
| Histogram統計 | double/long | getMean(), getMax(), getMin(), パーセンタイル等 |
| Meter値 | double/long | getRate(), getCount() で取得 |

### 出力先

Java Platform MBeanServer

## 処理フロー

### 処理シーケンス

```
1. JMXReporterFactory.createMetricReporter(Properties) 呼び出し
   └─ port 設定の読み込み（非推奨警告）
2. JMXReporter コンストラクタで MBeanServer 取得
3. notifyOfAddedMetric() でメトリクス追加
   └─ generateJmxDomain() でドメイン名生成
   └─ generateJmxTable() でオブジェクト名属性生成
   └─ 適切な JmxXxxMBean を生成
   └─ mBeanServer.registerMBean() で登録
4. notifyOfRemovedMetric() でメトリクス削除
   └─ mBeanServer.unregisterMBean() で登録解除
5. close() でリソース解放（特になし）
```

### フローチャート

```mermaid
flowchart TD
    A[開始: createMetricReporter] --> B[JMXReporter生成]
    B --> C[MBeanServer取得]
    C --> D{メトリクス操作}
    D -->|追加| E[notifyOfAddedMetric]
    E --> F[generateJmxDomain]
    F --> G[generateJmxTable]
    G --> H{メトリクス型判定}
    H -->|Counter| I1[JmxCounter生成]
    H -->|Gauge| I2[JmxGauge生成]
    H -->|Histogram| I3[JmxHistogram生成]
    H -->|Meter| I4[JmxMeter生成]
    I1 --> J[registerMBean]
    I2 --> J
    I3 --> J
    I4 --> J
    J --> D
    D -->|削除| K[notifyOfRemovedMetric]
    K --> L[unregisterMBean]
    L --> D
    D -->|終了| M[close]
    M --> N[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-58-01 | ドメインプレフィックス | JMX ドメインは "org.apache.flink." で開始 | 常時 |
| BR-58-02 | 文字変換 | 不正文字を置換（空白→_, 特殊文字→-, 引用符→削除） | JMX名生成時 |
| BR-58-03 | 重複登録 | 同名MBeanが既に存在する場合は警告ログを出力 | registerMBean時 |
| BR-58-04 | 非同期削除 | 削除時に InstanceNotFoundException は無視 | unregisterMBean時 |

### 計算ロジック

特になし（メトリクス値をそのまま MBean 経由で公開）

## データベース操作仕様

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| MalformedObjectNameException | JMX名不正 | ドメインまたは属性が JMX 規則に違反 | 内部エラー（デバッグログ） |
| InstanceAlreadyExistsException | 重複登録 | 同名MBeanが既に存在 | 警告ログを出力 |
| NotCompliantMBeanException | MBean不適合 | MBean インターフェースが規則に違反 | 内部エラー（デバッグログ） |

### リトライ仕様

リトライは行わない。エラー時はログ出力して処理を継続。

## トランザクション仕様

該当なし

## パフォーマンス要件

- MBean の登録/解除は同期化されている（synchronized）
- メトリクス値の取得はロックフリー

## セキュリティ考慮事項

- JMX リモートアクセスには適切な認証・認可設定を推奨
- SSL/TLS によるリモート接続の暗号化を推奨
- 本番環境ではアクセス制御を設定すること

## 備考

- port 設定は非推奨。JMXServerOptions.JMX_SERVER_PORT を使用すること
- Dropwizard metrics の JmxReporter を参考に実装

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: ファクトリ実装を理解する

JMXレポーターファクトリの実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | JMXReporterFactory.java | `flink-metrics/flink-metrics-jmx/src/main/java/org/apache/flink/metrics/jmx/JMXReporterFactory.java` | ファクトリ実装 |

**主要処理フロー**:
- **25行目**: MetricReporterFactory を実装
- **27行目**: ARG_PORT = "port" 定義
- **30-33行目**: createMetricReporter() で JMXReporter を生成

**読解のコツ**: JMXReporterFactory はシンプルなファクトリで、port 設定のみを受け取る。

#### Step 2: レポーター実装を理解する

JMXReporter の実装を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | JMXReporter.java | `flink-metrics/flink-metrics-jmx/src/main/java/org/apache/flink/metrics/jmx/JMXReporter.java` | レポーター実装 |

**主要処理フロー**:
1. **59行目**: JMX_DOMAIN_PREFIX = "org.apache.flink."
2. **68行目**: MBeanServer を保持
3. **71行目**: registeredMetrics マップでメトリクスと ObjectName のマッピングを管理
4. **73-83行目**: コンストラクタで MBeanServer 取得、ポート設定時は警告
5. **106-159行目**: notifyOfAddedMetric() でメトリクスを MBean として登録
   - 125-144行目: メトリクス型に応じた JmxXxx クラス生成
   - 147-148行目: registerMBean() で登録
6. **162-179行目**: notifyOfRemovedMetric() で MBean 登録解除
7. **185-193行目**: generateJmxTable() で ObjectName の属性テーブル生成
8. **195-200行目**: generateJmxDomain() で JMX ドメイン名生成
9. **215-261行目**: replaceInvalidChars() で不正文字を置換

#### Step 3: MBean インターフェースを理解する

各メトリクス型の MBean インターフェースを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | JMXReporter.java（内部クラス） | 同上 | MBean インターフェースと実装クラス |

**MBean インターフェース**:
- **268行目**: MetricMBean - 共通マーカーインターフェース
- **273-275行目**: JmxCounterMBean - getCount()
- **291-293行目**: JmxGaugeMBean - getValue()
- **311-333行目**: JmxHistogramMBean - getCount(), getMean(), getStdDev(), getMax(), getMin(), getMedian(), パーセンタイル
- **400-403行目**: JmxMeterMBean - getRate(), getCount()

### プログラム呼び出し階層図

```
JMXReporterFactory.createMetricReporter(Properties)
    │
    └─ new JMXReporter(portsConfig)
           │
           ├─ ManagementFactory.getPlatformMBeanServer()
           │
           ├─ notifyOfAddedMetric(Metric, name, MetricGroup)
           │      │
           │      ├─ generateJmxDomain(name, group)
           │      │      └─ LogicalScopeProvider.getLogicalScope()
           │      │
           │      ├─ generateJmxTable(variables)
           │      │      └─ replaceInvalidChars(key/value)
           │      │
           │      ├─ new ObjectName(domain, table)
           │      │
           │      ├─ switch(metric.getMetricType())
           │      │      ├─ COUNTER: new JmxCounter(counter)
           │      │      ├─ GAUGE: new JmxGauge(gauge)
           │      │      ├─ HISTOGRAM: new JmxHistogram(histogram)
           │      │      └─ METER: new JmxMeter(meter)
           │      │
           │      └─ mBeanServer.registerMBean(jmxMetric, jmxName)
           │
           ├─ notifyOfRemovedMetric(Metric, name, MetricGroup)
           │      └─ mBeanServer.unregisterMBean(jmxName)
           │
           └─ close() [no-op]
```

### データフロー図

```
[入力]                      [処理]                        [出力]

Metric追加通知 ────────────▶ notifyOfAddedMetric ────────▶ MBean登録
    │                           │
MetricGroup ───────────────▶ generateJmxDomain ──────────▶ "org.apache.flink.xxx.yyy"
    │                           │
getAllVariables() ─────────▶ generateJmxTable ───────────▶ {key=value, ...}
    │                           │
                            ObjectName生成
    │                           │
Counter/Gauge/... ─────────▶ Jmx[Type]生成 ───────────────▶ MBeanServer
                                                            │
JMX Client ─────────────────────────────────────────────────┘
(JConsole, VisualVM, etc.)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| JMXReporter.java | `flink-metrics/flink-metrics-jmx/src/main/java/org/apache/flink/metrics/jmx/JMXReporter.java` | ソース | レポーター実装 |
| JMXReporterFactory.java | `flink-metrics/flink-metrics-jmx/src/main/java/org/apache/flink/metrics/jmx/JMXReporterFactory.java` | ソース | ファクトリ実装 |
| org.apache.flink.metrics.reporter.MetricReporterFactory | `flink-metrics/flink-metrics-jmx/src/main/resources/META-INF/services/` | 設定 | SPIサービス登録 |
