Redis
 Computer >> コンピューター >  >> プログラミング >> Redis

Cloudflare WorkersとRedisで実現するエッジコンピューティング活用術

エッジコンピューティングは、近年もっとも注目されている技術のひとつです。CDNがファイルをユーザーの近くに配置できるようにしたのと同じように、エッジコンピューティングはアプリケーションそのものをユーザーの近くで実行できるようにします。これにより、開発者はグローバルに分散され、高いパフォーマンスを発揮するアプリケーションを構築できるようになります。

Cloudflare Workersとステートレス性の課題

現在この分野をリードしている製品がCloudflare Workersです。コールドスタートのないサーバーレス実行環境を提供し、Cloudflareのグローバルネットワークを活かすことで、アプリケーションのレイテンシを最小限に抑えられます。関数はJavaScript、Rust、C、C++で記述可能です。

しかしAWS Lambdaなどのサーバーレス関数と同様に、Cloudflare Workersはステートレスです。Cloudflareの調査によると、開発者はエッジ関数からデータベースへ接続する方法を強く求めています。残念ながら、ほとんどのデータベースはサーバーレス環境向けに設計されておらず、永続的な接続を必要とします。そこで私たちはRedis上にREST APIを開発し、サーバーレスのエッジ関数からUpstashへ、最もシンプルかつ高速な方法でアクセスできるようにしました。

Cloudflare Workers KVとの比較

Cloudflareには、エッジ関数の状態を保存できる基本的なKey-Valueストアが用意されています。Upstash Redisは以下の点でCloudflare KVを上回ります。

  • 豊富なデータ構造: Cloudflare KVはget/set/deleteといった基本操作のみを提供します。一方Upstashでは、Hash、List、Sorted Set、範囲操作、append、インクリメントなど、Redisのすべてのデータ構造を利用でき、より高度な機能を構築できます。
  • どこからでもアクセス可能: Cloudflare KVはCloudflareエコシステム内からの利用を想定していますが、Upstash RedisはRedisプロトコルとREST APIの両方をサポートするため、どこからでもアクセス・利用できます。エッジからRedisへデータをオフロードし、任意のRedisクライアントで処理することも可能です。
  • 書き込み性能: Cloudflare KVは読み取り中心の用途に最適化されており、書き込みが他のロケーションへレプリケートされるまで最大60秒かかることがあります。Upstashの書き込みレイテンシはミリ秒単位です。

それでは、CloudflareとRedisの組み合わせの威力を示す簡単な例を作成してみましょう。

エッジでのアナリティクス(アクセス解析)

Webアナリティクスは、すべてのサイト運営者にとって共通のニーズです。Google Analyticsは強力ですが、トラフィックデータをGoogleと共有したり、ユーザーのブラウザにCookieを注入したりすることを好まない開発者も多くいます。サイトへのトラフィックはCDN経由で流れるため、エッジレイヤーで簡単に計測できます。ここでは、Cloudflare Workersでユーザートラフィックを追跡するシンプルな例を実装します。Workersでトラフィックをインターセプトし、ユーザーリクエストをUpstash Redisに保存します。さらに、リクエストを分析して指定日の以下の情報を出力する、基本的なスタンドアロンアプリケーションを作成します。

  • ページビュー数
  • ユニークビジター数
  • 訪問者数の多い上位国
  • 最も閲覧されたページ

セットアップ

まだデータベースをお持ちでない場合は、公式ガイドに従って作成してください。データベースページで「REST API」ボタンをクリックし、REST URLをコピーします。Cloudflareアカウントをお持ちならWorkers関数を作成できますし、アカウントがなくてもプレイグラウンドを利用できます。

注意: Upstashデータベースを作成する際は「Global Database」を選択してください。グローバルデータベースは複数リージョンにデータをレプリケートし、エッジ関数からのレイテンシを低減します。

Cloudflare Workersのコード

Cloudflare Workersの関数はrequestをパラメータとして受け取ります。UpstashのREST APIを使って、リクエストをRedis Listに記録します。キーには当日の日付を使用するため、リクエストは日ごとに別々のListに保存されます。

Upstash REST APIにはエンドポイントとトークンが必要です。データベース作成後、コンソールのREST APIボタンをクリックしてエンドポイントとトークンをコピーできます。以下のコードでエンドポイントとトークンを置き換えて、Workers関数を更新してください。

const endpoint = "REPLACE_UPSTASH_REST_ENDPOINT";
const token = "REPLACE_UPSTASH_REST_TOKEN";

async function recordRequest(request) {
  let d = new Date();
  let datestr = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate();
  let data = [["url", request.url], ...request.headers];
  let url = endpoint + "/lpush/" + datestr;
  const init = {
    body: JSON.stringify(data),
    method: "POST",
    headers: {
      Authorization: "Bearer " + token,
    },
  };
  return await fetch(url, init);
}

async function handleRequest(request) {
  recordRequest(request);
  return new Response("My Awesome Website");
}

addEventListener("fetch", (event) => {
  event.respondWith(
    handleRequest(event.request).catch(
      (err) => new Response(err.stack, { status: 500 })
    )
  );
});

アナリティクスツールのコード

次に、日付を引数として受け取り、アナリティクスデータを返すシンプルなコマンドラインアプリケーションを作成します。フォルダを作成してnpm initを実行し、npm install ioredisでRedisクライアントをインストールします。.env.example.envとしてコピーし、Redis URL(ioredis用)を設定します。index.jsを以下のように更新してください。

const Redis = require("ioredis");
require("dotenv").config();
console.log("EDGE analytics with CloudFlare Workers and Upstash Redis.");
let redis = new Redis(process.env.REDIS_URL);
let dateArg = process.argv[2];
let datestr;
if (dateArg) {
  datestr = dateArg;
} else {
  let d = new Date();
  datestr = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate();
}

redis.lrange(datestr, "0", "-1", function (err, result) {
  let pageview = 0;
  let users = new Set();
  let countries = new Map();
  let paths = new Map();
  if (err) {
    console.log("Could not connect to Redis.");
    console.error(err);
  } else {
    console.log(
      "Upstash Redis Connection Successful. Analyzing the access logs..."
    );
    if (!result || result.length === 0) {
      console.log("Could not find any access logs for the date:" + datestr);
    } else {
      for (const elem of result) {
        let entries = JSON.parse(elem);
        for (let entry of entries) {
          if (entry[0] === "accept") {
            if (entry[1].startsWith("text")) pageview++;
          }
          if (entry[0] === "cf-ipcountry") {
            let temp = countries.get(entry[1]);
            if (!temp) {
              temp = 0;
            }
            countries.set(entry[1], temp + 1);
          }
          if (entry[0] === "url") {
            let temp = paths.get(entry[1]);
            if (!temp) {
              temp = 0;
            }
            paths.set(entry[1], temp + 1);
          }
          if (entry[0] === "x-real-ip") {
            users.add(entry[1]);
          }
        }
      }
      countries = new Map([...countries.entries()].sort((a, b) => b[1] - a[1]));
      paths = new Map([...paths.entries()].sort((a, b) => b[1] - a[1]));
      console.log("\nDATE: " + datestr);
      console.log("\nPAGE VIEWS: " + pageview);
      console.log("\nUNIQUE VISITORS: " + users.size);
      logMap("TOP COUNTRIES", countries);
      logMap("TOP PAGES", paths);
    }
  }
});

function logMap(title, data) {
  console.log("\n" + title);
  console.log("----------------");
  console.log(mapEntriesToString(data));
}

function mapEntriesToString(entries) {
  return Array.from(entries, ([k, v]) => `${k} : ${v}\n`).join("");
}

あとはnode index 2021-6-16のように日付を指定して実行するか、単にnode indexと実行すれば今日のデータを照会できます。

Cloudflare WorkersとRedisで実現するエッジコンピューティング活用術

この例はあくまで出発点にすぎません。アナリティクスのニーズに応じて、チャートやテーブルを備えたリッチなWebアプリケーションへ発展させることができます。また、他のRedisデータ構造を活用すれば、さらに強力な分析も実現可能です。

Upstashのエッジロードマップ

REST APIは私たちのエッジ戦略における第一歩です。今後は以下の2つの重要な開発を予定しています。

  • エッジキャッシュ:(アップデート: リリース済み)現在、すべてのRESTリクエストはデータベースのリージョンへ送信されます。エッジキャッシュをサポートすれば、RESTリクエストが世界中のすべてのエッジロケーションでキャッシュされるようになります。これにより、Cloudflare KVのように世界中で低レイテンシを提供できるようになります。
  • グローバルレプリケーテッドデータベース:(アップデート: リリース済み)グローバル(マルチリージョン)レプリケーションにより、データが複数のリージョンへ複製されます。すべてのリクエスト(Redis APIとREST APIの両方)は最寄りのロケーションへ送られるため、整合性への影響を最小限に抑えつつ、グローバルに低レイテンシを実現します。

エッジロードマップについては、専用のブログ記事を執筆する予定です。ぜひTwitterでフォローして、最新情報をお見逃しなく。

  1. Cloudflare WorkersとUpstash Redisで作る、Webサイト独自の待合室(Waiting Room)

    この記事では、Cloudflare WorkersとUpstash Redisを組み合わせて、Webサイト向けの待合室(Waiting Room)ページを実装する方法を解説します。 なぜ待合室が必要なのか? Webサイトへの訪問者数が増えるのは本来喜ばしいことですが、必ずしもそうとは限りません。突発的な大量トラフィックはアプリケーションを容易に圧倒し、最悪の場合、サービス全体が停止してしまうこともあります。待合室は、トラフィック急増時にアクセスを制御し、リソースを保護するための有効なソリューションです。 Cloudflareには公式の「Waiting Room」機能がありますが、残念ながらBu

  2. エッジキャッシングで実現する、世界どこでも5ミリ秒のRedisレイテンシ

    Redisでは、データベースとクライアントが同じリージョン内にあれば、1ミリ秒のレイテンシは容易に実現できます。しかし、クライアントが世界中に分散している場合、レイテンシは100ミリ秒を超えてしまいます。この課題を解決するために開発されたのが「Edge Caching(エッジキャッシング)」です。 エッジキャッシングとは エッジキャッシングでは、CDNと同じようにREST APIのレスポンスが世界各地のエッジロケーションにキャッシュされます。エッジキャッシングを有効にすると、平均5ミリ秒というグローバルレイテンシを実現できます。実際に、10の異なるリージョンに配置したクライアントからレイテンシ