Azureの可用性ゾーンについて異なるサブスクリプション間で同一ゾーンになるゾーン番号を確認する


要約
---------------

あるサブスクリプションから見た各サブスクリプションのあるリージョンのゾーンの対応を返してくれるcheck-zone-peersというAPIが用意されており、そこからlocation単位で確認することができます。

https://learn.microsoft.com/ja-jp/rest/api/resources/subscriptions/check-zone-peers

次の中の人の記事で知りました。勉強になります。

https://qiita.com/YoshiakiOi/items/c5ee761cb009633f762d

次の記事は本APIについても言及されており、図もきれいでわかりやすいです。また[VM内部のデータからどのゾーンに配置されたか判別する裏技](https://medium.com/azure-architects/how-to-check-your-azure-subscriptions-availability-zone-peers-7d84e5220f4e#fc13)も紹介しており面白いです。

https://medium.com/azure-architects/how-to-check-your-azure-subscriptions-availability-zone-peers-7d84e5220f4e


Azure CLIで以下のようにして利用できます（AzureのCloud ShellのBashで使えます）

``` bash
# リソースプロバイダーでAvailabilityZonePeeringを有効化（サブスクリプション単位で行う）
az feature register -n AvailabilityZonePeering --namespace Microsoft.Resources --subscription "サブスクリプションID"

# 登録状況を確認。Registered になるまで待ちます
az feature show -n AvailabilityZonePeering --namespace Microsoft.Resources --subscription "サブスクリプションID"

# サブスクリプションID 各ゾーン番号からみた、サブスクリプションID XとサブスクリプションID Yのゾーン番号を得る
# locationは適宜変更
az rest --method post --url "https://management.azure.com/subscriptions/サブスクリプションID/providers/Microsoft.Resources/checkZonePeers/?api-version=2020-01-01" --body @- << EOF
{
  "location":"japaneast",
  "subscriptionIds":[
    "subscriptions/サブスクリプションID X",
    "subscriptions/サブスクリプションID Y"
  ]
}
EOF
```

このAPIを利用することで別サブスクリプション間でもゾーン的に近い配置をすることができるようになります。低レイテンシに抑えたいようなニーズには使えるかもしれません。

背景
-----------

過去にゾーン番号は論理的な値であり、サブスクリプション毎に異なるということを別途調査して確認していました。

https://qiita.com/fukasawah/items/7acd651425029cd52558

しかし、この計測をしないとわからないのは不便だと思っていました。実際、異なるサブスクリプション間で**物理的に同じゾーン**に配置したいニーズがある場合に一々こんな検証はできないでしょう。

そこで、上記のAPIの存在を知ったので試しました。

### 雑な解説

Azureのデータセンターは同一リージョンでも地理的に離れているデータセンターらで冗長化されています。この1つの単位が可用性ゾーンです。例えば、東日本なら東京と埼玉に合計3つの可用性ゾーンが存在します。

Azureではこれらのゾーンを識別する番号が振られていますが、この値はサブスクリプション毎にランダマイズされているようです。つまり異なるサブスクリプション同士で同じ「ゾーン1」を選んでも物理的には同じゾーンとは限りません。そのため「論理ゾーン（論理可用性ゾーン）」と呼び分けている記事もあります。本記事でも論理ゾーン番号と呼ぶことにします。

では物理的なゾーンを一致させたい場合にどうするかというと、上記のAPIが使えます。これで確認することができます。


試す
------------


https://learn.microsoft.com/ja-jp/rest/api/resources/subscriptions/check-zone-peers

ちょっとドキュメントが不親切ですが、URL中のサブスクリプションから見て、リクエストのサブスクリプションらのゾーンIDを返すという代物になっています。

以下の実行例をみていただくとわかるかもしれません。例えば以下のようになります。

```
# Xから見た各サブスクリプション(X,Y)の論理ゾーン番号を得る（コメントは後付け）
hiroyuki_fukasawa@Azure:~$ $ az rest --method post --url "https://management.azure.com/subscriptions/SUB-X/providers/Microsoft.Resources/checkZonePeers/?api-version=2020-01-01" --body @- << EOF
{
  "location":"eastus",
  "subscriptionIds":[
    "subscriptions/SUB-X",
    "subscriptions/SUB-Y"
  ]
}
EOF
```

その時のレスポンスは以下のようになります。

`availabilityZonePeers[].availabilityZone` はURLのサブスクリプションからみた論理ゾーン番号、`availabilityZonePeers[].peers[].availabilityZone` はサブスクリプションごとに対応した論理ゾーン番号、という感じです。

``` jsonc
{
  "availabilityZonePeers": [
    {
      "availabilityZone": "1", // URLのサブスクリプション(X)のAZ-1と同じ論理ゾーンは...
      "peers": [
        {
          "availabilityZone": "1", // XはZone 1
          "subscriptionId": "SUB-X"
        },
        {
          "availabilityZone": "2", // YはZone 2
          "subscriptionId": "SUB-Y"
        }
      ]
    },
    {
      "availabilityZone": "2",// XのAZ-2と同じ論理ゾーンは...
      "peers": [
        {
          "availabilityZone": "2", // XはZone 2
          "subscriptionId": "SUB-X"
        },
        {
          "availabilityZone": "3", // YはZone 3
          "subscriptionId": "SUB-Y"
        }
      ]
    },
    {
      "availabilityZone": "3",// XのAZ-3と同じ論理ゾーンは...
      "peers": [
        {
          "availabilityZone": "3", // XはZone 3
          "subscriptionId": "SUB-X"
        },
        {
          "availabilityZone": "1", // YはZone 1
          "subscriptionId": "SUB-Y"
        }
      ]
    }
  ],
  "location": "eastus",
  "subscriptionId": "SUB-X"
}
```

<details>
<summary>(参考) 同様にサブスクリプションYからみた結果(クリックして表示)</summary>

```
# Yから見た各サブスクリプションのゾーンの対応
hiroyuki_fukasawa@Azure:~$ az rest --method post --url "https://management.azure.com/subscriptions/SUB-Y/providers/Microsoft.Resources/checkZonePeers/?api-version=2020-01-01" --body @- << EOF
{
  "location":"eastus",
  "subscriptionIds":[
    "subscriptions/SUB-X",
    "subscriptions/SUB-Y"
  ]
}
EOF
```

```jsonc
{
  "availabilityZonePeers": [
    {
      "availabilityZone": "1",
      "peers": [
        {
          "availabilityZone": "3",
          "subscriptionId": "SUB-X"
        },
        {
          "availabilityZone": "1",
          "subscriptionId": "SUB-Y"
        }
      ]
    },
    {
      "availabilityZone": "2",
      "peers": [
        {
          "availabilityZone": "1",
          "subscriptionId": "SUB-X"
        },
        {
          "availabilityZone": "2",
          "subscriptionId": "SUB-Y"
        }
      ]
    },
    {
      "availabilityZone": "3",
      "peers": [
        {
          "availabilityZone": "2",
          "subscriptionId": "SUB-X"
        },
        {
          "availabilityZone": "3",
          "subscriptionId": "SUB-Y"
        }
      ]
    }
  ],
  "location": "eastus",
  "subscriptionId": "SUB-Y"
}
```

</details>


この場合、論理ゾーン番号は以下のように対応しているということとなります。

- サブスクリプションXのZone 1 = サブスクリプションYのZone 2
- サブスクリプションXのZone 2 = サブスクリプションYのZone 3
- サブスクリプションXのZone 3 = サブスクリプションYのZone 1

この対応の関係を図にするとこんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/55872015-259c-da33-9807-4873c1aa7be2.png)

つまり、この状況においては、サブスクリプションXのZone 1 サブスクリプションYのZone 2と通信するのは早くなるはずという事となります。

注意点は論理的なゾーンなので、ゾーンを一致させることができても、そのゾーンはどこかまではわかりません。（例えば絶対に埼玉のデータセンターには置きたくない！ということができません）

実際に計測してみる
----------

上記の結果が本当か試してみたくなるものです。適当なゾーン番号を返しているかもしれませんからね。

[前と同じように](https://qiita.com/fukasawah/items/7acd651425029cd52558#%E6%A4%9C%E8%A8%BC)2つのサブスクリプションを用意し、3ゾーン、合計6台のVMに対して総当たりでpingを50回投げ、最も低いレイテンシだったケースを表にしました。
ゾーン間は物理的に距離があるはずですから、同一ゾーンなら物理的な距離も近くなり、ネットワーク的にも近くなるはず、という考えです。

上がpingを投げる側で左が投げられた側です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/932c8c47-f75f-1681-204e-d320c41b950b.png)

太字は別サブスクリプション内で最も低レイテンシ、緑字がcheck-zone-peersの結果で一致したところ、赤字はレイテンシが最も小さいがcheck-zone-peersの結果に反したところ。（グレーアウトは同サブスクリプション・同ゾーンなので最短になるため除外扱い）

結果としては、XのAZ-1→YのAZ-2、YのAZ-2→XのAZ-1がcheck-zone-peersの通りの結果とはなりませんでした。しかしこれは誤っているわけではなく、レイテンシの差は0.1ミリ以内に収まっており、計測誤差ともいえそうです。もしくはXのAZ-1→YのAZ-3、YのAZ-2→XのAZ-2はネットワーク的にかなり近いのかもしれません。

本当はサンプル数を増やして検証すればよいのですが、東日本はクォータにひっかかったりと面倒になってしまいました（なのでeastusでやってます）。まぁ6個中4個は合っていますから正しい結果を返しているとみて良いでしょう（雑）

まとめ
------

自分のサブスクリプションと物理的に近いゾーンに別サブスクリプションのリソースを配置したいときは、このcheck-zone-peers APIで論理ゾーン番号の対応を確認することで、地理的に近いゾーンにリソースを配置することができます。

サブスクリプションが分かれている状態でそんな需要があるかといえばなかなか怪しいですが、ゾーン跨ぎの通信では性能が劣化するケースがしばしばあります。そのときにつかえる豆知識としては面白いかもしれません。