ホームページ >運用・保守 >Linuxの運用と保守 >ウェブサイトシステムのキャッシュ機構の構築と最適化
Web システムの外部ネットワーク環境について説明した後、Web システム自体のパフォーマンスの問題に注意を払い始めます。
当社の Web サイトへのアクセス数が増加すると、多くの課題に直面するようになります。これらの問題を解決するには、マシンを拡張するだけでなく、適切なキャッシュ メカニズムを確立して使用することが重要です。
当初、私たちの Web システム アーキテクチャは次のようになっており、各リンクには 1 台のマシンしかありません。
1. MySQL データベースの内部キャッシュは
MySQL のキャッシュ メカニズムを使用します。MySQL の内部から始めましょう。コンテンツ 最も一般的な InnoDB ストレージ エンジンに基づいています。
1. 適切なインデックスを作成します
最も簡単なのはインデックスを作成することです。テーブル データが比較的大きい場合、インデックスはデータを迅速に取得する役割を果たします。ただし費用がかかるものもございます。まず、ある程度のディスク領域を占有します。その中でも結合インデックスが最も顕著です。使用には注意が必要です。生成されるインデックスはソース データよりも大きくなる場合もあります。次に、インデックス作成後のデータの挿入/更新/削除などの操作では、元のインデックスを更新する必要があるため、時間がかかります。もちろん、実際には、システム全体が選択クエリ操作によって支配されているため、インデックスを使用すると、システムのパフォーマンスを大幅に向上させることができます。
2. データベース接続スレッド プール キャッシュ
すべてのデータベース操作リクエストで接続の作成と破棄が必要な場合、間違いなくデータベースにとって大きなオーバーヘッドになります。このタイプのオーバーヘッドを軽減するために、MySQL で thread_cache_size を構成して、再利用のために予約されているスレッドの数を示すことができます。スレッドが足りない場合は再度作成され、アイドル状態のスレッドが多すぎる場合は破棄されます。
実際には、pconnect (データベースロング接続) を使用する、より根本的なアプローチがあり、一度スレッドが作成されると、それは長期間維持されます。ただし、アクセス量が比較的多く、マシンの数が多い場合、この使用法では接続が再利用されず、最終的に max_connections (最大接続数) が制限されるため、「データベース接続の数が枯渇する」可能性があります。データベースの数に達しました。したがって、長い接続を使用するには、通常、CGI マシンによって「盲目的に」作成される接続の数を制御するために、CGI と MySQL の間に「接続プール」サービスを実装する必要があります。
3. Innodb キャッシュ設定 (innodb_buffer_pool_size)
innodb_buffer_pool_size インデックスやデータの保存に使用されるメモリ キャッシュ領域です。マシンが MySQL 専用の場合、通常は 80 にすることが推奨されます。マシンの物理メモリ。%。テーブル データをフェッチするシナリオでは、ディスク IO を削減できます。一般に、この値を大きくするとキャッシュヒット率が高くなります。
4. サブライブラリ/テーブル/パーティション。
MySQL データベースのテーブルは一般に数百万単位のデータ量に耐えますが、これ以上増加するとパフォーマンスが大幅に低下するため、これを超えるデータ量が予測される場合は、サブシステムなどの運用を推奨します。 -データベース/テーブル/パーティション。最善のアプローチは、最初からサービスをサブデータベースおよびサブテーブルのストレージ モデルに設計し、中期以降の段階でのリスクを根本的に排除することです。ただし、リストベースのクエリなどの一部の利便性が犠牲になり、同時にメンテナンスの複雑さが増加します。しかし、データの量が数千万以上になると、それらすべてに価値があることがわかります。
2. 複数の MySQL データベース サービスをセットアップする
1 台の MySQL マシンは、ハングアップすると Web サービスが利用できなくなるため、実際には高リスクの単一ポイントになります。利用可能。さらに、Web システムへのアクセス数が増加し続けると、ある日、1 台の MySQL サーバーではサポートできないことがわかり、さらに多くの MySQL マシンを使用する必要が生じました。複数の MySQL マシンを導入すると、多くの新たな問題が発生します。
1. スレーブ データベースをバックアップとして使用して、MySQL のマスター/スレーブを確立します。
このアプローチは、純粋に「単一障害点」の問題を解決するためのものです。マスター データベースに障害が発生した場合、スレーブデータベースに切り替えます。ただし、スレーブ ライブラリは実際にはアイドル状態であるため、このアプローチは実際には少しリソースの無駄になります。
#2. MySQL は読み取りと書き込み、つまりメイン データベースへの書き込みとスレーブ データベースからの読み取りを分離します。
2 つのデータベースは読み取りと書き込みを分離しており、メイン データベースはクラスの書き込みを担当し、スレーブ データベースは読み取り操作を担当します。また、メインデータベースに障害が発生した場合でも、読み取り操作には影響を与えず、同時にすべての読み取りと書き込みを一時的にスレーブデータベースに切り替えることができます(トラフィックが大きすぎる可能性があるため、トラフィックに注意する必要があります)スレーブ データベースはダウンします)。
#3. プライマリ バックアップとセカンダリ バックアップ。
2 つの MySQL サーバーは、お互いのスレーブ データベースであると同時にマスター データベースでもあります。このソリューションは、トラフィックのプレッシャーを回避するだけでなく、「単一障害点」の問題も解決します。いずれかのユニットに障害が発生した場合でも、別のサービス セットが利用可能です。
ただし、このソリューションは 2 台のマシンのシナリオでのみ使用できます。ビジネスが依然として急速に拡大している場合は、ビジネスを分離し、複数のマスター間サービスや相互バックアップ サービスを確立することもできます。
3. Web サーバーとデータベースの間にキャッシュを確立する
実際、大規模なアクセスの問題を解決するには、単純に行うことはできません。データベースレベルに焦点を当てます。 「80/20 ルール」によると、リクエストの 80% はホット データの 20% のみに焦点を当てています。したがって、Web サーバーとデータベースの間にキャッシュ メカニズムを確立する必要があります。このメカニズムでは、ディスクをキャッシュまたはメモリ キャッシュとして使用できます。これらにより、ほとんどのホット データ クエリはデータベースの前でブロックされます。
1. ページの静的化
ユーザーが Web サイト上の特定のページにアクセスすると、ページ上のコンテンツのほとんどは長期間変更されない可能性があります。たとえば、ニュースレポートは、一度公開されるとほとんど変更されません。この場合、CGI によって生成された静的 HTML ページは、Web サーバーのディスク上にローカルにキャッシュされます。動的 CGI クエリ データベースを通じて取得される初回を除き、ローカル ディスク ファイルはユーザーに直接返されます。
Web システムの規模が比較的小さかったときは、このアプローチが最適であるように思えました。しかし、Webサーバーが100台になるなど、Webシステムの規模が大きくなると。この方法では、これらのディスク ファイルのコピーが 100 個存在することになりますが、これはリソースの無駄であり、保守が困難です。このとき、サーバーを一元管理して保存すればよいのではないかと考える人もいるかもしれませんが、次のキャッシュ方法を見てみてはいかがでしょうか。
2. シングル メモリ キャッシュ
ページの静的化の例を通して、Web マシン自体で「キャッシュ」を維持するのは難しく、さらに多くの問題を引き起こすことがわかります (実際、PHP の apc 拡張機能を使用すると、Web サーバーのネイティブ メモリをキー/値を通じて操作できます)。したがって、構築することを選択したメモリ キャッシュ サービスも独立したサービスである必要があります。
メモリ キャッシュの選択には、主に redis/memcache が含まれます。パフォーマンスの点では両者に大きな違いはありませんが、機能の豊富さの点では Redis の方が優れています。
3. メモリ キャッシュ クラスター
単一のメモリ キャッシュを構築すると、単一障害点の問題に直面するため、それをクラスター化する必要があります。簡単な方法は、スレーブをバックアップ マシンとして追加することです。しかし、実際にリクエストが多く、キャッシュ ヒット率が高くなく、より多くのマシン メモリが必要であることが判明した場合はどうなるでしょうか?したがって、クラスターとして構成することをお勧めします。たとえば、redis クラスターに似ています。
Redis クラスター クラスター内の Redis は複数のマスターとスレーブのセットであり、同時に各ノードがリクエストを受け入れることができるため、クラスターを拡張する場合に便利です。クライアントは任意のノードにリクエストを送信でき、それが「担当する」コンテンツであれば、そのコンテンツが直接返されます。それ以外の場合は、実際に責任のある Redis ノードを見つけて、クライアントにアドレスを通知し、クライアントは再度要求します。
これはすべて、キャッシュ サービスを使用するクライアントに対して透過的です。
メモリ キャッシュ サービスを切り替える場合には、特定のリスクが伴います。クラスタ A からクラスタ B に切り替えるプロセスでは、クラスタ B が事前に「ウォームアップ」されていることを確認する必要があります (クラスタ B のメモリ内のホット データは可能な限りクラスタ A のメモリと同じである必要があります)そうしないと、切り替えの瞬間に大量のコンテンツ要求が要求されます。クラスター B のメモリ キャッシュでは見つかりません。トラフィックはバックエンド データベース サービスに直接影響し、データベースのダウンタイムが発生する可能性があります)。
4. データベースの「書き込み」の削減
上記のメカニズムはいずれもデータベースの「読み取り」操作の削減を実現しますが、書き込み操作も大きな負担となります。書き込み操作を減らすことはできませんが、リクエストをマージすることで負荷を軽減できます。このとき、メモリ キャッシュ クラスタとデータベース クラスタの間で変更の同期メカニズムを確立する必要があります。
まず、外部クエリが正常に表示できるように、変更リクエストをキャッシュに入れてから、これらの SQL 変更をキューに入れて保存します。キューがいっぱいになったとき、または時々、これらは 1 つのリクエストにマージされ、データベースに送信されます。データベースを更新します。
上記のシステム アーキテクチャを変更することで書き込みパフォーマンスを向上させることに加えて、MySQL 自体もパラメーター innodb_flush_log_at_trx_commit を構成することでディスクへの書き込み戦略を調整できます。マシンのコストが許せば、ハードウェア レベルから問題を解決するために、古い RAID (独立したディスクの冗長アレイ、ディスク アレイ) または新しい SSD (ソリッド ステート ドライブ、ソリッド ステート ドライブ) を選択できます。
5. NoSQL ストレージ
データベースの読み取り、書き込みに関係なく、トラフィックがさらに増加すると、最終的には「人手が制限されるとき」のシナリオに到達します。マシンを追加するコストは比較的高く、実際には問題を解決できない可能性があります。現時点では、一部のコア データに NoSQL データベースの使用を検討できます。 NoSQL ストレージの多くはキーバリュー方式を採用していますが、上で紹介したように Redis を使用することをお勧めします。Redis 自体がメモリ キャッシュであり、ストレージとしても使用できるため、データを直接ディスクに保存できます。
この場合、データベース内で頻繁に読み書きされるデータの一部を分離し、新しく構築した Redis ストレージ クラスターに配置します。これにより、元の MySQL データベースへの負担がさらに軽減されます。 Redis自体はメモリレベルのキャッシュであり、読み書きのパフォーマンスが大幅に向上します。
国内の一流インターネット企業は、アーキテクチャの点で上記のソリューションと同様のソリューションを多く採用しています。ただし、使用されるキャッシュ サービスは必ずしも Redis であるとは限りません。他のオプションも豊富で、さらには Redis に基づくものもあります。独自のビジネス特性に基づいて独自の NoSQL サービスを開発します。
6. 空ノード クエリの問題
上記のサービスをすべて構築し、Web システムがすでに非常に強力であると考えたとき。私たちは今も同じことを言っていますが、新たな問題は依然として発生します。空のノード クエリは、データベースにまったく存在しないデータ リクエストを指します。たとえば、存在しない個人情報のクエリをリクエストすると、システムはすべてのレベルで段階的にキャッシュを検索し、最終的にデータベース自体を見つけ、見つからないという結論を導き出し、結果を返します。フロントエンドまで。すべてのレベルのキャッシュが無効であるため、このリクエストは大量のシステム リソースを消費し、多数の空のノード クエリが行われると、システム サービスに影響を与える可能性があります。
以上がウェブサイトシステムのキャッシュ機構の構築と最適化の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。