redis はデータベースですが、従来のデータベースとは異なり、redis データはメモリ上に保存されるため、読み取りと書き込みの速度が非常に高速であるため、キャッシュ方向で redis が広く使用されています。 Memcached は、高性能の 分散メモリ キャッシュ サーバーです。使用の一般的な目的は、データベース クエリ結果をキャッシュし、データベース アクセスの数を減らすことによって、動的 Web アプリケーションの速度とスケーラビリティを向上させることです。
Redis の作者である Salvatore Sanfilippo は、かつて次の 2 つのメモリベースのデータ ストレージ システムを比較しました。
Redis はサーバー側のデータ操作をサポートします: Memcached と比較して、Redis はより多くのデータ構造を持ち、より豊富なデータ操作をサポートします。通常、Memcached では、同様の操作を実行するためにクライアントにデータを取得する必要があります。変更を行ってから、それらを元に戻してください。これにより、ネットワーク IO の数とデータ量が大幅に増加します。一般的な GET/SET と比較すると、これらの複雑な操作は通常、Redis で同様に効率的です。したがって、より複雑な構造と操作をサポートするキャッシュが必要な場合は、Redis が適切な選択肢になります。
メモリ使用効率の比較: 単純なキーと値のストレージを使用する場合は、Memcached のメモリ使用率が高くなります。また、Redis がキーと値のストレージにハッシュ構造を使用する場合は、その組み合わせにより、Memcached のメモリ使用率が高くなります。このタイプの圧縮では、メモリ使用率が Memcached よりも高くなります。
パフォーマンスの比較: Redis は 1 つのコアのみを使用しますが、Memcached は複数のコアを使用できるため、各コアに少量のデータを保存する場合、平均して Redis の方が Memcached よりも高いパフォーマンスを発揮します。 100k を超えるデータについては、Memcached のパフォーマンスが Redis よりも高く、Redis は最近ビッグ データの保存パフォーマンスに最適化されていますが、それでも Memcached よりわずかに劣ります。
上記の結論が得られる具体的な理由は、以下が収集された情報です:
および Memcached は単純なデータ型のみをサポートしますキーと値の構造のデータ レコードは異なり、Redis でサポートされるデータ型はさらに豊富です。最も一般的なデータ型には、文字列、ハッシュ、リスト、セット、ソート セットなどがあります。 Redis は redisObject オブジェクトを使用してすべてのキーと値を表します。 redisObject の最も重要な情報を図に示します:
type は値オブジェクトの特定のデータ型を表し、エンコーディングはさまざまなデータ型を redis 内に格納する方法です。例: type=string は、格納される値 通常の文字列の場合、対応するエンコーディングは raw または int になります。int の場合、実際の Redis が内部的に文字列を格納し、数値クラスに従って表現することを意味します。もちろん、文字列自体が可能であることが前提です。 :"123″ "456" などの数値で表します。Redis の仮想メモリ機能がオンになっている場合にのみ、vm フィールドが実際にメモリを割り当てます。この機能はデフォルトではオフになっています。
1) String
一般的に使用されるコマンド: set/get/decr/incr/mget など;
アプリケーション シナリオ: String は最も一般的に使用されるデータ型です。通常のキー/値ストレージはこのカテゴリに分類できます;
実装方法: 文字列はデフォルトで文字列として redis 内に保存され、redisObject によって参照されます。このとき、redisObject のエンコードフィールドは int です。
2) Hash
共通コマンド: hget/hset/ hgetall など
アプリケーション シナリオ: ユーザー ID、ユーザー名、年齢、誕生日を含むユーザー情報オブジェクト データを保存したい。ユーザー ID を通じて、ユーザーの名前、年齢、誕生日を取得したい;
実装方法: Redis のハッシュは実際には内部に保存される値ですこれは HashMap であり、Map メンバーに直接アクセスするためのインターフェイスを提供します図に示すように、Key はユーザー ID、Value はマップ。このマップのキーはメンバーの属性名、値は属性値です。このようにして、データは変更され、内部マップのキー(内部マップのキー)を介して直接アクセスできます。マップは Redis ではフィールドと呼ばれます)、つまり、キー (ユーザー ID) フィールド (属性ラベル) を通じて、対応する属性データを操作できます。メモリを節約するために、実際の HashMap 構造を使用する代わりに、1 次元配列のような方法を使用してコンパクトに格納します。このとき、対応する値の redisObject のエンコードは zipmap です。増加すると、自動的に実際の HashMap に変換され、このときのエンコーディングは ht です。
3) リスト
共通コマンド: lpush/rpush /lpop/rpop/lrange など;
アプリケーション シナリオ: Redis リストには多くのアプリケーション シナリオがあり、Redis の最も重要なデータ構造の 1 つでもあります。たとえば、twitter のフォロー リスト、ファン リストなどです。 . Redis のリスト構造を使用して実装できます;
実装方法: Redis リストは双方向リンク リストとして実装され、逆方向検索とトラバーサルをサポートできるため、操作がより便利になります。追加のメモリ オーバーヘッド、送信バッファ キューなどを含む Redis 内の多くの実装。このデータ構造も使用されます。
4) Set
共通コマンド:sadd/spop/smembers/sunion など;
適用シナリオ: Redis セットが提供する外部関数はリストの機能に似ています。特別なことは、セットが自動的に重複排除できることです。リスト データを保存する必要があり、重複したデータが表示されたくない場合は、それを設定します。は良い選択であり、set は、メンバーがセット コレクションに含まれているかどうかを判断するための重要なインターフェイスを提供しますが、これも list では提供できないものです;
実装方法: set の内部実装は、永遠に値です A null HashMap は実際にはハッシュを計算することですぐに分類されるため、set はメンバーがセットに含まれているかどうかを判断する方法を提供できます。
5) ソート セット
一般的なコマンド: zadd/zrange/zrem/zcard など;
アプリケーション シナリオ: Redis ソート セットの使用シナリオSet は似ていますが、set が自動的に並べ替えられない点が異なります。一方、sorted set は、ユーザーが追加の優先順位 (スコア) パラメーターを指定することでメンバーを並べ替えることができ、挿入順、つまり自動的に並べ替えられます。順序付けされた重複しないセット リストが必要な場合は、ソートされたセット データ構造を選択できます。たとえば、Twitter の公開タイムラインを公開時刻をスコアとして保存すると、取得時に自動的に時刻でソートされます。
実装方法: Redis ソート セットは内部的に HashMap とスキップ リスト (SkipList) を使用してデータの保存と順序付けを保証します。HashMap はメンバーからスコアへのマッピングを保存し、スキップ リストはすべてのメンバーを保存します。ジャンプ テーブル構造を使用すると、検索効率が向上し、実装が比較的簡単です。
Redis では、すべてのデータが常にメモリに保存されるわけではありません。これが Memcached との最大の違いです。物理メモリが不足すると、Redis は長期間使用されなかった一部の値をディスクにスワップできます。 Redis はすべてのキー情報のみをキャッシュします。メモリ使用量が特定のしきい値を超えていることが Redis によって検出された場合、スワップ操作がトリガーされます。Redis は、「swappability = age*log(size_in_memory)」に基づいて値に対応するキーを計算し、ディスクにスワップします。その後、これらのキーに対応する値がディスクに保存され、メモリ内でクリアされます。この機能により、Redis はマシン自体のメモリ サイズを超えるデータを維持できるようになります。もちろん、このデータは交換されないため、マシンのメモリ容量はすべての重要なデータを保存するのに十分である必要があります。同時に、Redis がメモリ内のデータをディスクにスワップすると、サービスを提供するメインスレッドとスワップ操作を実行するサブスレッドがメモリのこの部分を共有するため、必要なデータがswapped が更新されると、Redis はサブスレッドが完了するまで操作をブロックします。変更はスワップ操作の完了後にのみ行うことができます。 Redis からデータを読み取るときに、読み取ったキーに対応する値がメモリにない場合、Redis は対応するデータをスワップ ファイルからロードして、リクエスターに返す必要があります。ここには I/O スレッド プールの問題があります。デフォルトでは、Redis はブロックします。つまり、すべてのスワップ ファイルがロードされるまで応答しません。この戦略は、クライアントの数が少なく、バッチ操作が実行される場合に適しています。同時実行性の高い大規模な Web サイト アプリケーションで Redis を使用したい場合、明らかにニーズを満たすには不十分です。したがって、Redis を実行するときは、I/O スレッド プールのサイズを設定し、スワップ ファイルから対応するデータをロードする必要がある読み取りリクエストに対して同時操作を実行して、ブロック時間を短縮します。
Redis や Memcached などのメモリベースのデータベース システムの場合、メモリ管理の効率はシステムのパフォーマンスに影響を与える重要な要素です。従来の C 言語の malloc/free 関数は、メモリの割り当てと解放に最も一般的に使用される方法ですが、この方法には大きな欠陥があります。まず、開発者にとって、malloc と free の不一致によりメモリ リークが発生しやすくなります。2 番目に、頻繁な呼び出しによりメモリ リークが発生します。リサイクルや再利用ができない大量のメモリ フラグメントによりメモリ使用量が削減され、最後に、システム コールとしてのシステム オーバーヘッドが通常の関数呼び出しよりもはるかに大きくなります。したがって、メモリ管理の効率を向上させるために、効率的なメモリ管理ソリューションでは malloc/free 呼び出しを直接使用しません。 Redis と Memcached はどちらも独自のメモリ管理メカニズムを使用しますが、その実装方法は大きく異なるため、以下で 2 つのメモリ管理メカニズムを個別に紹介します。
Memcached は、デフォルトでスラブ割り当てメカニズムを使用してメモリを管理します。その主なアイデアは、割り当てられたメモリを所定のサイズに従って特定の長さのブロックに分割し、対応する長さのキーと値のデータ レコードを格納して、メモリの断片化を完全に解決することです。問題。スラブ割り当てメカニズムは、外部データを保存することのみを目的として設計されています。つまり、すべてのキーと値のデータはスラブ割り当てシステムに保存されますが、Memcached に対する他のメモリ要求は通常の malloc/free を通じて適用されます。システム全体のパフォーマンスに影響を与えないことが周波数によって決まります。スラブ割り当ての原理は非常に単純です。図に示すように、まずオペレーティング システムから大きなメモリ ブロックを適用し、それをさまざまなサイズのチャンクに分割し、同じサイズのチャンクをスラブ クラスのグループに分割します。チャンクは、キーと値のデータを格納するための最小単位として使用されます。各スラブ クラスのサイズは、Memcached の起動時に Growth Factor を指定することで制御できます。図の Growth Factor の値が 1.25 であると仮定し、チャンクの最初のグループのサイズが 88 バイトの場合、チャンクの 2 番目のグループのサイズは 112 バイトなどとなります。
Memcached がクライアントから送信されたデータを受信すると、まず受信したデータのサイズに基づいて最適なスラブ クラスを選択し、次に Memcached によって保存されたスラブ クラス内の空きチャンクのリストをクエリします。データの保存に使用できるチャンクを見つけます。データベースが期限切れになるか破棄されると、そのデータベースが含まれるチャンクはリサイクルされ、空きリストに再度追加されます。
上記のプロセスから、Memcached のメモリ管理システムは非常に効率的であり、メモリの断片化を引き起こさないことがわかりますが、その最大の欠点はスペースの無駄につながることです。可変長データは、各チャンクに割り当てられた特定の長さのメモリ空間を完全に利用することができません。図に示すように、100 バイトのデータが 128 バイトのチャンクにキャッシュされ、残りの 28 バイトは無駄になります。
Redis がメモリ管理を実装する方法には、主にソース コード内の 2 つのファイル zmalloc.h および zmalloc.c が関係します。メモリ管理を容易にするために、Redis はメモリを割り当てた後、このメモリのサイズをメモリ ブロックの先頭に保存します。 real_ptr は、redis が malloc を呼び出した後に返されるメモリ ブロックを指します。 Redisはヘッダーにメモリブロックサイズを格納しますが、sizeが占めるメモリサイズはsize_t型の長さが既知であり、ret_ptrを返します。メモリを解放する必要がある場合、ret_ptr がメモリ マネージャーに渡されます。 ret_ptr を通じて、プログラムは real_ptr の値を簡単に計算し、real_ptr を free に渡してメモリを解放できます。
Redis は、配列を定義することによってすべてのメモリ割り当てを記録します。この配列の長さは ZMALLOC_MAX_ALLOC_STAT です。各数字は、プログラムによって現在割り当てられているメモリ ブロックの数を表し、各メモリ ブロックのサイズは、それが配置されている配列のインデックスと等しくなります。ソース コードでは、この配列は zmalloc_allocations です。 zmalloc_allocations[16] は、長さが 16 バイトの割り当てられたメモリ ブロックの数を表します。 zmalloc.c には、現在割り当てられているメモリの合計サイズを記録する静的変数 used_memory があります。したがって、一般に、Redis はパッケージ化された mallc/free を使用します。これは、Memcached のメモリ管理方法よりもはるかに単純です。
Redis はメモリベースのストレージ システムですが、それ自体がメモリ データの永続化をサポートし、RDB スナップショットと AOF ログという 2 つの主要な永続化戦略を提供します。 Memcached はデータ永続化操作をサポートしていません。
1) RDB スナップショット
RDB スナップショットは Redis の永続化メカニズムであり、ユーザーが現在のデータ スナップショットをデータ ファイルとして保存できるようにします。 Redis は、fork コマンドのコピー オン ライト メカニズムを使用して、データベースに継続的に書き込まれるスナップショットを生成します。スナップショットを生成するときは、fork 操作を使用して子プロセスを作成し、子プロセス内のすべてのデータをループして RDB ファイルに書き込みます。 Redis の save コマンドを使用して、RDB スナップショット生成のタイミングを構成できます。たとえば、スナップショットが 10 分で生成されるように構成したり、1,000 回の書き込み後にスナップショットを生成するように構成したり、複数のルールをまとめて実装したりできます。これらのルールの定義は Redis 構成ファイルにあり、Redis を再起動せずに Redis CONFIG SET コマンドを使用して Redis の実行中にルールを設定することもできます。
書き込み操作は新しいプロセスで実行されるため、Redis RDB ファイルは破損しません。新しい RDB ファイルが生成されると、Redis によって生成された子プロセスはまずデータを一時ファイルに書き込み、次に、アトミックな名前変更システム コールを使用して一時ファイルの名前を RDB ファイルに変更します。これにより、いつ障害が発生しても、Redis RDB ファイルを常に使用できるようになります。 Redis のマスター/スレーブ同期の内部実装では、RDB ファイルも重要な役割を果たします。 RDB には欠点があり、データベースに問題が発生すると、RDB ファイルに保存されたデータは新品ではなく、最後の RDB ファイルの生成から Redis のシャットダウンまでのデータがすべて失われます。一部のビジネスでは、これは許容できるものです。
2) AOF ログ
AOF ログの完全名は「Append Write File」で、継続的に追加および書き込みが行われるログ ファイルです。一般的なデータベースのbinlogとは異なり、AOFファイルは識別可能なプレーンテキストであり、その内容はRedis標準のコマンドを一つ一つ記述したものです。データの変更を引き起こすコマンドのみが AOF ファイルに追加されます。データを変更する各コマンドによってログが生成され、AOF ファイルがどんどん大きくなるため、Redis には AOF リライトと呼ばれる別の機能が用意されています。その機能は AOF ファイルを再生成することであり、同じ値に対して複数の操作が記録される可能性がある古いファイルとは異なり、新しい AOF ファイルのレコードに対する操作は 1 つだけです。 AOF は、プロセスをフォークし、データを直接走査して新しい一時 AOF ファイルに書き込むという、RDB と同様の方法で生成されます。データが新しいファイルに書き込まれている間、すべての書き込み操作ログは元の AOF ファイルに記録され、同時にメモリ バッファーにも記録されます。重要な操作が完了すると、すべてのバッファ ログがバッチで一時ファイルに書き込まれます。次に、アトミックな「rename」コマンドを使用して、古い AOF ファイルを新しい AOF ファイルに置き換えます。
AOF はファイル書き込み操作であり、その目的は操作ログをディスクに書き込むことであるため、前述の書き込み操作プロセスも発生します。 Redis で AOF の write を呼び出した後、appendfsync オプションを使用して、fsync を呼び出してディスクに書き込む時間を制御します。appendfsync の以下の 3 つの設定のセキュリティ強度は徐々に強化されます。
appendfsync no appendfsync が no に設定されている場合、Redis は AOF ログの内容をディスクに同期するために fsync を積極的に呼び出しません。そのため、これはすべてオペレーティング システムのデバッグに完全に依存します。ほとんどの Linux オペレーティング システムでは、fsync 操作が 30 秒ごとに実行され、バッファ データがディスクに書き込まれます。
appendfsync Everysec appendfsync が Everysec に設定されている場合、Redis はデフォルトで毎秒 fsync 呼び出しを実行し、バッファー内のデータをディスクに書き込みます。ただし、この fsync 呼び出しが 1 秒以上続く場合。 Redis は fsync を遅らせる戦略を採用し、さらに 1 秒待ちます。つまり、fsync は 2 秒後に実行されますが、今回は実行にかかる時間に関係なく fsync が実行されます。 fsync 操作の進行中はファイル記述子がブロックされるため、現在の書き込み操作はブロックされます。したがって、通常の状況では、Redis は fsync 操作を毎秒実行します。最悪の場合、fsync 操作は 2 秒ごとに発生します。この操作は、ほとんどのデータベース システムではグループ コミットと呼ばれ、複数の書き込み操作のデータを結合し、ログを一度にディスクに書き込みます。
appednfsync always appendfsync が always に設定されている場合、fsync は書き込み操作ごとに 1 回呼び出されます。この時点で、データは最も安全です。もちろん、fsync が実行されるため、そのたびに、そのパフォーマンスも影響を受けます。
一般的なビジネス ニーズでは、永続化のために RDB を使用することをお勧めします。その理由は、RDB のオーバーヘッドが AOF ログのオーバーヘッドよりもはるかに低いためです。データを許容できないアプリケーションの場合は、損失がある場合は、AOF ログを使用することをお勧めします。
Memcached はフルメモリのデータ バッファリング システムであり、Redis はデータの永続化をサポートしていますが、結局のところフルメモリこそがその高パフォーマンスの本質です。メモリベースのストレージ システムとして、マシンの物理メモリのサイズが、システムが収容できるデータの最大量となります。処理するデータ量が単一マシンの物理メモリ制限を超える場合、ストレージ機能を拡張するには、分散クラスターを確立する必要があります。
Memcached 自体は分散をサポートしていないため、Memcached の分散ストレージは、コンシステント ハッシュなどの分散アルゴリズムを通じてのみクライアントに実装できます。以下の図は、Memcached の分散ストレージ実装アーキテクチャを示しています。クライアントが Memcached クラスターにデータを送信する前に、まずデータのターゲット ノードが組み込みの分散アルゴリズムによって計算され、次にデータは保存のためにノードに直接送信されます。クライアントがデータをクエリするときは、まずクエリ対象のデータが存在するノードを計算し、次にそのノードにクエリ リクエストを送信してデータを取得する必要があります。
クライアントを使用して分散ストレージを実装することしかできない Memcached と比較して、Redis はサーバー側に分散ストレージを構築することを好みます。最新バージョンの Redis はすでに分散ストレージ機能をサポートしています。 Redis Cluster は、分散を実装し、単一障害点を可能にする Redis の高度なバージョンで、中央ノードがなく、線形のスケーラビリティを備えています。以下の図は、Redis Cluster の分散ストレージ アーキテクチャを示しています。ノード間はバイナリ プロトコルを通じて通信し、ノードとクライアント間は ASCII プロトコルを通じて通信します。データ配置戦略の観点から、Redis Cluster はキー値フィールド全体を 4096 個のハッシュ スロットに分割し、各ノードは 1 つ以上のハッシュ スロットを保存できます。つまり、Redis Cluster で現在サポートされているノードの最大数は 4096 です。 Redis Cluster で使用される分散アルゴリズムも非常に単純です: crc16(key) % HASH_SLOTS_NUMBER。
Redis クラスターにはマスター ノードとスレーブ ノードが導入されており、単一障害点が発生した場合でもデータを確実に利用できるようになります。 Redis クラスターでは、冗長性を確保するために、各マスター ノードに 2 つの対応するスレーブ ノードがあります。このようにして、クラスター全体で、2 つのノードのダウンタイムによってデータが利用できなくなることはありません。マスター ノードがオフラインになると、クラスターはスレーブ ノードから新しいマスター ノードを自動的に選択します。
以上がRedis と Memcached の違いは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。