Databricksのコンピュートシステムテーブルによるクラスター使用率の監視

Databricksの様々なメトリクスにクイックにアクセスできるシステムテーブル、これまでにも監査用データや課金データなどにアクセスすることができていました。

https://qiita.com/maroon-db/items/b89d47009948206ac064

https://qiita.com/taka_yayoi/items/abaa48828cefe4f41e62

ここ最近でも様々なメトリクスが追加されています。

そして最近では、コンピュートシステムテーブル`system.compute`が追加されました。こちらのシステムテーブルでは、all-purposeクラスターやjobsクラスターのアクティビティやメトリクスを監視できるようになります。

https://docs.databricks.com/ja/admin/system-tables/compute.html

- `clusters`: コンピュート設定をアカウントに記録します。
- `node_types`: ハードウェア情報を含む、現在使用可能なノード タイプごとに 1 つのレコードが含まれます。
- `node_timeline`: コンピュートの使用状況メトリクスの分単位の記録が含まれます。

`clusters`はクラスターの設定を記録し、`node_types`にはアカウントで利用できるノードタイプの一覧が記録され、`node_timeline`にはクラスターのノードレベルでの使用状況が記録されることになります。個人的には、リソースの利用状況をモニタリングできるので`node_timeline`が嬉しいです。

# `compute`システムテーブルの有効化

早速、[Databricks SDK](https://docs.databricks.com/ja/dev-tools/sdk-python.html)を使って有効化します。

```py
%pip install databricks-sdk --upgrade
dbutils.library.restartPython()
```

```py
from databricks.sdk import WorkspaceClient
w = WorkspaceClient()

for schema in w.system_schemas.list(w.metastores.current().metastore_id):
  print(f"スキーマ名: {schema.schema}, 状態: {schema.state}")
```
```
スキーマ名: storage, 状態: SystemSchemaInfoState.AVAILABLE
スキーマ名: access, 状態: SystemSchemaInfoState.ENABLE_COMPLETED
スキーマ名: billing, 状態: SystemSchemaInfoState.ENABLE_COMPLETED
スキーマ名: compute, 状態: SystemSchemaInfoState.AVAILABLE
スキーマ名: marketplace, 状態: SystemSchemaInfoState.AVAILABLE
スキーマ名: query, 状態: SystemSchemaInfoState.ENABLE_COMPLETED
スキーマ名: lakeflow, 状態: SystemSchemaInfoState.AVAILABLE
スキーマ名: operational_data, 状態: SystemSchemaInfoState.UNAVAILABLE
スキーマ名: lineage, 状態: SystemSchemaInfoState.UNAVAILABLE
スキーマ名: information_schema, 状態: SystemSchemaInfoState.ENABLE_COMPLETED
```

`SystemSchemaInfoState.AVAILABLE`になっているので有効化できます。

```py
w.system_schemas.enable(metastore_id=w.metastores.current().metastore_id, schema_name="compute")
```

有効化されていることを確認します。

```py
from databricks.sdk import WorkspaceClient
w = WorkspaceClient()

for schema in w.system_schemas.list(w.metastores.current().metastore_id):
  print(f"スキーマ名: {schema.schema}, 状態: {schema.state}")
```
```
スキーマ名: storage, 状態: SystemSchemaInfoState.AVAILABLE
スキーマ名: access, 状態: SystemSchemaInfoState.ENABLE_COMPLETED
スキーマ名: billing, 状態: SystemSchemaInfoState.ENABLE_COMPLETED
スキーマ名: compute, 状態: SystemSchemaInfoState.ENABLE_COMPLETED
スキーマ名: marketplace, 状態: SystemSchemaInfoState.AVAILABLE
スキーマ名: query, 状態: SystemSchemaInfoState.ENABLE_COMPLETED
スキーマ名: lakeflow, 状態: SystemSchemaInfoState.AVAILABLE
スキーマ名: operational_data, 状態: SystemSchemaInfoState.UNAVAILABLE
スキーマ名: lineage, 状態: SystemSchemaInfoState.UNAVAILABLE
スキーマ名: information_schema, 状態: SystemSchemaInfoState.ENABLE_COMPLETED
```

`SystemSchemaInfoState.ENABLE_COMPLETED`になっているので有効化されています。カタログエクスプローラでも確認できます。

![Screenshot 2024-08-28 at 18.24.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/bab10c89-871a-1806-f6cb-4496fa3fd696.png)
![Screenshot 2024-08-28 at 18.25.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/5dd7b586-d5b7-7daa-8670-9ac92182a274.png)

# サンプルクエリー

マニュアルにある[クエリー](https://docs.databricks.com/ja/admin/system-tables/compute.html#sample-queries)を実行していきます。

## クラスターレコードを最新の請求レコードと結合する

```sql
%sql
SELECT
  u.record_id,
  c.cluster_id,
  c.owned_by,
  c.change_time,
  u.usage_start_time,
  u.usage_quantity
FROM
  system.billing.usage u
  JOIN system.compute.clusters c
  JOIN (SELECT u.record_id, c.cluster_id, max(c.change_time) change_time
    FROM system.billing.usage u
    JOIN system.compute.clusters c
    WHERE
      u.usage_metadata.cluster_id is not null
      and u.usage_start_time >= '2023-01-01'
      and u.usage_metadata.cluster_id = c.cluster_id
      and date_trunc('HOUR', c.change_time) <= date_trunc('HOUR', u.usage_start_time)
    GROUP BY all) config
WHERE
  u.usage_metadata.cluster_id is not null
  and u.usage_start_time >= '2023-01-01'
  and u.usage_metadata.cluster_id = c.cluster_id
  and u.record_id = config.record_id
  and c.cluster_id = config.cluster_id
  and c.change_time = config.change_time
ORDER BY cluster_id, usage_start_time desc;
```

クラスターごとのDBU消費を確認することができます。
![Screenshot 2024-08-28 at 18.26.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/37550af3-326e-b7e5-b742-4cbb78258beb.png)
![Screenshot 2024-08-28 at 18.28.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7dcf735c-6366-ac3d-2841-99b66dac84c7.png)

## コストをクラスター所有者に帰属させる

```sql
%sql
SELECT
  u.record_id record_id,
  c.cluster_id cluster_id,
  max_by(c.owned_by, c.change_time) owned_by,
  max(c.change_time) change_time,
  any_value(u.usage_start_time) usage_start_time,
  any_value(u.usage_quantity) usage_quantity
FROM
  system.billing.usage u
  JOIN system.compute.clusters c
WHERE
  u.usage_metadata.cluster_id is not null
  and u.usage_start_time >= '2023-01-01'
  and u.usage_metadata.cluster_id = c.cluster_id
  and c.change_time <= u.usage_start_time
GROUP BY 1, 2
ORDER BY cluster_id, usage_start_time desc;
```
![Screenshot 2024-08-28 at 18.29.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/63df5d8a-6e17-0b90-7b7e-1bcd74009bc2.png)

## 平均使用率とピーク使用率が最も高いコンピュート リソースを特定する

オリジナルから若干変更しています。

```sql
%sql
SELECT
        distinct cluster_id,
driver,
avg(cpu_user_percent + cpu_system_percent) as `Avg CPU Utilization`,
max(cpu_user_percent + cpu_system_percent) as `Peak CPU Utilization`,
        avg(cpu_wait_percent) as `Avg CPU Wait`,
        max(cpu_wait_percent) as `Max CPU Wait`,
        avg(mem_used_percent) as `Avg Memory Utilization`,
        max(mem_used_percent) as `Max Memory Utilization`,
avg(network_received_bytes)/(1024^2) as `Avg Network MB Received per Minute`,
avg(network_sent_bytes)/(1024^2) as `Avg Network MB Sent per Minute`
FROM
        system.compute.node_timeline
WHERE
        start_time >= date_add(now(), -100)
GROUP BY
        cluster_id,
        driver
ORDER BY
        3 desc;
```
![Screenshot 2024-08-28 at 18.30.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/4ffd0c7a-e8ea-e651-40fd-9f92afca29f5.png)

## 特定のクラスターの利用状況

シンプルなSQLで簡単に可視化できます。

```sql
SELECT
  *
FROM
  node_timeline
WHERE
  cluster_id = "1118-004519-nu0u899x"
```
![Screenshot 2024-08-28 at 18.38.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0591424a-e7a2-0f6f-3851-028644efd523.png)
![Screenshot 2024-08-28 at 18.39.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/3622eb7a-8130-2634-699e-e3657e8e85d1.png)

さらにクエリーを洗練させることで**起動しているがほとんど使われていないクラスター**や**ヘビーに使用されているクラスター**を特定することもできます。是非ご活用ください

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)