推奨: 「PHP ビデオ チュートリアル 」
# #1. フラッシュセールビジネスはなぜ難しいのですか?
1) QQ や Weibo などの IM システム、誰もが自分のデータを読みます (友達リスト) 、グループリスト、個人情報);
2) Weibo システム、誰もがフォローしている人のデータを読むことができます、1 人が複数の人のデータを読むことができます;
3) フラッシュセールシステムでは、在庫は1部のみであり、全員が集中してデータの読み書きを行います。複数人で1つのデータを読み込みます。 例: Xiaomi 携帯電話では毎週火曜日にフラッシュ セールが開催されます。携帯電話は 10,000 台しかないかもしれませんが、瞬間的なトラフィックは数百または数千万になる可能性があります。
別の例: 12306 枚のチケットを取得します。チケットは限られており、インベントリは 1 つあり、大量の瞬間的なトラフィックがあり、それらはすべて同じインベントリを読み取ります。
読み取りと書き込みの競合、ロックは非常に深刻です。これがフラッシュ セールス ビジネスの難しいところです。では、フラッシュセールビジネスの構造を最適化するにはどうすればよいでしょうか?
2. 最適化の方向最適化には 2 つの方向があります (今日はこれら 2 つの点について説明します):
(1)
リクエストは可能な限りシステムの上流でインターセプトされる必要があります (ロックの競合がデータベースに及ばないようにします)。従来のフラッシュセールシステムが失敗する理由は、リクエストがバックエンドデータ層を圧倒し、データの読み取り/書き込みロックの競合が深刻で、同時実行性が高く応答が遅く、ほとんどすべてのリクエストがタイムアウトになるためです。成功した注文に対する有効なトラフィックは非常に小さいです。 12306を例にとると、実際には電車の切符は2,000枚しかなく、200万人が買いに来たとしても、ほとんどの人がうまく買えず、リクエスト効率は0です。(2) キャッシュ
を最大限に活用し、チケットを瞬時に購入します。これは、読み取り回数を増やしたり減らしたりする典型的なアプリケーション シナリオです。ほとんどのリクエストは列車番号のクエリ、チケットです。クエリ、注文、支払い、これは書き込みリクエストです。実際には、電車の切符は 2,000 枚しかなく、200 万人が買いに来ます。注文に成功するのは最大 2,000 人で、残りの全員が在庫を照会します。書き込み率はわずか 0.1%、読み取り率は 99.9% です。キャッシュの最適化に非常に適しています。さて、「リクエストをできるだけシステム上流で傍受する」方法と「キャッシュする」方法については後ほど、詳細についてお話しましょう。3. フラッシュセールの一般的なアーキテクチャ
一般的なサイトのアーキテクチャは基本的にこんな感じです(欺瞞的なアーキテクチャ図は絶対に描かないでください)
(1) ブラウザ側、最上位層は JS コードを実行します
(2) サーバー側、この層はバックエンド データにアクセスし、HTML ページをブラウザに返します
4. 各レベルの最適化の詳細
最初のレベル、クライアント (ブラウザ層、APP 層) を最適化する方法
質問するという質問、誰もが WeChat のシェイクをプレイして赤い封筒を手に入れたことがあるでしょう?シェイクするたびに、リクエストがバックエンドに送信されますか?チケットを取得するために注文するシーンを振り返ると、「クエリ」ボタンをクリックした後、システムがスタックし、進行状況バーがゆっくりと増加するため、ユーザーとしては無意識にもう一度「クエリ」をクリックしてしまいますよね。クリックし続けて、クリックし続けて、クリックして、クリックしてください。 。 。役に立ちますか?システム負荷が理由もなく増加します。ユーザーが 5 回クリックすると、リクエストの 80% が生成されます。これを修正するにはどうすればよいですか?
(a) 製品レベルでは、ユーザーが「クエリ」または「チケットの購入」をクリックすると、 ボタンがグレー表示になり、ユーザーはリクエストを繰り返し送信できなくなります。 #(b) JS レベルでは、ユーザーは #xx 秒以内にリクエストを 1 つだけ送信するよう制限されています
;APP レベルでは、同様のことが可能です。 WeChat を狂ったように振ると、実際に戻るには x 秒かかります。クライアントがリクエストを開始します。これは、「システムのできるだけ上流でリクエストを傍受する」と呼ばれるものです。上流が多ければ多いほど良いです。ブラウザ層と APP 層がブロックされるため、リクエストの 80% をブロックできます。この方法でブロックできるのは、リクエストの 80% だけです。一般ユーザー (ただし、99% ユーザーは一般ユーザー) グループ 内の
ハイエンド プログラマを止めることはできません。 Firebug がパケットをキャプチャするとすぐに、http がどのようなものかを誰もが知ることができます。JS は、プログラマが for ループを記述して http インターフェイスを呼び出すのを止めることはできません。リクエストのこの部分を処理するにはどうすればよいでしょうか?2 番目の層、サーバー レベルでのリクエストのインターセプト
どうやって迎撃するか? プログラマーが for ループ呼び出しを作成できないようにするにはどうすればよいですか ? 重複排除の根拠はありますか? IP?クッキーID? ...複雑です。この種のビジネスではログインが必要です。uid を使用するだけです。 サーバー レベルでは、 は uid に対してリクエストのカウントと重複排除を実行し、カウントを均一に保存する必要さえなく、サーバーのメモリに直接保存します (このカウントは不正確になります) 、しかしそれが最も単純です)。 uid は 5 秒間に 1 つのリクエストのみを渡すことができ、これにより for ループリクエストの 99% がブロックされる可能性があります。
5s は 1 つのリクエストだけを渡しますが、他のリクエストはどうなりますか?キャッシュ、ページ キャッシュ、同じ uid、アクセス頻度の制限、ページ キャッシュの実行、x 秒以内に server に到着するすべてのリクエストは同じページを返します。列車番号など、同じ項目に関するクエリの場合、ページ キャッシュが実行され、x 秒以内に server に到着したリクエストはすべて同じページを返します。このような電流制限により、 ユーザーが良好なユーザー エクスペリエンスを得ることができる (404 が返されない) だけでなく、システムの堅牢性も確保できます (ページ キャッシュを使用して サーバー上のリクエストをインターセプトします)) 。
ページ キャッシュは、必ずしもすべての サーバー が一貫したページを返すことを保証するものではなく、各サイトのメモリに直接配置することもできます。利点はシンプルであることですが、欠点は http リクエストが異なる サーバー に渡されるため、返されるチケット データが異なる可能性があることです。これが サーバーのリクエスト インターセプトとキャッシュの最適化です。 。
わかりました。このメソッドは、http リクエストを送信するために for ループを作成するプログラマを停止します。一部のハイエンド プログラマ (ハッカー) は 100,000 個のブロイラーを制御し、100,000 個の uid を手にし、同時にリクエストを送信します (考慮されていません)今のところ実名システム) 問題は、Xiaomi が携帯電話を取得するために実名システムを必要としないことです)、どうすればよいですか? uid の現在の制限に従って サーバー を停止できません。
3 番目の層はインターセプトするサービス層です (とにかく、リクエストをデータベースに渡さないでください)
サービス層をインターセプトするにはどうすればよいですか?兄さん、私はサービスレベルにいます。Xiaomi が携帯電話を 10,000 台しか持っていないことははっきりと知っています。電車の切符は 2,000 枚しかないことは知っています。データベースに 100,000 件のリクエストを行う意味は何ですか?そう、リクエストキューです!
書き込みリクエストの場合、リクエストキューを作成し、毎回限られた数の書き込みリクエストのみをデータ層に送信します (注文を出し、そのような書き込みビジネスに対して支払います)
1w の携帯電話、1w の注文リクエストのみを db
に送信 3,000 の電車のチケット、3,000 の注文リクエストのみ db
に送信 すべてが成功すると、別のバッチが配置されます。十分ではないため、キュー内の書き込みリクエストはすべて「売り切れ」を返します。
読み取りリクエストを最適化するにはどうすればよいですか?キャッシュ耐性は、memcached であっても redis であっても、1 台のマシンが 1 秒あたり 10 ワットに耐えることができれば問題ありません。このような電流制限により、非常に少数の書き込みリクエストと非常に少数の読み取りキャッシュ ミス リクエストのみがデータ層に侵入し、リクエストの 99.9% がブロックされます。
もちろん、ビジネス ルールにもいくつかの最適化があります。 12306 が行ったことを思い出してください。タイムシェアリングとセグメント化されたチケット販売。以前は 10 時にチケットを販売していましたが、現在は 8 時、8 時 30 分、9 時にチケットを販売しています。 ...そして 30 分ごとにバッチをリリースします。トラフィックは均等に分散されます。
2 番目に、データ粒度の最適化: チケットを購入しようとすると、残りのチケット クエリ ビジネスには 58 枚、つまり 26 枚のチケットが残っています。本当に気にしますか? 実際、私たちだけ 投票するかしないか心配ですか?トラフィックが多い場合は、「チケット付き」と「チケットなし」の大まかなキャッシュを作成するだけです。
3 番目に、一部のビジネス ロジックの非同期性: 注文ビジネスと支払いビジネスの分離など。私は以前、「ビジネスから切り離された建築設計はすべて不正である」という見解を共有しましたが、建築の最適化もビジネスを対象としていなければなりません。
OK、最後にデータベース層です。
ブラウザは 80% をインターセプトし、サーバーは 99.9% をインターセプトしてページをキャッシュし、サービス層はリクエスト キューを使用して別の書き込みを行いました。およびデータ キャッシュでは、データベース層への各リクエストが制御可能です。基本的にデータベースへの負荷はありません。ゆっくり散策することができ、1 台のマシンで処理できます。繰り返しになりますが、在庫には限りがあり、Xiaomi の生産能力には限界があります。データベースに多くのリクエストを行う意味はありません。
すべてがデータベースに送信され、100 万件の注文が行われ、成功したものは 0 件、リクエスト効率は 0% です。 3k のデータが取得され、すべて成功し、リクエスト効率は 100% でした。
5. 要約
上記の説明は非常に明確であるはずです。要約はありません。フラッシュ セール システムについては、私の考えた 2 つのアーキテクチャ最適化アイデアを繰り返します。個人的な経験。:
(1)システムの上流でリクエストをインターセプトしてみてください (上流ほど良いです);
(2)読み取りを多くし、書き込みを減らす、これがより一般的に使用されます。キャッシュ (キャッシュは読み取り圧力に耐えます);
ブラウザとアプリ: 速度制限
サーバー: UID に応じた速度制限とページ キャッシュ
サービス層 (Web サーバー): 業務に応じてトラフィックを制御する書き込みリクエスト キューを作成し、データ キャッシュを実行
##データ層:中庭そして: ビジネスに基づいて最適化6. Q&A
質問 1. あなたのアーキテクチャによれば、実際、最大の負荷は サーバーにかかっています。実際の有効なリクエストの数が 1,000 万であると仮定すると、リクエストの数を制限する可能性は低いです。つながり、この部分のプレッシャーにどう対処すればよいでしょうか?
回答: 1 秒あたりの同時実行数は 1kw ではない可能性があります。1kw があると仮定すると、解決策は 2 つあります:
(1) サービス層 (Web サーバー) は、マシンを追加することで拡張できます。 1,000 台のマシンがあるだけでは十分ではありません。
(2) マシンが十分でない場合は、リクエストを破棄し、50% を破棄します (50% は直接返され、後で再試行します)。原則は、システムを保護し、すべてのユーザーが失敗しないようにすることです。 。
質問 2. 「100,000 頭のブロイラーを制御し、100,000 個の UID を手にし、同時にリクエストを送信します。」 この問題を解決するにはどうすればよいですか?
回答: 前述の通り、サービス層(Webサーバー)の書き込みリクエストキュー制御
質問3: アクセス頻度を制限するキャッシュは検索にも利用できますか?たとえば、ユーザー A が「携帯電話」を検索し、ユーザー B が「携帯電話」を検索した場合、A の検索によって生成されたキャッシュされたページが最初に使用されますか?
回答: これは可能です。この方法は、短期間での 4kw ユーザー アプリ プッシュ操作アクティビティのプッシュやページ キャッシュの実行など、「動的」操作アクティビティ ページでもよく使用されます。
質問 4: キューの処理が失敗した場合はどうすればよいですか?ブロイラー鶏が列を乱した場合はどうすればよいですか?
回答: 処理が失敗した場合、注文は失敗として返され、ユーザーは再試行するように求められます。キューコストが非常に低いので爆発するのは難しいでしょう。最悪の場合、いくつかのリクエストがキャッシュされた後、後続のリクエストは直接「チケットなし」を返します (キューにはすでに 100 万件のリクエストがあり、すべて待機しているため、これ以上リクエストを受け入れる意味がありません)
質問 5 :サーバーフィルタリングする場合、uid リクエストの数を各サイトのメモリに個別に保存しますか?この場合、複数のサーバー クラスタがロード バランサを介して同じユーザーの応答を異なるサーバーに分散する状況にどのように対処すればよいでしょうか。それとも、負荷分散の前に server フィルタリングを配置する必要がありますか?
回答: メモリに配置できます。この場合、1 つのサーバーが 5 秒間で 1 つのリクエストを制限しているように見えます。グローバル (マシンが 10 台あると仮定して) では、実際には 5 秒間で 10 リクエストが制限されます。
1) 制限を増やします (これが推奨される解決策であり、最も簡単です)
2) nginx レイヤーで 7 レイヤーのバランシングを実行し、uid リクエストが同じマシンに配信されるようにします。可能な限り
質問 6: サービス層 (Web サーバー) がフィルタリングする場合、キューはサービス層 (Web サーバー) の統合キューになりますか?それともサービスを提供するサーバーごとにキューがあるのでしょうか?統合キューの場合、各サーバから投入されたリクエストをキューに入れる前に排他制御を行う必要がありますか?
回答: キューを統合する必要はありません。この場合、各サービスが渡すリクエストの数は少なくなります (チケットの総数/サービスの数)。非常に簡単です。キューの統合は再び複雑になります。
質問 7: フラッシュ セール後に支払いが完了し、支払いなしでプレースホルダーがキャンセルされた後、残りの在庫をタイムリーに管理および更新するにはどうすればよいですか?
回答: データベースには未払いというステータスがあります。たとえば、時間が 45 分を超えると、在庫は再び復元されます (「倉庫に戻る」と呼ばれます)。チケットを入手するきっかけは、フラッシュ セールを開始した後、45 分後にもう一度試してみることです。またチケットになります~
質問 8: 異なるユーザーが同じ製品を閲覧し、異なるキャッシュ インスタンスに表示される在庫がまったく異なります。キャッシュ データの一貫性を保つ方法、またはダーティ リードを許可する方法を教えてください。
回答: 現在のアーキテクチャ設計では、リクエストが異なるサイトに送信され、データが不整合になる可能性があります (ページ キャッシュが異なります)。このビジネス シナリオは許容可能です。ただし、データベース レベルの実データには問題ありません。
質問 9: ビジネスの最適化で「3,000 枚の電車のチケット、3,000 件の注文リクエストのみがデータベースに送信される」と考慮した場合でも、これらの 3,000 件の注文は輻輳を引き起こしませんか?
答え: (1) データベースは 3,000 回の書き込みリクエストに耐えることができます; (2) データは分割できます; (3) 3,000 回に耐えられない場合は、サービス層 (Web サーバー) ストレス テストの状況に基づいて、同時接続の数を制御できます。3k は単なる例です。
質問 10; サーバー またはサービス層 (Web server)バックグラウンド処理が失敗した場合、失敗したリクエストのこのバッチを再実行することを検討する必要がありますか?それともただ捨てるだけですか?
回答: リプレイしないでください。ユーザー クエリの失敗または注文の失敗に戻ります。アーキテクチャ設計原則の 1 つは「フェイル ファスト」です。
質問 11. 12306 のような大規模システムのフラッシュセールについて、同時に多数のフラッシュセールが行われていますが、それらを転用するにはどうすればよいですか?
答え: 垂直分割
質問 12. 別の質問が頭に浮かびます。このプロセスは同期ですか、それとも非同期ですか?同期している場合は、応答が遅いフィードバックがあるはずです。しかし、非同期の場合、応答結果を正しいリクエスタに返すことができるかどうかをどのように制御すればよいでしょうか?
回答: ユーザー レベルは間違いなく同期です (ユーザーの http リクエストは抑制されます)。サービス層 (Web サーバー) は同期または非同期にすることができます。
質問 13. フラッシュ セール グループの質問: どの段階で在庫を削減する必要がありますか?在庫をロックする注文を出した場合、多数の悪意のあるユーザーが支払いなしで在庫をロックする注文を出した場合はどうすればよいでしょうか?
回答: データベース レベルでの書き込みリクエストの量が非常に少ないです。幸いなことに、注文は支払われません。時間が経過するまで待ってから、「位置に戻る」ようにしてください。前述したとおりです。
Tips: 注意すべき点
1. 元のサイトから離れた場所に配置する(フラッシュセール機能のサーバーとモールサーバーは配置しない)フラッシュセールを防ぐために同じサーバーを使用 クラッシュ、モールにアクセスできません...)
2. もっと監視し、監視に注意を払い、監視する人を見つけてください
の重要なポイントフラッシュ セール:
1. 高可用性: デュアルアクティブ
2. 高同時実行性: ロード バランシング、セキュリティ フィルタリング
設計アイデア:
1.静的ページ: cdn (大手メーカーの既製品を使用)、URL の非表示、ページ圧縮、キャッシュ機構
2. 動的ページ: キューイング、非同期、修飾ラッシュ
その他の提案:
1. Baidu の提案: オペコード キャッシュ、cdn 、より大きなサーバー インスタンス
2. Alibaba の提案: クラウド モニタリング、クラウド シールド、ecs、oss、rds、cdn
の使用アイデアcdn:
1. 静的リソース (画像、js、css など) を cdn
2 にアップロードします。欠点: ただし、更新時に cdn の更新が間に合わないことに注意してください。プッシュする必要があります。
現状を認識します。環境、形式:
1. ユーザー: 非常に多数、正常/不良ユーザー (cdn アクセラレーションも気晴らしです。cdn にアクセスするため)
2. 地域: 全国 (1 秒の遅延では不十分です。フラッシュ セールは 1 秒の遅延で終了する可能性があるため、ユーザーが最も近いノードを選択できるようにするには CDN が必要です) )
3. 業務プロセス: フロントでの商品の展示と登録。バックエンド データ アクセスとデータ処理
#フラッシュ セールの前にページを追加して、他の製品の転用と宣伝を行う
## 製品の表示レイヤー アーキテクチャ
ページの 3 つのステータス: 1. 製品表示: カウントダウン ページ 2. 進行中のフラッシュ セール: クリックしてフラッシュ セール ページに入ります3. フラッシュ セール アクティビティは終了しました: アクティビティが終了したことを通知します新しいアイデア: タイムラインの観点から問題を考えてください
表示されているのはフラッシュ セールであると仮定します。進行中、前に進むとカウントダウン、後ろに押すと終わりです。#次の図は、ユーザーの観点から問題を示しています:
コード :
静的リソース。デプロイメント用に oss に保存します。
最初にカウントダウン ページを削除し、すぐにフラッシュ セール ページにコピーします。ここに来てください。
その後、coretab を使用してこのスクリプトを定期的に実行してください。
概要:
カウントダウンからラッシュセールまで: Linux のスケジュールされたタスクを使用し、シェル スクリプトを使用して実行します。
購入ラッシュは終わり、購入ラッシュも終了: PHP を使用して実行します。テーブル ルックアップがなくなると終了します。
ユーザー登録層のアーキテクチャ
コード:
##$.cookie カプセル化
データ アクセス層
コード:
レイヤー 2 からレイヤー 3 までの時間を計算するにはどうすればよいですか? ? レイヤー 2 からレイヤー 3 ネットワーク送信へのデータ送信の DNS 解決などの要因によって引き起こされる遅延の合計はどのくらいですか。これにより、構成する必要があるサーバーの数を評価できます
2 文での要約:
1. 重要なポイントで失敗した場合は、前の層 (ユーザー登録層) に直接戻ります 2重要なポイントを通過し、他のレイヤーに通知します有効性: Microsoft シリアル番号と同様の暗号化と復号化キュー: redis を使用した順序付けされたコレクション上限: 技術フラグ
データ処理層
以上がPHP フラッシュセール機能を実装するためのアイデアを共有するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。