🦎

Vercelのインフラ構成を妄想する

2021/11/12に公開

ども、takiponeです。
最近いじっていて面白いなぁと思っている開発者向けサービス Vercel のインフラ構成を妄想してみた様子をシェアします。

まずはインフラ構成について触れているドキュメントを見てみます。

https://vercel.com/docs/concepts/edge-network/overview

以下の一文に集約されている感じです。

The Vercel Edge Network is a CDN with the ability to execute functions at the edge.

静的ファイルの配信とServerless Function(FaaS)による動的コンテンツをエッジで実行する構成と読めますね。実際に利用しているデータセンターは以下のドキュメントにあります。

https://vercel.com/docs/concepts/edge-network/regions#routing

Cloud providerとしてAWSの16個のリージョンを利用しているとのことです。Region IDはIATAの空港コードに見えますが、同様にIATAコードを利用しているAmazon CloudFrontとは微妙に異なる空港を採用しているのが面白いですね。

試してみた

VercelでNext.jsテンプレートをクローンしたプロジェクトに pages/api/hello.js として以下のコード[1]をServerless Functionとして書いて見比べてみましょう。

const handler = (_, res) => {
  const body = { message : 'Hello' };
  res.statusCode = 200;
  res.json(body);
};
export default handler;

まずは静的ファイルとしてパス / (Next.jsとしては pages/index.js) に curl でアクセスします(ヘッダだけ確認できれば良いので -I オプション)。

$ curl -I https://nextjs-takipone.vercel.app/
HTTP/2 200 
date: Fri, 12 Nov 2021 05:45:18 GMT
content-type: text/html; charset=utf-8
content-length: 4462
x-robots-tag: noindex
x-matched-path: /
content-disposition: inline; filename="index"
cache-control: public, max-age=0, must-revalidate
etag: W/"776d27c4aa97f290e559ffb3d43fe042ca90fdb78ef1c5e0dd13663a266eff49"
access-control-allow-origin: *
accept-ranges: bytes
age: 263571
x-vercel-cache: HIT
server: Vercel
x-vercel-id: hnd1:hnd1::bv5s4-1636695918118-a87f96e054e0
strict-transport-security: max-age=63072000; includeSubDomains; preload
$

VercelのEdge Networkにはキャッシュ機能があるので、 x-vercel-cache ヘッダでその様子が見えますね。また、 x-vercel-id ヘッダのプレフィックスに先程の Region ID があるので、Edge Networkの様子が推測できます。今回は東京からのアクセスなので、最寄りのRegionである hnd1 になっている様子がわかります。ちなみにAWSオレゴンリージョンのEC2から同様に curl を実行すると、 x-vercel-id ヘッダは以下になりました。

x-vercel-id: pdx1:pdx1::lqwsq-1636696296594-3980ac5656f5

自分はポートランドに行ったことがないのでピンと来なかったのですが(笑)、 pdx1 は確かにオレゴン州ポートランドのRegion IDです。

今度はServerless Functionにリクエストを送ってみます。

$ curl -I https://nextjs-takipone.vercel.app/api/hello
HTTP/2 200 
content-type: application/json; charset=utf-8
x-robots-tag: noindex
x-matched-path: /api/hello
cache-control: public, max-age=0, must-revalidate
content-length: 0
date: Fri, 12 Nov 2021 05:46:05 GMT
etag: "13-Pa/MFmOyCaOzvReId5aJY+w0TX8"
x-vercel-cache: MISS
age: 0
server: Vercel
x-vercel-id: hnd1::iad1::mqsmq-1636695964569-8b292bc84b84
strict-transport-security: max-age=63072000; includeSubDomains; preload
$

お、ヘッダの様子が静的ファイルとは違う感じになりました。 x-vercel-cache は何度コマンドを繰り返しても MISS になったので、キャッシュせずに毎回コードを実行するSSR(Server Side Rendering)になっているのがわかります。また、 x-vercel-id ヘッダのプレフィックスのうち、2つ目のRegion IDが hnd1 ではなく iad1 になっていますね。これはドキュメントの下記にあたる挙動です。

the Edge Network will automatically forward incoming requests to the closest location in which your Serverless Function is running (Static Files are always distributed across the whole network, thus not location-specific).

静的ファイルはEdge Network全体に分散配置されるのに対して、Serverless Functionは実行するロケーションが決まっていて、リクエストを受け取った最寄りに転送するとあります。一方で今回試しているVercelのアカウントはHobby Planのため、Serverless Functionの実行は iad1 のみに制限されているため、そこに転送されたわけです。

あとはクライアントに近いEdge Networkに行くとのことだったので、東京とオレゴンそれぞれからPingを送出してみます。

東京から
$ ping -c 3 nextjs-takipone.vercel.app
PING nextjs-takipone.vercel.app (76.76.21.21) 56(84) bytes of data.
64 bytes from 76.76.21.21 (76.76.21.21): icmp_seq=1 ttl=120 time=4.36 ms
64 bytes from 76.76.21.21 (76.76.21.21): icmp_seq=2 ttl=120 time=4.04 ms
64 bytes from 76.76.21.21 (76.76.21.21): icmp_seq=3 ttl=120 time=4.22 ms

--- nextjs-takipone.vercel.app ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 4.042/4.207/4.356/0.128 ms
オレゴンから
$ ping -c 3 nextjs-takipone.vercel.app
PING nextjs-takipone.vercel.app (76.76.21.21) 56(84) bytes of data.
64 bytes from 76.76.21.21 (76.76.21.21): icmp_seq=1 ttl=101 time=6.03 ms
64 bytes from 76.76.21.21 (76.76.21.21): icmp_seq=2 ttl=101 time=5.56 ms
64 bytes from 76.76.21.21 (76.76.21.21): icmp_seq=3 ttl=101 time=5.57 ms

--- nextjs-takipone.vercel.app ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 5.564/5.724/6.037/0.229 ms

どちらも10msに満たない良好なRTTですね。東京とオレゴンはRTTが100msかかってもおかしくない物理的な距離があるので、確かに最寄りのEdge Networkからレスポンスを返していることがわかります。

...と、ここで妙なことに気づきました。東京からとオレゴンからで Pingの送信先IPアドレスが同じ です。これ、普通のCDNではあまり見かけない IPエニーキャスト っぽいと[2]

IPエニーキャスト

ググると案の定、ブログにその旨の記事がありました。

https://vercel.com/blog/new-edge-dev-infrastructure#vercel's-own-anycast-ip-range

しかもVercel所有のグローパルIPレンジ 76.76.21.0/24 を持っていると。確かにWHOISを引いてみると、VercelによるARINのレコードが返ってきます。

whoisの実行結果
$ whois 76.76.21.21

#
# ARIN WHOIS data and services are subject to the Terms of Use
# available at: https://www.arin.net/resources/registry/whois/tou/
#
# If you see inaccuracies in the results, please report at
# https://www.arin.net/resources/registry/whois/inaccuracy_reporting/
#
# Copyright 1997-2021, American Registry for Internet Numbers, Ltd.
#


NetRange:       76.76.21.0 - 76.76.21.255
CIDR:           76.76.21.0/24
NetName:        VERCEL-01
NetHandle:      NET-76-76-21-0-1
Parent:         NET76 (NET-76-0-0-0-0)
NetType:        Direct Allocation
OriginAS:       
Organization:   Vercel, Inc (ZEITI)
RegDate:        2020-05-08
Updated:        2020-06-05
Comment:        -----BEGIN CERTIFICATE-----MIIDmzCCAoOgAwIBAgIUYqxVc6t5udbMz0Ys6xC4VTX4NDgwDQYJKoZIhvcNAQELBQAwXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQ8wDQYDVQQHDAZXYWxudXQxEzARBgNVBAoMClZlcmNlbCBJbmMxGzAZBgkqhkiG9w0BCQEWDG1AdmVyY2VsLmNvbTAeFw0yMDA1MTExMzIxMDJaFw0yMjA1MTExMzIxMDJaMF0xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEPMA0GA1UEBwwGV2FsbnV0MRMwEQYDVQQKDApWZXJjZWwgSW5jMRswGQYJKoZIhvcNAQkBFgxtQHZlcmNlbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGZNRvQYOIYbBJHiZAs3VUPlT9OxU3S+zg5gFgEogAM5sCuQC+jOAfTY/RLgy9RFyfqeqrAtggW7AcSxVbywKaoPUrSeO0leksfVIWnUUpvuZvZJeoArlzrw7CjZ2AZirHkbgZpkpoPDOyR6D9nt5pY1uWiP2CF1vV2XIX7lJEwrzgu1Ki0O4a9UXRCHx818OHEJzF9OJfg5iwGuHmSwAQ0tVfOtvHCKMuFRb6wQzzdcI+4GmKIkfYKSQsTEAndDXcI8nDVEJ3lEt1mFA0x/vrFm5u4fzos9nogPGLaoQ1cUqnwFcoTckM0ic2GAuEUUnhLLr3kC+remuVMGN1HuZ/AgMBAAGjUzBRMB0GA1UdDgQWBBS8RvrS4Dyk7FAMmz+ldKyIPsITGzAfBgNVHSMEGDAWgBS8RvrS4Dyk7FAMmz+ldKyIPsITGzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQC5JPZscR5+q3YMgwLsjCAFY/AbUDJvavT3oy8fyO597Xa9fzBJFXY6qG7b+KYQ8TfEgNGY/AUNU3+h8YG5VyRgaIzC0FANQc2EpxnmBBW+grvLIn+BlKAaFH2LvpG+hc8fUUgGicCKUvKxCyuRZMYxzpnTn4A6PzojbALdVAG1CuicfYvD91yvsBzDimniUehSG7dyWJklwsssT6sHFjqOv/1PLej2NWcE92M1Il27IZwZfOV8urG6yd6FZlGBG+8KZP8IEsMf6OropTRKlikHSvKzsOhAnmE/1J45HDjVFNeco+bZW5iOZiHu2Ov1FMTENrMe0xgjPjI7Ri2rdcU8-----END CERTIFICATE-----
Ref:            https://rdap.arin.net/registry/ip/76.76.21.0


OrgName:        Vercel, Inc
OrgId:          ZEITI
Address:        340 S LEMON AVE #4133
City:           Walnut
StateProv:      CA
PostalCode:     91789
Country:        US
RegDate:        2020-03-26
Updated:        2020-06-05
Comment:        https://vercel.com
Ref:            https://rdap.arin.net/registry/entity/ZEITI


OrgAbuseHandle: ABUSE7926-ARIN
OrgAbuseName:   Abuse 
OrgAbusePhone:  +1-416-535-0123 
OrgAbuseEmail:  abuse@vercel.com
OrgAbuseRef:    https://rdap.arin.net/registry/entity/ABUSE7926-ARIN

OrgTechHandle: MFV2-ARIN
OrgTechName:   Vieira, Matheus Fernandez
OrgTechPhone:  +1-416-535-0123 
OrgTechEmail:  m@vercel.com
OrgTechRef:    https://rdap.arin.net/registry/entity/MFV2-ARIN


#
# ARIN WHOIS data and services are subject to the Terms of Use
# available at: https://www.arin.net/resources/registry/whois/tou/
#
# If you see inaccuracies in the results, please report at
# https://www.arin.net/resources/registry/whois/inaccuracy_reporting/
#
# Copyright 1997-2021, American Registry for Internet Numbers, Ltd.
#

独自ドメインの持ち込みが簡単にできるのは、このあたりの構成がミソだったわけですね。一方でIPエニーキャストは、一般的にはインターネットのルーター同士での経路情報の交換やARINなどの機関とのやりとりなど Internetworking に関する高度な専門知識が必要です。Vercelがそれをどのように実現しているのかを外から見ることはできませんが、似たような仕組みを実現するとしたら、AWS Global AcceleratorでBYOIPすると実現できそうな気がしています(妄想です)。

https://docs.aws.amazon.com/ja_jp/global-accelerator/latest/dg/using-byoip.html

まとめ

Vercelのインフラ構成をドキュメントとコマンドの実行結果から妄想してみました。ドキュメントにあるEdge NetworkがIPエニーキャストを駆使した先進的な仕組みで実現されている様子がわかりました。

脚注
  1. (WEB+DB PRESS Vol.123@takepepeさんの記事の作業跡地です、わかりやすくて楽しく勉強できました ↩︎

  2. Amazon CloudFrontはDNSベースの分散で、FastlyがIPエニーキャストを利用しています。 ↩︎

Discussion