はじめに #
pyvmomiにはsi.content.PerformanceManager
という機能があります。
これは以下のようなvCenterから取得できるVM/ESXiのperformance情報をpyvmomi経由で取得できるAPIです。
vCenterのチャート情報はdefaultでは1h以上過ぎたデータは容量削減のため値が丸められてしまいます。(1日前であれば5分間隔、1週間前なら30分間隔)
APIで取得して外部に保存しておけばトラブルの切り分け等に役立ちます。
1. PerformanceManagerとは? #
MOBでsi.content.PerformanceManager
と進むと以下のような項目が見えます。
項目 | 説明 |
---|---|
description | 集計方法(average, maximum)の定義が記載 |
historicalInterval | 1day, 1week, 1monthごとのデータ保持数(sampling数)の定義が記載 |
perfCounter | cpu.usage.average ,mem.usage.average のようなperformance情報の定義が記載 |
集計期間(historicalInterval)は変更もできますが、vCenterDBを圧迫していくのでおすすめではないようです。公式doc
2. perfCounterとは? #
pyvmomiでperformance情報を取得する上で重要なのが、perfCounter
です。
perfCounterにはperformance情報の定義が3つの属性に分類されて保存されています。
vCenterの監視(Monitor) → Performance → 詳細のチャートオプションの項目と対応します。
従って欲しいパフォーマンス情報をチャートオプションで確認して、cpu.usage.average
のようにperfCounterの属性を把握しておきましょう。
<group>.<name>.<rollup>
とドットで繋ぐと表記しやすいので以降はこのように記載します。
3. performanceを取得してみる #
1. perfCounterのKeyを特定する
pyvmomiでは、取得するperformance項目をperfCounterのKey
で指定するので、これを特定します。
# 扱いにくいので、performance情報: Keyという形で保存する
counters_dict = {
f"{c.groupInfo.key}.{c.nameInfo.key}.{c.rollupType}": c.key
for c in si.content.perfManager.perfCounter
}
# {'cpu.usage.none': 1,
# 'cpu.usage.average': 2,
# 'cpu.usage.minimum': 3,
# 'cpu.usage.maximum': 4,
# 'cpu.usagemhz.none': 5,
# 'cpu.usagemhz.average': 6,
# performance情報でKeyを検索する
counter_key = counters_dict["cpu.usagemhz.average"]
>>> 6
2. vim.PerformanceManager.QuerySpec
を作成して、データを取得
引数は公式doc参照ください。
とは言っても、引数は複雑なので今回はいくつか例を紹介したいと思います。
query = vim.PerformanceManager.QuerySpec(
maxSample=1,
entity=host,
metricId=[
vim.PerformanceManager.MetricId(
counterId=6,
instance="*"
)
],
intervalId=20
)
res = si.content.perfManager.QueryPerf(querySpec=[query])
4. performance取得例 #
最新のデータを取得する #
intervalId=20
はデータの間隔です。1h以内のデータなら20s, 1day以内のデータなら300s等が選べます。maxSample=1
はデータの取得数です。2にすれば最新の2つが取得できます。
intervalId=21
など、存在しないデータ間隔を選ぶとエラーになります。
とりうる値はこちら
vmodl.fault.InvalidArgument
msg = 'A specified parameter was not correct:
faultCause = <unset>,
faultMessage = (vmodl.LocalizableMessage) [],
invalidProperty = 'querySpec.interval'
print(
"{}.{}.{}".format(
si.content.perfManager.perfCounter[5].groupInfo.key,
si.content.perfManager.perfCounter[5].nameInfo.key,
si.content.perfManager.perfCounter[5].rollupType
)
)
>>> cpu.usagemhz.average
query = vim.PerformanceManager.QuerySpec(
maxSample=1,
entity=host,
metricId=[
vim.PerformanceManager.MetricId(
counterId=5,
instance="*"
)
],
format="normal",
intervalId=20
)
res = si.content.perfManager.QueryPerf(querySpec=[query])
res
# (vim.PerformanceManager.EntityMetricBase) [
# (vim.PerformanceManager.EntityMetric) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# entity = 'vim.HostSystem:host-14',
# sampleInfo = (vim.PerformanceManager.SampleInfo) [
# (vim.PerformanceManager.SampleInfo) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# timestamp = 2024-07-09T09:18:20Z,
# interval = 20
# }
# ],
# value = (vim.PerformanceManager.MetricSeries) [
# (vim.PerformanceManager.IntSeries) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# id = (vim.PerformanceManager.MetricId) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# counterId = 5,
# instance = ''
# },
# value = (long) [
# 2033
# ]
# }
# ]
# }
# ]
時間を指定して取得する #
startTime
とendTime
で範囲を指定できるmaxSample
はこの時間の範囲でなるべく最新のデータを取得する
from datetime import datetime, timedelta
print(
"{}.{}.{}".format(
si.content.perfManager.perfCounter[5].groupInfo.key,
si.content.perfManager.perfCounter[5].nameInfo.key,
si.content.perfManager.perfCounter[5].rollupType
)
)
# cpu.usagemhz.average
query = vim.PerformanceManager.QuerySpec(
maxSample=10,
entity=host,
metricId=[
vim.PerformanceManager.MetricId(
counterId=5,
instance="*"
)
],
intervalId=20,
startTime=datetime.now() - timedelta(minutes=20),
endTime=datetime.now() - timedelta(minutes=10)
)
res = si.content.perfManager.QueryPerf(querySpec=[query])
res
# (vim.PerformanceManager.EntityMetricBase) [
# (vim.PerformanceManager.EntityMetric) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# entity = 'vim.HostSystem:host-14',
# sampleInfo = (vim.PerformanceManager.SampleInfo) [
# (vim.PerformanceManager.SampleInfo) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# timestamp = 2024-07-09T09:28:00Z,
# interval = 20
# },
# (vim.PerformanceManager.SampleInfo) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# timestamp = 2024-07-09T09:28:20Z,
# interval = 20
# },
# (vim.PerformanceManager.SampleInfo) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# timestamp = 2024-07-09T09:28:40Z,
# interval = 20
# },
intervalId=20
のデータは1h以内しか残っていないのに、1日前のqueryで指定するなど、存在しないデータをqueryすると空が返ってくるの注意
query = vim.PerformanceManager.QuerySpec(
# 省略
intervalId=20,
startTime=datetime.now() - timedelta(day=2),
endTime=datetime.now() - timedelta(day=1)
)
si.content.perfManager.QueryPerf(querySpec=[query])
>>>(vim.PerformanceManager.EntityMetricBase) []
instanceが複数ある場合 #
cpu.usage.average
のようにcore毎にperformance情報が取得できるものがある。- この時
instance="*"
としていると、全データが取得できる。
print(
"{}.{}.{}".format(
si.content.perfManager.perfCounter[1].groupInfo.key,
si.content.perfManager.perfCounter[1].nameInfo.key,
si.content.perfManager.perfCounter[1].rollupType
)
)
# >>> cpu.usage.average
query = vim.PerformanceManager.QuerySpec(
maxSample=1,
entity=host,
metricId=[
vim.PerformanceManager.MetricId(
counterId=1,
instance="*"
)
],
format="normal",
intervalId=20
)
res = si.content.perfManager.QueryPerf(querySpec=[query])
res
# (vim.PerformanceManager.IntSeries) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# id = (vim.PerformanceManager.MetricId) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# counterId = 1,
# instance = '4' # cpu4個目のデータ
# },
# value = (long) [
# 234
# ]
# },
# (vim.PerformanceManager.IntSeries) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# id = (vim.PerformanceManager.MetricId) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# counterId = 1,
# instance = '11' # cpu11個目のデータ
# },
# value = (long) [
# 538
# ]
# },
# 省略...
csv形式で取得 #
format="csv"
にするとcsv形式で出力される。データ数が多い場合に有用
print(
"{}.{}.{}".format(
si.content.perfManager.perfCounter[5].groupInfo.key,
si.content.perfManager.perfCounter[5].nameInfo.key,
si.content.perfManager.perfCounter[5].rollupType
)
)
query = vim.PerformanceManager.QuerySpec(
maxSample=10,
entity=host,
metricId=[
vim.PerformanceManager.MetricId(
counterId=5,
instance="*"
)
],
format="csv",
intervalId=20
)
res = si.content.perfManager.QueryPerf(querySpec=[query])
res
# (vim.PerformanceManager.EntityMetricBase) [
# (vim.PerformanceManager.EntityMetricCSV) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# entity = 'vim.HostSystem:host-14',
# sampleInfoCSV = '20,2024-07-09T09:27:00Z,20,2024-07-09T09:27:20Z,20,2024-07-09T09:27:40Z,20,2024-07-09T09:28:00Z,20,2024-07-09T09:28:20Z,20,2024-07-09T09:28:40Z,20,2024-07-09T09:29:00Z,20,2024-07-09T09:29:20Z,20,2024-07-09T09:29:40Z,20,2024-07-09T09:30:00Z',
# value = (vim.PerformanceManager.MetricSeriesCSV) [
# (vim.PerformanceManager.MetricSeriesCSV) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# id = (vim.PerformanceManager.MetricId) {
# dynamicType = <unset>,
# dynamicProperty = (vmodl.DynamicProperty) [],
# counterId = 5,
# instance = ''
# },
# value = '1989,2126,2005,1898,1915,1816,1804,2179,2520,2623'
# }
# ]
# }
# ]