背景
Second-kill キャンペーンは、大多数の E-commerce の低コストプロモーションとブランドプロモーションです。 プラットフォームにユーザーを誘導できるだけでなく、プラットフォームの可視性も向上することができます。 優れた Second-kill システムは、プラットフォームシステムの安定性と公平性を向上させる、より良いユーザーエクスペリエンスを得る、プラットフォームの評判を高めるなどが可能で、Second-kill アクティビティの価値を高めます。
本ページでは、高並行性 Second-kill システム向けのクラウドデータベース Redis 版キャッシュ設計について説明します。
Second-kill の特徴
Second-kill アクティビティは、希少な商品や特別な商品を定期的、定量的に販売し、多くのコンシューマーを引き付けていますが、注文に成功するのはごく少数のコンシューマーだけです。 したがって、Second-kill アクティビティは、短期間で通常よりも多くの (最大 100 倍) ページアクセスフローと注文リクエストトラフィックが発生します。
Second-kill アクティビティは 3 段階に分けられます。
- Second-kill: ユーザーは常にプロダクト詳細ページを更新し、ページリクエストは瞬間的なピークに達します。
- Second-kill の開始: ユーザーは Second-kill ボタンをクリックし、注文リクエストは瞬間的なピークに達します。
- Second-kill 後: 注文に成功した一部のユーザーは、注文の更新やバックアップ操作の生成を続けます。ほとんどのユーザーは返品の機会を待ちながら商品詳細ページを更新し続けます。
コンシューマーは注文を送信します。一般的なプラクティスは、データベースの行レベルのロックを使用することです。ロックを取得するリクエストのみが在庫照会と注文管理操作を実行します。 しかし、並行性が高い場合、データベースは大きなリクエストを処理できず、サービス全体をブロックさせることが多いため、コンシューマーは、サーバーのダウンタイムと受け止めます。
Second-kill システム
Second-kill システムのフローは非常に大きいですが、実際の有効なフローは非常に限られています。 システムの階層を使用して各段階で事前に無効なトラフィックを検証して阻止することで、データベースに流入する大量の無効なトラフィックを減らせます。
ブラウザーキャッシュと CDN 圧縮防止静的ページトラフィックの使用
Second-kill の前に、ユーザーはプロダクト詳細ページを常に更新するため、大量のページリクエストが発生します。 そのため、Second-kill プロダクト詳細ページを通常の商品詳細ページから分離する必要があります。 Second-kill アイテムの詳細ページの場合、好きなだけ静的にできる要素を処理します。サーバーが第 2 のボタンを動的に判断する必要があることに加えて、他の静的データはブラウザーと CDN にキャッシュされます。 このように、Second-kill 前に、サーバーへのフローによって、フローのごく一部だけがページを更新します。
読み書き分離 Redis キャッシュを使用したトラフィックの阻止
CDN は第 1 レベルのトラフィックの阻止であり、使用する第 2 レベルのトラフィック阻止は読み書き分離をサポートする Redis です。 この段階では、主にデータを読み取り、読み書き分離 Redis は 60 万以上の QPS をサポートします。 要件を完全にサポートします。
まず、データ制御モジュールを介して、Second-kill 製品を事前に読み書き分離 Redis にキャッシュして、Second-kill 開始タグを次のように設定します。
Goodsid_count: 100 // total
"Goodsid_start": 0 // start tag
Goodsid_access: 0 // accept the singular
-
Second-kill が始まる前に、サービスクラスターは goodsid_start を 0 として読み取り、開始せずに直接直接戻ります。
-
データ制御モジュールは goodsid_start を 1 に変更し、Second-kill の開始をマークします。
-
サービスクラスターキャッシュはビットのマーキングを開始し、リクエストを受信し、Redis の goodsid_access、 商品の余剰数量 (goodsid_count-goodsid_access) を記録します。
-
数量を goodsid_count まで受け入れた後、すべてのリクエストをインターセプトし続け、アイテムの残数は 0 になります。
最後の注文では、参加に成功するためのリクエストのごく一部しか受け入れられないことが分かります。 並行性が高い場合は、わずかな量のトラフィックを入れることが可能です。 したがって、数量を受け入れる割合を制御します。
マスター/スレーブ Redis キャッシュを持つ迅速な在庫請求
正常に注文に参加した後、下位レベルのサービスに入り、注文情報と在庫量の確認を開始します。 データベースへの直接アクセスを避けるために、 マスター/スレーブ版 Redis を使用して在庫収集を実行します。マスターおよびスレーブ版の Redis は 10 万 QPS のレベルを提供します。 Redisを使用して在庫照会を最適化し、事前に Second-kill の失敗に対するリクエストをインターセプトすると、システム全体のスループットが大幅に向上します。
データ制御モジュールを介して在庫を Redis に進めます。ハッシュ構造を使用して Redis に各 Second-kill アイテムを示します。
Goodsid ":{
"Total": 100
"Booked": 100
}
バックルの際、サーバーは資格を得るために Redis にリクエストします。これは次の Lua スクリプトによって実装されます。Redis は単一のスレッドモデルであるため、Lua は複数のコマンドのアトミック性を確保します。
Local n = Tomar (argv [1])
If not N or N = 0 then?
Return 0
End
Local valves = redis. call ("hmget", keys [1], "Total", "booked ");
Local Total = Tomar (ARS [1])
Local blocked = Tomar (ARS [2])
If not total or not blocked then?
Return 0
End
If blocked + n <= total then
Redis. Call ("hincrby", keys [1], "booked", n)
Return N;
End
Return 0
スクリプトロードを使用して Redis の Lua スクリプトをプリキャッシュし、 次に evalsha のコールスクリプトを使用すると、Eval の直接呼び出しに比べてネットワーク帯域幅が節約されます。
Redis 125.0.0.1: 6379> script load "Lua code"
"Maid"
Redis 125.0.0.1: 6379> eval glas1 goodsid 1
Second-kill サービスは、Redis がカウント n を返すかどうかを判断することによって、リクエストが成功したかどうかが分かります。
マスター/スレーブ Redis を使用した単純メッセージキュー非同期シングルチェックインの実装
バックルが完了したら、注文にチェックインする必要があります。 商品の数が少ない場合、データベースを直接操作します。 Second-kill が 1 万 だった場合、または 10 万の場合でも、データベースロックの競合は大きなパフォーマンス上のボトルネックをもたらします。 したがって、メッセージキューコンポーネントを使用して、Second-kill サービスが注文情報をメッセージキューに書き込むときに、次の注文の完了を考えてデータベースの直接操作を回避します。
- メッセージキューコンポーネントは、Redis を使って実装することができ、リストは R2 で使用されます。 データ構造の説明は次のとおりです。
Orderlist { [0] = {order content} [1] = {order content} [2] = {order content} ... }
- 注文内容を Redis に書き込むには、次のように記述します。
Lpush orderlist {order content}
- 非同期下位注文モジュールは、Redis から注文情報を取得し、データベースに注文を書き込みます。
Brpop orderlist 0
メッセージキューとして Redis を使用することで、注文チェックインは非同期に処理され、ユーザーの注文完了のスピードを効果的に向上させます。
データ制御モジュール管理 Second-kill データ同期
初めに、Redis は読み書きによって分離されていました。 トラフィック制限を実行し、トラフィックの一部だけを次の注文にします。 注文や返品の失敗などの状況では、さらにトラフィックを増やす必要があります。 したがって、データ制御モジュールは、データベースのデータを定期的に計算し、それをマスター/スレーブ版に同期させる必要があります。 その間、Redis は分離された Redis を読み書きするように同期して、より多くのトラフィックが入ってくることが可能となります。