9ヶ月ぐらい前?に社内の勉強会っぽいなにかで話そうと思ってたけど結局やらなくてお蔵入りになっていたメモ。
このとき試した Prometheus はだいぶ古いです・・・たぶん 1.5 ぐらいです。今が 2.0 とかなので色々変わっていると思います
メモ
- 監視対象でエージェントを実行してマネージャーが HTTP でメトリクスを取得するいわゆる PULL 型
- エージェントは Exporter と呼ばれる
- ワンバイナリで他に依存もない
- インストールが超楽
- 標準的な Exporter がデフォでめちゃくちゃいろんなメトリクスを取ってくる
- とりあえず収集して、必要に応じでアラートとか可視化とかする、というメンタルで使える
- あらかじめ監視設計を難しく考えなくてもとりあえず始めることができる
- 外形監視や SNMP 監視もできることはできる
- 外形監視や SNMP 監視のための Exporter がある
- その Exporter を Prometheus に監視対象として設定する
- Prometheus から PULL されたときに Exporter が実際の監視をする
- Prometheus ではまともな可視化はできない
- Grahana で可視化が基本
- アラートや可視化には PromQL というクエリ式が使える
- そこそこフレキシブルに書ける
- デフォで 3G ぐらいメモリを使うらしい
- 必要に応じて減らしたり増やしたりする
- https://prometheus.io/docs/operating/storage/#memory-usage
- ダウンサイジングができずデフォでは 15 日で消える
- 期間は増やせるが 1 年とかのデータを保持するのは辛そう
- InfluxDB などの別の時系列データベースにデータを送れる
- ダウンサイジングしたければそっちでやる
参考
- https://prometheus.io/
- Prometheus のサイト
- http://docs.grafana.org/features/datasources/prometheus/
- Grafana の Prometheus プラグイン
- http://qiita.com/sugitak/items/ff8f5ad845283c5915d2
- Prometheus を知ったきっかけ
- http://qiita.com/tukiyo3/items/da379f6e5844c99b65df
- Prometheus を docker で動かして Grafana で表示する例
Prometheus セットアップ
下記のようにバイナリをダウンロードして実行してもいいし、
docker でも簡単に実行できます。
docker run \ -v ~/data/prometheus:/prometheus:rw \ -v ./prometheus.yml:/etc/prometheus/prometheus.yml:ro \ -p 9090:9090 \ prom/prometheus
設定ファイル prometheus.yml
は次のような感じです。
global: scrape_interval: 15s scrape_configs: - job_name: prometheus scrape_interval: 5s static_configs: - targets: [localhost:9090]
デフォルトだと 9090 ポートでリッスンするのでブラウザで下記の URL を開くと画面が閲覧できます。
この画面は Expression browser と呼ばれるもので PromQL というクエリ式でグラフを表示したりできます。
本格的な可視化は Grafana でやるとして Grafana に設定するためのクエリ式を調べるのに使うと良いです。
監視対象 に Node exporter をセットアップ
↑の設定だと Prometheus 自身のメトリクスしか収拾されていないので、他のサーバのメトリクスも収集してみます。
監視するサーバには Node exporter をインストールします。
バイナリをダウンロードして実行します、設定ファイルとかはありません。
./node_exporter
試しに社内のサーバにインストールしたときの手順とかは下記の通り。
# CentOS 7 ... 再起動すると消えるのでちゃんとやるなら systemd のユニットファイルを作る curl -L https://github.com/prometheus/node_exporter/releases/download/v0.14.0-rc.1/node_exporter-0.14.0-rc.1.linux-amd64.tar.gz | tar zxf - cd node_exporter-0.14.0-rc.1.linux-amd64 systemd-run --unit=node_exporter ./node_exporter systemctl status node_exporter # CentOS 6 wget https://github.com/prometheus/node_exporter/releases/download/v0.14.0-rc.1/node_exporter-0.14.0-rc.1.linux-amd64.tar.gz tar zxf node_exporter-0.14.0-rc.1.linux-amd64.tar.gz cd node_exporter-0.14.0-rc.1.linux-amd64 cat <<EOS> /etc/init/node_exporter.conf start on runlevel [2345] stop on runlevel [!2345] chdir $PWD exec ./node_exporter respawn EOS initctl start node_exporter
Node exporter を起動したサーバの http://localhost:9100/metrics
を叩くとメトリクスがだらーっと出ていることがわかります。
これを prometheus.yml
で次のような感じで設定します。
scrape_configs: - job_name: node static_configs: - targets: - vm01 relabel_configs: - source_labels: [__address__] target_label: instance - source_labels: [__address__] replacement: ${0}:9100 target_label: __address__
クエリ
Prometheus の画面でクエリを入力するとグラフが見えます。
instant-vector
メトリクス名をそのまま書くと instant-vector となります。これは時刻がインデックスな配列みたいなものなのです。
コードで表現すると下記のような感じ?
[ "12:00": 100, "12:01": 101, "12:02": 103, "12:03": 104, "12:04": 109, ]
ロードアベレージのような GAUGE 値は instant-vector をそのままグラフに表示できます。
# ロードアベレージ
node_load1
range-vector
node_cpu
とかは COUNTER 値なので、そのまま表示してもあまり意味がありません。
node_cpu[5m]
のように角括弧で時間を指定すると range-vector になります。これは要素が5分の範囲の配列である配列のようなものです。
コードで表現すると下記のような感じ?(実際にはこんな非効率な持ち方はしていない)
[ "12:09": [ "12:04": 10000, "12:05": 10000, "12:06": 10100, "12:07": 10300, "12:08": 10400, "12:09": 10900, ], "12:10": [ "12:05": 10000, "12:06": 10100, "12:07": 10300, "12:08": 10400, "12:09": 10900, "12:10": 11100, ], ]
これはそのままだとグラフにできませんが range-vector を instant-vector に変換する関数を使えばグラフにできます。
例えば rate
は range-vector範囲の最初と最後のポイントから導かれる1秒間の増加分です。なので、下記のようにすると CPU 使用率が求められます。
# CPU 使用率 ... 元が 100ミリ秒単位の CPU カウンタなので秒間の増加値がパーセンテージとして使える rate(node_cpu[5m])
フィルタ
複数の監視対象がある場合、メトリクスのラベルでフィルタできます。
例えば特定のインスタンスのロードアベレージだけ表示してみたり。
node_load1{instance="sv01"}
否定の条件や正規表現も使えます。
node_load1{instance!="sv01"} node_load1{instance=~"vm.*"} node_load1{instance!~"vm.*"}
正規表現は文字列全体にマッチする必要があります(前後に ^
と $
が付く感じ)。また、わりと貧弱で言明とか使えません。
フィルタは監視対象を表す instance
ラベルだけでなく、例えば node_cpu
なら CPU の状態とかごとにラベルがあるので、例えば特定の状態をフィルタしたりできます。
rate(node_cpu{mode!="idle",instance="sv01"}[5m])
集計
CPU 使用率の場合、CPU コアごとにラベル付けされて記録されているため、複数コアだとコアごとに表示されます。
rate(node_cpu{mode!="idle",instance="vm01"}[5m])
集計関数を使えば合計した結果にできます。
sum(rate(node_cpu{mode!="idle",instance="vm01"}[5m]))
SQL での GROUP BY もできます。例えば下記の様にすれば mode ごとに集計できます。
sum(rate(node_cpu{mode!="idle",instance="vm01"}[5m])) by (mode)
こう書いても一緒です。
sum by (mode)(rate(node_cpu{mode!="idle",instance="vm01"}[5m]))
どのラベルで集計するか、ではなく、どのラベルを除いて集計するか、も出来ます。
例えば下記のようにすれば cpu ラベルを除いたラベルで集計されます。
sum(rate(node_cpu{mode!="idle",instance="vm01"}[5m])) without (cpu)
演算子
instant-vector は四則演算もできます。例えば下記のように CPU コア数に対しての CPU 使用率が計算できます。
sum(rate(node_cpu{mode!="idle"}[5m]) * 100) by (instance) / count(node_cpu{mode="system"}) by (instance)
メトリクス名をフィルタに使う
__name__
でメトリクス名をフィルタにできます。この方法を使えば1つのクエリで複数のメトリクスが同時に表示できます。
# ロードアベレージを 1s 5s 15s 全部表示 {__name__=~"node_load.*"} # メモリ(Buffers + Cached + MemFree) {__name__=~"node_memory_(Buffers|Cached|MemFree)"}
Grafana を使う場合はクエリ式を縦に並べればいいだけなのであんまり使うことはないです。
アラート
Prometheus のクエリ式の結果を元にメールとか Slack とかでアラートできます。
例えば下記のようなクエリ式でアラートできます。
ALERT cpu_usage IF sum(rate(node_cpu{mode!="idle"}[2m]) * 100) by (job, instance) / count(node_cpu{mode="system"}) by (job, instance) > 80 FOR 30s LABELS { severity = "warning" } ANNOTATIONS { summary = "[{{ $labels.job }} {{ $labels.instance }}] cpu usage", description = "cpu usage now:{{$value}}", }
Grafana で複数の監視対象をずらーっと表示
Templating と Repeat for を使えば、同じ種類の複数の監視対象のグラフをずらーっと並べたりできます。
Cacti のように検索条件を指定してアドホックに表示とかはできなさそうだけど。
Grafana のダッシュボードのインポートとエクスポート
Grafana はダッシュボードの作成は基本的に WebUI ぽちぽちなのですが、Grafana の API を使えばダッシュボードの定義のインポートやエクスポートがサクッとできます。
Grafana の API は下記のように呼べます。
# /api/org の例 curl \ -H "Authorization: Bearer $GRAFANA_API_KEY" \ -H "Content-type: application/json" \ "http://localhost:3000/api/org"
下記のスクリプトを用意してサクッと呼べるようにします。
#!/bin/bash set -eu api=${1#/} shift exec curl -H "Authorization: Bearer $GRAFANA_API_KEY" -H "Content-type: application/json" http://localhost:3000/$api "$@"
ダッシュボードをエクスポートします。
./grafana-api.sh /api/dashboards/db/servers | jq . > grafana/servers.json
トップレベルのキーに meta
と dashboard
がありますが、必要なのは dashboard
だけです。
{ "meta": { "...snip..." }, "dashboard": { "...snip..." } }
インポートするときは、新規追加なのか上書きなのかで微妙に異なります。
新規追加の場合は .dashboard.id
を null
にする必要があります。
cat grafana/servers.json | jq '. * {dashboard:{id:null}}' | ./grafana-api.sh /api/dashboards/db -X POST -d @-
上書きする場合はさらに .overwrite
を true
にする必要があります(同じ名前のダッシュボードが上書きされます)。
cat grafana/servers.json | jq '. * {dashboard:{id:null},overwrite:true}' | ./grafana-api.sh /api/dashboards/db -X POST -d @-
外形監視
外形監視も Blackbox exporter を使えばできます。
- Prometheus に Blackbox exporter を監視対象として追加
- このとき外形監視したいサーバをパラメータとして設定
- Prometheus から PULL されるときパラメータも渡される
- そのパラメータに基づいて Blackbox exporter が PING や HTTP で監視する
- 結果を Blackbox exporter のメトリクスとして Prometheus に返す
Blackbox exporter 自体は外形監視先の情報を持っていないので、Blackbox exporter の設定は下記のように、どのように監視するか、しかありません。
modules: http_2xx: prober: http timeout: 5s http: valid_status_codes: [] # Defaults to 2xx method: GET headers: Host: example.com ssh_banner: prober: tcp timeout: 5s tcp: query_response:- expect: "^SSH-2.0-" icmp: prober: icmp timeout: 5s
このように設定された Blackbox exporter に対して Prometheus が下記のようにメトリクスを PULL することで実際の監視が実行されます。
SNMP
SNMP での監視も Snmp Exporter で外形監視と同じような仕組みで動きます。
ただ、監視する OID を Snmp Exporter でだばーっと設定する必要があります。例えば次のように。
default: version: 2 auth: community: hoge walk: - 1.3.6.1.4.1.2021.4 - 1.3.6.1.4.1.2021.11 metrics: - { name: snmp_memTotalSwap , oid: 1.3.6.1.4.1.2021.4.3.0 , type: gauge } - { name: snmp_memAvailSwap , oid: 1.3.6.1.4.1.2021.4.4.0 , type: gauge } - { name: snmp_memTotalReal , oid: 1.3.6.1.4.1.2021.4.5.0 , type: gauge } - { name: snmp_memAvailReal , oid: 1.3.6.1.4.1.2021.4.6.0 , type: gauge } - { name: snmp_memTotalFree , oid: 1.3.6.1.4.1.2021.4.11.0 , type: gauge } - { name: snmp_memMinimumSwap , oid: 1.3.6.1.4.1.2021.4.12.0 , type: gauge } - { name: snmp_memBuffer , oid: 1.3.6.1.4.1.2021.4.14.0 , type: gauge } - { name: snmp_memCached , oid: 1.3.6.1.4.1.2021.4.15.0 , type: gauge } - { name: snmp_ssCpuRawUser , oid: 1.3.6.1.4.1.2021.11.50.0 , type: counter } - { name: snmp_ssCpuRawNice , oid: 1.3.6.1.4.1.2021.11.51.0 , type: counter } - { name: snmp_ssCpuRawSystem , oid: 1.3.6.1.4.1.2021.11.52.0 , type: counter } - { name: snmp_ssCpuRawIdle , oid: 1.3.6.1.4.1.2021.11.53.0 , type: counter } - { name: snmp_ssCpuRawWait , oid: 1.3.6.1.4.1.2021.11.54.0 , type: counter } - { name: snmp_ssCpuRawKernel , oid: 1.3.6.1.4.1.2021.11.55.0 , type: counter } - { name: snmp_ssCpuRawInterrupt , oid: 1.3.6.1.4.1.2021.11.56.0 , type: counter } - { name: snmp_ssIORawSent , oid: 1.3.6.1.4.1.2021.11.57.0 , type: counter } - { name: snmp_ssIORawReceived , oid: 1.3.6.1.4.1.2021.11.58.0 , type: counter } - { name: snmp_ssRawInterrupts , oid: 1.3.6.1.4.1.2021.11.59.0 , type: counter } - { name: snmp_ssRawContexts , oid: 1.3.6.1.4.1.2021.11.60.0 , type: counter } - { name: snmp_ssCpuRawSoftIRQ , oid: 1.3.6.1.4.1.2021.11.61.0 , type: counter } - { name: snmp_ssRawSwapIn , oid: 1.3.6.1.4.1.2021.11.62.0 , type: counter } - { name: snmp_ssRawSwapOut , oid: 1.3.6.1.4.1.2021.11.63.0 , type: counter }
こまかいメモ
ここから下はこまかいことのメモ。
ストレージについて
https://prometheus.io/docs/operating/storage/
Memory usage
- インデックスの場合は LevelDB を使用する
- バルクサンプルデータの場合は独自のストレージ?
- 1024 バイトのチャンクごとに整理される
- チャンクは time series ごとにファイルに保存される
- 現在使用されているすべてのチャンクをメモリに保持する
- 最近使用されたチャンクは
storage.local.memory-chunks
までメモリに保持する- デフォルトは
1048576
で増やしたり減らしたりの調整をしても良い
- デフォルトは
- サーバのメモリ使用量は
storage.local.memory-chunks * 1024
よりも遥かに大きくなる- オーバーヘッドがあるので。また、単にサンプルを保存する以外のこともしているので
- どの程度のオーバーヘッドがあるかは使用方法による
- 設定値よりも多くのチャンクをメモリに乗せることもある
- 使用するすべてのチャンクをメモリに乗せる必要があるので
- 少なくとも 3 倍ぐらいのメモリを使用する
- 下記のメトリクスでどれぐらい使われているか見ることができる
prometheus_local_storage_memory_chunks
process_resident_memory_bytes
- 大量の time series を含む PromQL クエリは LevelDB バックエンドインデックスを大量に使用する
- その種のクエリを実行するならインデックスキャッシュサイズを調整する必要がある
Settings for high numbers of time series
- 100,000 を超える time series を扱うならストレージ設定の調整が必要
- 本質的には、各 time series の特定の数のチャンクをメモリの保持する必要がある
storage.local.memory-chunks
のデフォルトは1048576
です300,000
series までは、series ごとに平均 3 のチャンクがある- もっと多くの series を扱うなら
storage.local.memory-chunks
を増やすべき - とりあえず最初は series の 3 倍にしておくと良い
- 設定されているメモリチャンクよりも多くの series がアクティブになった場合・・・
- 設定値よりも多くのチャンクをメモリに読む必要があるのだが・・・
- 設定値を 10% 以上上回ると、設定値が 5% 以下になるまでサンプルの取得を抑止する
- スクラップやルールの評価をスキップすることで
- これはとても良くないことです
- spinning disk に書き込むときは
storage.local.max-chunks-to-persist
の値を上げる- とりあえず最初は
storage.local.memory-chunks
の 50% ぐらいにしておくと良い storage.local.max-chunks-to-persist
はディスクに書き込まれるのを待つチャンクの数- 待機チャンクがこの値を超えると設定値の 95% に下がるまでサンプルの取り込みを調整する
- series が 1M なら
storage.local.memory-chunks
は 3M ぐらい必要 - このうち 2M が永続化可能なので・・・
storage.local.max-chunks-to-persist
を 2M 以上にすると・・・storage.local.memory-chunks
の設定にかかわらず・・・- メモリ内に 3M 以上のチャンクが簡単に生成される
- とりあえず最初は
Helpful metrics
prometheus_local_storage_max_memory_chunks
storage.local.memory-chunks
の設定値
prometheus_local_storage_memory_series
- メモリに保持されているシリーズ数
prometheus_local_storage_memory_chunks
- メモリに保持されているチャンク数
prometheus_local_storage_chunks_to_persist
- ディスクに永続化する必要のあるメモリチャンク数
prometheus_local_storage_persistence_urgency_score
- 緊急度スコア (0...1)
prometheus_local_storage_rushed_mode
- 緊急モードのフラグ (0 or 1)
うーん? 下記のように設定しておけば OK かな。
storage.local.memory-chunks
- 総メトリクス数の 3 倍
- 総メトリクス数ってどうやって取れば良い?
prometheus_local_storage_memory_series
で良い?
storage.local.max-chunks-to-persist
- ↑の半分
Node exporter の調整
デフォだと dm-X みたいな LVM のディスクとか tmpfs とか nfs とかのファイルシステムとか vnat とかのインタフェースの情報まで取ってきてしまうので、除外パターンを調整する。
./node_exporter \ -collector.diskstats.ignored-devices '^(dm-|[sv]d[a-z]|sr|drbd)\d+$' \ -collector.filesystem.ignored-fs-types '^(sys|proc|root|rpc_pipe|tmp|n)fs$' \ -collector.filesystem.ignored-mount-points '^/(sys|proc|dev|run)($|/)' \ -collector.netdev.ignored-devices '^(vnet\d+|p5p\d+|br\d+|br\d+-nic|lo)$'
設定後は下記のようにコマンドでサッと確認する。
curl -s http://127.0.0.1:9100/metrics | grep node_filesystem_avail curl -s http://127.0.0.1:9100/metrics | grep node_disk_bytes_read curl -s http://127.0.0.1:9100/metrics | grep node_network_receive_bytes
PromQL でも下記のように確認する。
count(node_disk_bytes_read) without (instance) count(node_filesystem_avail) without (instance) count(node_network_receive_bytes) without (instance)
メモリ使用量
メモリ使用量は Node exporter の node_memory_*
なメトリクスで詳細に取れるけど、下記でもリアルなメモリ使用量が取れる。
process_resident_memory_bytes process_virtual_memory_bytes
この値は Prometheus でも Node exporter でも取れるっぽい(Prometheus 自身に Node exporter をセットアップしなくてもメモリ使用量は取れる、という意味)。
予測監視
あと何秒でディスクが枯渇するか、のような予測監視を deriv
とか使ってできる。
( node_filesystem_size{instance='sv01'} - node_filesystem_free{instance='sv01'} ) / deriv(node_filesystem_free{instance='sv01'}[3d])
irate と rate
irate
のが細かい変化が見れる、大まかな変化が知りたい時やアラートで FOR しているときは rate
のが良い。
rate
は [5m]
とかの範囲の最初と最後が、irate
は範囲の最後の2点、irate
での [5m]
とかの範囲は「最後の2点」をどこまで遡るかの指定(無限に遡るわけにはいかないので)。
つまり、rate
の [5m]
は 5 分間の平均を意味するので範囲の広さによって明らかにグラフが変わるが、irate
の [5m]
はこの範囲の最後の 2 点という意味なので、範囲を広くしてもグラフは変わらない。ただし、短くしすぎて範囲内に観測点が 1 つしかなくなるとグラフが表示できなくなるので、それなりの広さにしておく必要がある。
アラートで FOR しているときは、閾値を超えた時間がそれだけ続いたらアラートにする、という意味になる。irate
だとグラフが激しく振れるので、FOR が設定されているととアラートされにくくなる。
memory_chunks の監視
下記のように max_memory_chunks
に対する memory_chunks
の割合を監視したりしてみたけど、
たぶんあるだけ使うだろうのであんまりが意味ない(全データがメモリに乗せる前提とかじゃない限り)。
prometheus_local_storage_memory_chunks / prometheus_local_storage_max_memory_chunks * 100 > 70
chunks_to_persist
とか、
prometheus_local_storage_chunks_to_persist / prometheus_local_storage_max_chunks_to_persist * 100 > 70
persistence_urgency_score
とかで監視するのが良いだろう。
prometheus_local_storage_persistence_urgency_score * 100 > 60
InfluxDB にデータを渡す
Prometheus で remote_write
を使えば取得したメトリクスを HTTP で外に投げることができる。この機能を用いて InfluxDB などの他の時系列データベースへデータを送ることができる。
InfluxDB を起動します。
docker run -p 8086:8086 -p 8083:8083 -e INFLUXDB_ADMIN_ENABLED=true \ -v ~/data/influxdb:/var/lib/influxdb:rw influxdb
http://localhost:8083/ で管理画面を開いて、データベースとユーザーを作成します。
DROP DATABASE prometheus; CREATE DATABASE prometheus; CREATE USER prometheus WITH PASSWORD 'password'; GRANT ALL ON prometheus TO prometheus;
長期保存のためにデータを間引くための2つの RP を作成します。
CREATE RETENTION POLICY "tmp" ON prometheus DURATION 1d REPLICATION 1; CREATE RETENTION POLICY "monthly" ON prometheus DURATION 30d REPLICATION 1 DEFAULT;
さらに Continuous Query を作成します。
CREATE CONTINUOUS QUERY monthly ON prometheus BEGIN SELECT mean(value) as value INTO prometheus."monthly".:MEASUREMENT FROM prometheus."tmp"./.*/ GROUP BY time(1h), job, virt, instance END
Prometheus と InfluxDB を繋ぐためのコマンドをインストールします。
docker run -v /usr/local/bin:/go/bin:rw golang \ go get github.com/prometheus/prometheus/documentation/examples/remote_storage/remote_storage_bridge
起動します。
INFLUXDB_PW=password remote_storage_bridge \ -influxdb-url http://influxdb:8086 \ -influxdb.database prometheus \ -influxdb.username prometheus \ -influxdb.retention-policy tmp
Prometheus で下記のように設定します。
remote_write: url: "http://remote_storage_bridge:9201/receive" write_relabel_configs: - source_labels: [__name__] regex: node_load.* action: keep
InfluxDB でクエリを実行すると書き込まれていることがわかります。
SHOW RETENTION POLICIES; SHOW CONTINUOUS QUERIES SHOW MEASUREMENTS; SELECT * FROM tmp.node_load1; SELECT * FROM monthly.node_load1; SELECT * FROM node_load1;
"tmp"
には Prometheus で取得したのと同じ間隔で記録されています。一方、"monthly"
には Continuous Query により1時間毎の平均になった値が記録されます。
Grafana で InfluxDB のデータを見る
次のようなクエリで InfluxDB のデータを取得できます。
SELECT mean(value) FROM tmp.node_load1 WHERE time > now() - 1h GROUP BY time(5m), instance
Grafana に設定するときは time > now() - 1h
を $timeFilter
に、5m
を $interval
に置き換えます。
SELECT mean(value) FROM tmp.node_load1 WHERE $timeFilter GROUP BY time($interval), instance fill(null)
SELECT mean(value) FROM tmp./^node_load/ WHERE time > now() - 1h GROUP BY time(5m) fill(null)
他の Prometheus からデータを取ってくる(Federation)
他の Prometheus サーバからデータを取ってきたりできる。
データを取る元の prometheus.yml
で下記のように設定するとできる。データを取る先(データ元)で特に設定は必要ないっぽい。
scrape_configs: - job_name: federate scrape_interval: 2m honor_labels: true metrics_path: /federate params: match[]: - instance_mode:cpu:rate static_configs: - targets: - other-prometheus:9090
保持期間やスクレイプの時間を変更した Prometheus を別に設けてそいつに Federate することでダウンサイジングしたりできる。