Edge Functions - エッジコンピューティングの実践

15分 で読める | 2025.01.21

公式ドキュメント

Edge Functionsとは

Edge Functionsは、ユーザーに最も近いエッジロケーション(CDNの各拠点)でコードを実行するサーバーレス関数です。従来のサーバーレス(AWS Lambdaなど)と比較して、圧倒的に低いレイテンシーを実現します。

flowchart LR
 subgraph Traditional["従来のサーバーレス"]
 User1["ユーザー<br/>(東京)"] --> Region["リージョン<br/>(バージニア)"]
 Region --> Response1["応答<br/>200ms"]
 end

 subgraph Edge["Edge Functions"]
 User2["ユーザー<br/>(東京)"] --> EdgeLoc["エッジ<br/>(東京)"]
 EdgeLoc --> Response2["応答<br/>20ms"]
 end

主要プラットフォーム

1. Cloudflare Workers

最も成熟したエッジプラットフォームの一つです。

// Cloudflare Worker
export default {
 async fetch(request: Request, env: Env): Promise<Response> {
 const url = new URL(request.url);

 // キャッシュチェック
 const cache = caches.default;
 let response = await cache.match(request);

 if (!response) {
 // オリジンからフェッチ
 response = await fetch(request);

 // キャッシュに保存
 const responseToCache = response.clone();
 responseToCache.headers.set('Cache-Control', 'max-age=3600');
 await cache.put(request, responseToCache);
 }

 return response;
 },
};

2. Vercel Edge Functions

Next.jsと深く統合されたエッジ実行環境です。

// middleware.ts (Next.js)
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
 // 地理情報に基づくルーティング
 const country = request.geo?.country || 'US';

 if (country === 'JP') {
 return NextResponse.rewrite(new URL('/jp', request.url));
 }

 // A/Bテスト
 const bucket = Math.random() < 0.5 ? 'a' : 'b';
 const response = NextResponse.next();
 response.cookies.set('ab-test', bucket);

 return response;
}

export const config = {
 matcher: ['/((?!api|_next/static|favicon.ico).*)'],
};

3. Deno Deploy

Deno ランタイムベースのエッジプラットフォームです。

// main.ts (Deno Deploy)
Deno.serve(async (req: Request) => {
 const url = new URL(req.url);

 if (url.pathname === '/api/data') {
 // KVストアからデータ取得
 const kv = await Deno.openKv();
 const data = await kv.get(['cache', 'data']);

 if (data.value) {
 return Response.json(data.value);
 }

 // データを生成してキャッシュ
 const newData = { timestamp: Date.now(), message: 'Hello from Edge!' };
 await kv.set(['cache', 'data'], newData, { expireIn: 60000 });

 return Response.json(newData);
 }

 return new Response('Not Found', { status: 404 });
});

4. AWS Lambda@Edge / CloudFront Functions

AWSのCDNと統合されたエッジ実行環境です。

// CloudFront Function
function handler(event) {
 const request = event.request;
 const headers = request.headers;

 // デバイス検出
 const userAgent = headers['user-agent']?.value || '';
 const isMobile = /Mobile|Android/i.test(userAgent);

 // モバイル用URLにリダイレクト
 if (isMobile && !request.uri.startsWith('/m/')) {
 return {
 statusCode: 302,
 headers: {
 location: { value: `/m${request.uri}` },
 },
 };
 }

 return request;
}

ユースケース

1. 認証・認可

// JWTトークン検証をエッジで実行
async function verifyToken(request: Request): Promise<Response | null> {
 const authHeader = request.headers.get('Authorization');

 if (!authHeader?.startsWith('Bearer ')) {
 return new Response('Unauthorized', { status: 401 });
 }

 const token = authHeader.slice(7);

 try {
 const payload = await verifyJWT(token, JWT_SECRET);

 // ユーザー情報をヘッダーに追加してオリジンへ転送
 const newRequest = new Request(request, {
 headers: new Headers(request.headers),
 });
 newRequest.headers.set('X-User-ID', payload.sub);

 return null; // 続行
 } catch {
 return new Response('Invalid Token', { status: 401 });
 }
}

2. パーソナライゼーション

// 地理・言語に基づくコンテンツ最適化
export default {
 async fetch(request: Request): Promise<Response> {
 const country = request.cf?.country || 'US';
 const language = request.headers.get('Accept-Language')?.split(',')[0] || 'en';

 // 地域別価格表示
 const prices = {
 US: { currency: 'USD', amount: 9.99 },
 JP: { currency: 'JPY', amount: 980 },
 EU: { currency: 'EUR', amount: 8.99 },
 };

 const price = prices[country] || prices['US'];

 // HTMLをエッジで生成
 const html = `
 <!DOCTYPE html>
 <html lang="${language}">
 <body>
 <h1>Welcome!</h1>
 <p>Price: ${price.currency} ${price.amount}</p>
 </body>
 </html>
 `;

 return new Response(html, {
 headers: { 'Content-Type': 'text/html' },
 });
 },
};

3. APIゲートウェイ

// レート制限・ルーティング
export default {
 async fetch(request: Request, env: Env): Promise<Response> {
 const ip = request.headers.get('CF-Connecting-IP') || 'unknown';

 // レート制限(Cloudflare Durable Objects使用)
 const rateLimiter = env.RATE_LIMITER.get(env.RATE_LIMITER.idFromName(ip));
 const { allowed } = await rateLimiter.fetch(request).then(r => r.json());

 if (!allowed) {
 return new Response('Too Many Requests', { status: 429 });
 }

 // パスベースルーティング
 const url = new URL(request.url);
 const routes = {
 '/api/users': 'https://users-service.internal',
 '/api/products': 'https://products-service.internal',
 '/api/orders': 'https://orders-service.internal',
 };

 for (const [path, origin] of Object.entries(routes)) {
 if (url.pathname.startsWith(path)) {
 return fetch(new URL(url.pathname, origin), request);
 }
 }

 return new Response('Not Found', { status: 404 });
 },
};

4. 画像最適化

// 画像のリサイズ・フォーマット変換
export default {
 async fetch(request: Request): Promise<Response> {
 const url = new URL(request.url);
 const imageUrl = url.searchParams.get('url');
 const width = parseInt(url.searchParams.get('w') || '800');
 const format = url.searchParams.get('f') || 'webp';

 if (!imageUrl) {
 return new Response('Missing image URL', { status: 400 });
 }

 // Cloudflare Image Resizing
 return fetch(imageUrl, {
 cf: {
 image: {
 width,
 format,
 quality: 80,
 },
 },
 });
 },
};

注意: Edge Functionsには実行時間、メモリ、コードサイズ、利用可能なAPIなどの制約があります。上限はサービスとプランで異なるため、デプロイ先の公式ドキュメントを確認してください。

実践メモ: A/Bテスト、認証チェック、リダイレクト、地域判定など軽量な処理がEdge Functionsの最適なユースケースです。

制約と最適化

実行時間制限

プラットフォームCPU時間実時間
Cloudflare Workers10ms〜50ms30秒
Vercel Edge25秒25秒
Deno Deploy50ms無制限
Lambda@Edge5秒30秒

コールドスタート

// コールドスタート最小化のベストプラクティス
// 1. グローバルスコープで初期化を避ける
// Bad
const heavyConfig = loadHeavyConfig(); // 毎回実行される

// Good
let cachedConfig: Config | null = null;
function getConfig(): Config {
 if (!cachedConfig) {
 cachedConfig = loadConfig();
 }
 return cachedConfig;
}

メモリ制限

// ストリーミング処理でメモリを節約
export default {
 async fetch(request: Request): Promise<Response> {
 const response = await fetch('https://api.example.com/large-data');

 // ストリーム変換
 const transformStream = new TransformStream({
 transform(chunk, controller) {
 // チャンクごとに処理
 const processed = processChunk(chunk);
 controller.enqueue(processed);
 },
 });

 return new Response(response.body?.pipeThrough(transformStream), {
 headers: response.headers,
 });
 },
};

プラットフォーム比較

特徴Cloudflare WorkersVercel EdgeDeno Deploy
ランタイムV8 IsolatesV8 IsolatesDeno
グローバル拠点300+100+35+
KVストア◎ Workers KV○ Edge Config◎ Deno KV
データベース◎ D1 (SQLite)○ Postgres○ KV
無料枠100k req/日100k req/月100k req/日

関連記事

まとめ

Edge Functionsは、グローバルに低レイテンシーなアプリケーションを構築するための強力なツールです。

  • 低レイテンシー: ユーザーに最も近い場所で実行
  • グローバル配信: 自動的に世界中に展開
  • コスト効率: 使用量ベースの課金
  • シンプルなデプロイ: git pushで即座に反映

認証、パーソナライゼーション、APIゲートウェイなど、適切なユースケースを選んで活用しましょう。

参考リソース

← 一覧に戻る
PR
PR
PR
PR