こんにちは。
突然ですが、今私はトリ二ダード・トバゴにいます。
日本の裏側の南米に位置し、日本からは飛行機をNYで乗り継いで、総移動時間22時間の長旅です。
自然が好きなので大型休暇で南米の大自然に触れに来たわけですが、
来る前に「なんか地理的差異を体感できる検証とかしたら楽しそうだな、、、」と思い付いたため、
折角なので認定資格取得の中でしか触れなかったようなサービスを触ってみることにしました!
(観光に来ているので、大した検証はしません!!)
はじめに
今回はパッと思いついた3つを検証してみます。
本記事では①を実施します。
- Global Accelaratorを使って、共通のエンドポイントからAWSで最適化されたALBにルーティングされる挙動を試してみる。ついでにレイテンシーを比較してみる。
- Route53の位置情報ルーティング・地理的近接性ルーティングを利用して、日本と南米から同じドメインにアクセスした際の挙動を見てみる。
- CloudFrontに静的ウェブサイトをホスティングし、エッジロケーションによりアクセスが高速化する様子を見てみる
日本にいても出来るやん、、と思うかもしれませんが、
南米から実際に日本にアクセスした際にどれくらい変わるの??というのを今回は見てみようと思います!
検証
前提事項
-
今回は東京リージョンとブラジルのサンパウロリージョンにパブリックアクセス可能なALB+Lambdaをデプロイしてみます。
-
Lambdaはアクセス元の情報とアクセス先のリージョンを返すだけのシンプルな処理+レイテンシを比較するために少しデータ量を増やして、1MBほどのデータ転送が行われるようにします。
-
環境作成にはCloudFormationを使って両リージョンに全く同じ構成をデプロイします。
-
セキュリティやネットワーク制御はガバガバですが、今回は検証用の一時的なものなので目を瞑ることにします。
作成に使用したCloudFormation
AWSTemplateFormatVersion: "2010-09-09"
Description: "Global Accelarator test"
Parameters:
ProjectName:
Type: String
Default: geolatancy
VpcCidr:
Type: String
Default: 10.0.0.0/16
PublicSubnet1Cidr:
Type: String
Default: 10.0.0.0/24
PublicSubnet2Cidr:
Type: String
Default: 10.0.1.0/24
AlbListenerPort:
Type: Number
Default: 80
AllowedIngressCidr:
Type: String
Default: 0.0.0.0/0
Description: "For demo only. Restrict if needed."
Resources:
# -------------------------
# VPC / Subnets
# -------------------------
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidr
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub "${ProjectName}-vpc"
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub "${ProjectName}-igw"
VPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub "${ProjectName}-public-rt"
PublicRoute:
Type: AWS::EC2::Route
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnet1Cidr
AvailabilityZone: !Select [0, !GetAZs ""]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub "${ProjectName}-public-a"
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnet2Cidr
AvailabilityZone: !Select [1, !GetAZs ""]
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub "${ProjectName}-public-b"
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicRouteTable
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet2
RouteTableId: !Ref PublicRouteTable
# -------------------------
# Security Group for ALB
# -------------------------
AlbSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: !Sub "${ProjectName} ALB SG"
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: !Ref AlbListenerPort
ToPort: !Ref AlbListenerPort
CidrIp: !Ref AllowedIngressCidr
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub "${ProjectName}-alb-sg"
# -------------------------
# Lambda
# -------------------------
LambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${ProjectName}-lambda-role-${AWS::Region}-${AWS::StackName}"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
HelloFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub "${ProjectName}-hello-${AWS::Region}"
Runtime: nodejs20.x
Handler: index.handler
Role: !GetAtt LambdaExecutionRole.Arn
Timeout: 10
MemorySize: 128
Code:
ZipFile: |
exports.handler = async (event) => {
const now = new Date().toISOString();
const ua =
(event && event.headers && (event.headers["user-agent"] || event.headers["User-Agent"])) ||
null;
const payloadBytes = 256 * 1024; // 256KB
const blob = "x".repeat(payloadBytes);
const bodyObj = {
region: process.env.AWS_REGION,
now,
path: event && event.path,
requestId: event && event.requestContext && event.requestContext.requestId,
ua,
payloadBytes,
blob,
};
const body = JSON.stringify(bodyObj);
return {
statusCode: 200,
headers: {
"content-type": "application/json",
"cache-control": "no-store",
},
body,
};
};
# ✅ Allow ALB (ELBv2) to invoke Lambda (create this BEFORE TargetGroup with DependsOn)
AllowAlbInvokeLambda:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref HelloFunction
Principal: elasticloadbalancing.amazonaws.com
# SourceArn is TargetGroup ARN; but TG doesn't exist yet.
# We'll set permission without SourceArn restriction to avoid create-order deadlock.
# This is acceptable for a short-lived lab. If you want to restrict, use custom resource.
# SourceArn: !Ref LambdaTargetGroup
# -------------------------
# ALB + TargetGroup (Lambda)
# -------------------------
Alb:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub "${ProjectName}-alb-${AWS::Region}"
Scheme: internet-facing
Type: application
IpAddressType: ipv4
Subnets:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
SecurityGroups:
- !Ref AlbSecurityGroup
LambdaTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
DependsOn:
- AllowAlbInvokeLambda
Properties:
Name: !Sub "${ProjectName}-tg-${AWS::Region}"
TargetType: lambda
Targets:
- Id: !GetAtt HelloFunction.Arn
HealthCheckEnabled: true
AlbListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref Alb
Port: !Ref AlbListenerPort
Protocol: HTTP
DefaultActions:
- Type: forward
TargetGroupArn: !Ref LambdaTargetGroup
Outputs:
AlbDnsName:
Description: "ALB DNS Name (use as test endpoint)"
Value: !GetAtt Alb.DNSName
AlbArn:
Description: "ALB ARN (use for Global Accelerator stack)"
Value: !Ref Alb
TestUrlHello:
Description: "Test URL"
Value: !Sub "http://${Alb.DNSName}/"
Global Accelaratorを作成する
続いて、Global Accelaratorを作成していきます。
ユーザがGlobal AccelaratorのエンドポイントのDNS名にアクセスすると、AWS側で最適化されたルートでより高速なルーティングを自動で行ってくれるというサービスです。
構築は以下の4ステップで行います。
- 名前/タイプの指定
- リスナーの追加
- エンドポイントグループの追加
- エンドポイントの追加
1.名前/タイプの指定
アクセラレータの名前およびアクセラレータのタイプを指定します。
今回はユーザに最も近いALBに自動でルーティングの振り分けを行ってもらいたいため、標準を選択し、アドレスタイプはIPv4を選択します。
2.リスナーの追加
ポート及びプロトコルを指定します。
今回はHTTPでALBへアクセスするため、ポートは80-80、プロトコルはTCPを選択します。
クライアントアフィニティというのは一定時間同ユーザからのアクセスを同じエンドポイントに振り分ける設定のようです。
今回はなしとします。
3.エンドポイントグループの追加
続いて、エンドポイントグループでアクセラレータからのルーティング先のリージョン及びトラフィックの重みを指定します。
今回は東京(ap-northeast-1)とサンパウロ(sa-east-1)で2つのエンドポイントグループを作成します。
トラフィックダイアルは一旦100:100とし、デフォルトで最適化されたルーティングの様子を見てみます。
4.エンドポイントの作成
続いて、前項で作成したエンドポイントグループにルーティング先のエンドポイントを指定します。
ここでは、前提事項で作成したALBのDNS名を設定します。
クライアントのIPアドレスを保持については、ALBがクライアントのIPアドレスを識別できるようにする設定です。これをオンにするとALBのアクセスログ等に表示させることが出来るようです。する設定のことです。
今回はデフォルトで有効化したままとします。
ここまで出来たら、「エンドポイントを作成」ボタンを押してエンドポイントを作成します。
有効化されてステータスがデプロイ済みとなったら作成完了です。
実際にアクセスしてみる(From 日本)
まずは日本から普通にアクセスしてみます。
(エビデンスは後から撮りなおしたので重み付け後と時間が逆になってマス💦)
日本のALBにアクセス出来ましたね!
続いて、トラフィックダイアルを南米100、日本0にしてみます。
続いて、実際のレイテンシの差も定量的に比較してみます。
以下のスクリプトで、10回アクセス時の中央値と平均値を取ります。
コードを表示する
# Geo-latancy-lab.ps1
# Measure avg and median (p50) for TTFB and TOTAL against multiple endpoints.
# Requires: curl.exe (Windows 10/11)
$Count = 30
$endpoints = @(
"Tokyo ALB,http://xxxxxxx.ap-northeast-1.elb.amazonaws.com/"
"SaoPaulo ALB,http://xxxxxxxxx.sa-east-1.elb.amazonaws.com/"
"Global Accelerator,http://xxxxxxxxx.awsglobalaccelerator.com/"
)
function Get-Median {
param([double[]]$Values)
if (-not $Values -or $Values.Count -eq 0) { return [double]::NaN }
$sorted = $Values | Sort-Object
$n = $sorted.Count
if ($n % 2 -eq 1) {
return [double]$sorted[[int]($n / 2)]
} else {
$a = [double]$sorted[($n / 2) - 1]
$b = [double]$sorted[$n / 2]
return ($a + $b) / 2.0
}
}
foreach ($item in $endpoints) {
$parts = $item.Split(",", 2)
$name = $parts[0].Trim()
$url = $parts[1].Trim()
Write-Host ""
Write-Host "===== $name ====="
Write-Host "URL: $url"
Write-Host "Requests: $Count"
$ttfb = New-Object System.Collections.Generic.List[double]
$total = New-Object System.Collections.Generic.List[double]
for ($i = 1; $i -le $Count; $i++) {
# curl output: "<ttfb> <total>\n"
$result = curl.exe -s -o NUL -w "%{time_starttransfer} %{time_total}`n" $url
if ([string]::IsNullOrWhiteSpace($result)) {
Write-Warning "Empty curl output at attempt ${i}"
continue
}
$vals = $result.Trim() -split "\s+"
if ($vals.Count -lt 2) {
Write-Warning "Unexpected curl output at attempt ${i}: $result"
continue
}
$t1 = 0.0
$t2 = 0.0
if (-not [double]::TryParse($vals[0], [ref]$t1)) {
Write-Warning "Failed to parse TTFB at attempt ${i}: $result"
continue
}
if (-not [double]::TryParse($vals[1], [ref]$t2)) {
Write-Warning "Failed to parse TOTAL at attempt ${i}: $result"
continue
}
$ttfb.Add($t1)
$total.Add($t2)
}
$nOk = $ttfb.Count
if ($nOk -eq 0) {
Write-Host "No successful measurements."
continue
}
$avgTtfb = ($ttfb | Measure-Object -Average).Average
$avgTotal = ($total | Measure-Object -Average).Average
$p50Ttfb = Get-Median -Values ($ttfb.ToArray())
$p50Total = Get-Median -Values ($total.ToArray())
Write-Host ("OK: {0}/{1}" -f $nOk, $Count)
Write-Host ("TTFB : avg={0:N3}s p50={1:N3}s" -f $avgTtfb, $p50Ttfb)
Write-Host ("TOTAL : avg={0:N3}s p50={1:N3}s" -f $avgTotal, $p50Total)
}
結果は以下の通り。
東京のALBに直アクセスしたときが一番早いですね。
(アクセラレータのエンドポイントを介さずに直でアクセスするから??)
アクセラレータとサンパウロへのアクセスを比較すると、圧倒的ンアクセラレータ経由の方が早いので、
東京のALBにルーティングされていることが分かります。
===== Tokyo ALB =====
URL: http://xxxxxxxxxx.ap-northeast-1.elb.amazonaws.com/
Requests: 30
OK: 30/30
TTFB : avg=0.116s p50=0.108s
TOTAL : avg=0.212s p50=0.214s
===== SaoPaulo ALB =====
URL: http://xxxxxxxxxxxxx.sa-east-1.elb.amazonaws.com/
Requests: 30
OK: 30/30
TTFB : avg=0.704s p50=0.690s
TOTAL : avg=2.031s p50=2.000s
===== Global Accelerator =====
URL: http://xxxxxxxxxxxxxxx.awsglobalaccelerator.com/
Requests: 30
OK: 30/30
TTFB : avg=0.158s p50=0.159s
TOTAL : avg=0.257s p50=0.214s
トラフィックダイアルの重みを日本0にしたらどうなるでしょうか。
===== Tokyo ALB =====
URL: http://xxxxxxxxxxxxxxxx.ap-northeast-1.elb.amazonaws.com/
Requests: 30
OK: 30/30
TTFB : avg=0.110s p50=0.105s
TOTAL : avg=0.200s p50=0.181s
===== SaoPaulo ALB =====
URL: http://xxxxxxxxxxxxxx.sa-east-1.elb.amazonaws.com/
Requests: 30
OK: 30/30
TTFB : avg=0.704s p50=0.692s
TOTAL : avg=2.100s p50=2.010s
===== Global Accelerator =====
URL: http://xxxxxxxxxxxx.awsglobalaccelerator.com/
Requests: 30
OK: 30/30
TTFB : avg=0.655s p50=0.644s
TOTAL : avg=1.205s p50=1.187s
アクセラレータ経由のアクセス時の時間が伸びて、サンパウロにアクセスしていることが分かります。
ですが、直接サンパウロのALBにアクセスするよりも断然早いですね。
実際にアクセスしてみる(From トリニダード・トバゴ)
では、実際に南米からも同じ検証をしてみます。
まずは普通にブラウザからアクセラレータのDNS名にアクセスしてみます。
南米のALBに飛ばされました!
レイテンシも見てみます。
PS C:\Takuto-work> powershell -ExecutionPolicy Bypass -File "C:\Takuto-work\Geo-latancy-lab.ps1"
===== Tokyo ALB =====
URL: http://xxxxxxxxxxxx.ap-northeast-1.elb.amazonaws.com/
Requests: 30
OK: 30/30
TTFB : avg=0.566s p50=0.547s
TOTAL : avg=1.888s p50=1.850s
===== SaoPaulo ALB =====
URL: http://xxxxxxxxxxxxxxxx.sa-east-1.elb.amazonaws.com/
Requests: 30
OK: 30/30
TTFB : avg=0.465s p50=0.450s
TOTAL : avg=1.369s p50=1.280s
===== Global Accelerator =====
URL: http://xxxxxxxxxxxxxxxxx.awsglobalaccelerator.com/
Requests: 30
OK: 30/30
TTFB : avg=0.521s p50=0.504s
TOTAL : avg=0.878s p50=0.810s
当然ですが、東京ALBへのアクセスが最も遅いですね
サンパウロのALBに直接アクセスした際の時間のほうがアクセラレータ経由でのアクセスに比べると遅くなっている点は東京と違います。(東京は直でALB叩いた方が早かった)
サンパウロとトリニダード・トバゴで若干距離があるからでしょうか。
重みをサンパウロ0にしてみます。
ブラウザからアクセスすると、当然東京のALBにルーティングされます。
PS C:\Takuto-work> powershell -ExecutionPolicy Bypass -File "C:\Takuto-work\Geo-latancy-lab.ps1"
===== Tokyo ALB =====
URL: http://xxxxxxxxxxxxxxxxx.ap-northeast-1.elb.amazonaws.com/
Requests: 30
OK: 30/30
TTFB : avg=0.624s p50=0.574s
TOTAL : avg=3.618s p50=4.126s
===== SaoPaulo ALB =====
URL: http://xxxxxxxxxxxxxxx.sa-east-1.elb.amazonaws.com/
Requests: 30
OK: 30/30
TTFB : avg=0.472s p50=0.456s
TOTAL : avg=1.529s p50=1.386s
===== Global Accelerator =====
URL: http://xxxxxxxxxxxxxxx.awsglobalaccelerator.com/
Requests: 30
OK: 30/30
TTFB : avg=0.594s p50=0.567s
TOTAL : avg=1.037s p50=0.978s
レイテンシを比較すると、両ALBに直でアクセスするよりも、アクセラレータ経由でサンパウロにアクセスしたほうが早くなっていることが分かります。
Global Accelarator恐るべし、、
まとめ
本記事では、南米(サンパウロ)から日本リージョンを含む AWS 環境へアクセスし、
Global Accelerator がレイテンシ(特に TTFB)に与える影響を実際に検証しました。
東京 ALB / サンパウロ ALB / Global Accelerator を比較し、
AWS グローバルネットワーク経由の通信が、直接ALBにアクセスするよりも安定して低遅延になる傾向を確認しました。
Global Accelerator は、
グローバルユーザー向けにアクセス速度を改善したいケースで有効な選択肢だと肌で実感できました。
なにより、普段触れないサービスについて、こうやって旅先ならではの検証をしてみるのも面白いなと思った検証でした!
おわり











