Hashnodeは、数千人のユーザーのフィードデータを構成するためのスケーラブルなイベント駆動アーキテクチャ(EDA)を構築した。同社は、Lambda、Step Functions、EventBridge、Redis Cacheを含むAWS上のサーバーレスサービスを使用した。このソリューションは、Step Functionsの分散マップ機能を活用し、高度な並行処理を可能にしている。
同社は以前、パーソナライズされたユーザーフィードを提供するソリューションを実装していたが、すぐにそのソリューションがページ読み込みの遅さや、ユーザーフィードをその場で構成する際に高コストなクエリを実行するためデータベースが不安定になる潜在的なリスクを抱えていることが判明した。HashnodeのソフトウェアエンジニアであるFlorian Fuchs氏は、フィード計算を最適化するための全体的なアイデアについて説明している。
ページスピードを最適化するためには、ユーザー用のフィードを事前に計算することが最良の選択肢だと判明しました。これは、ユーザーがフィードページにアクセスするたびにフィードを計算する必要がないことを意味します。その代わり、キャッシュからフィードを返し、ページの読み込み時間をより速くすることができます。そのために重要なのが、キャッシュを使うことです。キャッシュが提供する高速アクセスによって、そこから直接フィードを読み込んでユーザーに提示できます。
エンジニアは、フィード計算ロジックをAWS Step Functionsに実装し、2つのワークフローを使用した。最初のワークフローでは、3つのLambda関数を使用して、フィード計算のためにユーザーデータを準備する。Lambda関数はデータベースから関連データを抽出し、AWS ElastiCache(Redis)キャッシュに保存する。2つ目のワークフローは、実際のフィード計算を担当する。ユーザーに対してキャッシュされたメタデータが見つかるかどうかに応じて、フィード計算ロジックは、Redisキャッシュからソースされたメタデータに完全に基づくか、データベースのユーザーメタデータを抽出する必要がある。
新しいアーキテクチャでは、フィードの再計算は、投稿の作成や更新のイベントによってトリガーされ、AWS EventBridgeに公開されるか、EventBridgeスケジューラーの支援を受けて定期的に行われる。
Hashnodeチームは、並列ワークロードのオーケストレーションに役立つStep FunctionsのMapステートを活用した。Mapステートは、処理要件に応じて2つのモードをサポートする。デフォルトのインラインモードは、並行性が制限され、入力としてJSON配列のみを受け付ける。分散モードは大規模な並列ワークロードに適しており、S3に保存されたデータソースの処理をサポートする。分散モードでは、Step Functionsは10,000以上の並列子ワークロードを実行可能だ。
分散MapステートによるStep Functions(出典:AWSドキュメント)
このソリューションでは、分散モードでMapステートを使用する2つのStep Functionsが採用されている。1つはキャッシュされたメタデータを持つユーザー用、もう1つはメタデータが見つからなかったユーザー用だ。開発者の報告によると、今のところ、数千人のユーザーに対するフィードの完全な再計算には、わずか26秒しかかからないという。チームはさらに、古いキャッシュデータが定期的に削除されるよう、定期的なキャッシュ・パージ・ロジックを実装した。