ホームページ  >  記事  >  データベース  >  Redis でマスターしなければならない 20 の質問、ぜひ集めてください。 !

Redis でマスターしなければならない 20 の質問、ぜひ集めてください。 !

青灯夜游
青灯夜游転載
2021-10-19 10:31:241661ブラウズ

この記事では、知ってマスターする必要がある Redis に関する 20 の問題を紹介します。お役に立てれば幸いです。ぜひ集めてください。

Redis でマスターしなければならない 20 の質問、ぜひ集めてください。 !

Redis とは何ですか?

Redis (Remote Dictionary Server) は、C 言語で書かれた高性能の非リレーショナル キー/値データベースです。従来のデータベースとは異なり、Redis データはメモリに保存されるため、読み取りおよび書き込み速度が非常に速く、キャッシュに広く使用されています。 Redis はデータをディスクに書き込むことができ、データのセキュリティを確保して損失を防ぎ、Redis の操作はアトミックです。 [関連する推奨事項: Redis ビデオ チュートリアル ]

Redis の利点は何ですか?

  • メモリ操作に基づいて、メモリの読み取りおよび書き込み速度が高速です。

  • Redis は シングルスレッド であるため、スレッド切り替えのオーバーヘッドやマルチスレッドの競合の問題が回避されます。シングル スレッドとは、ネットワーク リクエストが 1 つのスレッドで処理されることを意味します。つまり、1 つのスレッドがすべてのネットワーク リクエストを処理します。Redis には実行時に複数のスレッドがあります。たとえば、データ永続化のプロセスは新しいスレッドを開始します。

  • 文字列、ハッシュ、リスト、セット、ZSet などを含む複数のデータ型をサポートします。

  • 永続性のサポート。 Redis は、RDB と AOF という 2 つの永続化メカニズムをサポートしており、永続化機能によりデータ損失の問題を効果的に回避できます。

  • サポート トランザクション。 Redis のすべての操作はアトミックであり、Redis は複数の操作をマージした後のアトミック実行もサポートしています。

  • マスター/スレーブ レプリケーションをサポート。マスター ノードはデータをスレーブ ノードに自動的に同期し、読み取りと書き込みを分離できます。

Redis はなぜそれほど速いのでしょうか?

  • メモリベース: Redis はメモリ ストレージを使用し、ディスク IO オーバーヘッドはありません。データはメモリに保存されるため、読み書き速度が高速です。
  • シングルスレッド実装 (Redis 6.0 より前): Redis は単一のスレッドを使用してリクエストを処理し、スレッド切り替えのオーバーヘッドと複数のスレッド間のロック リソースの競合を回避します。
  • IO 多重化モデル : Redis は IO 多重化テクノロジを使用します。 Redis は単一のスレッドを使用して記述子をポーリングし、ネットワーク I/O にあまり時間を費やすことなく、データベース操作をイベントに変換します。
  • 効率的なデータ構造: Redis は高速化を追求するために、各データ型の最下層を最適化しました。
Redis がシングルスレッドを選択する理由は何ですか?

    過剰な
  • コンテキスト切り替えオーバーヘッドを回避します。プログラムはプロセス内で常に単一スレッドで実行され、マルチスレッド切り替えのシナリオはありません。
  • 同期メカニズムのオーバーヘッドを回避する: Redis がマルチスレッド モデルを選択し、データ同期の問題を考慮する必要がある場合、必然的にいくつかの同期メカニズムが導入され、問題が発生します。オーバーヘッドが増えるとプログラムが複雑になり、パフォーマンスが低下します。
  • シンプルな実装と簡単なメンテナンス: Redis がマルチスレッド モードを使用する場合、基礎となるすべてのデータ構造の設計でスレッド セーフティの問題を考慮する必要があり、Redis の実装はより複雑になります。 。
Redis のアプリケーション シナリオは何ですか?

  • ホットスポット データをキャッシュしてデータベースへの負担を軽減します。

  • Redis のアトミックな自動インクリメント操作を使用すると、ユーザーのいいね数やユーザーの訪問数のカウントなど、
  • counter

    の機能を実現できます。 、など。

  • 単純なメッセージ キュー

    Redis 独自のパブリッシュ/サブスクライブ モードまたはリストを使用して、単純なメッセージ キューを実装し、非同期操作を実装できます。

  • スピード リミッター

    は、ユーザーが特定のインターフェイスにアクセスする頻度を制限するために使用できます。たとえば、フラッシュ セール シナリオは、ユーザーがアクセスするのを防ぐために使用されます。素早いクリックによる不必要な圧力。

  • 友人関係

    は、共通の友人や共通の趣味などの機能を実現するために、共通の友人や共通の趣味などの機能を実現するために、交差、和集合、差集合などのいくつかのコレクション コマンドを使用します。

  • Memcached と Redis の違いは何ですか?

    Redis は
  • 単一コア

    のみを使用しますが、Memcached は複数のコアを使用できます。

  • MemCached は単一のデータ構造を持ち、データをキャッシュするためにのみ使用されますが、
  • Redis は複数のデータ型をサポートします

  • MemCached はデータの永続化をサポートしていないため、再起動するとデータが消えます。
  • Redis はデータの永続性をサポートします

  • #Redis は、高可用性サービスを提供できるマスター/スレーブ同期メカニズムとクラスター展開機能

    を提供します。 Memcached はネイティブ クラスター モードを提供しないため、クラスター内のシャードにデータを書き込むにはクライアントに依存する必要があります。

  • Redis は Memcached よりもはるかに高速です。
  • Redis は
  • シングルスレッド マルチチャネル IO 再利用モデル

    を使用し、Memcached はマルチスレッドのノンブロッキング IO モデルを使用します。

Redis のデータ型は何ですか?

基本データ型:

1、String: 最も一般的に使用されるデータ型、文字列型の値は文字列または数値またはバイナリですが、最大値は 512MB を超えることはできません。

2、ハッシュ: ハッシュはキーと値のペアのコレクションです。

3、Set: 重複排除を備えた順序なしセット。 Set は交差や結合などのメソッドを提供しており、共通の友人や共通の注意などの機能を実現するのに特に便利です。

4、List: 順序付けされた反復可能なコレクション。最下層は二重リンク リストに依存して実装されます。

5, SortedSet(ZSet): 順序付きセット。 score パラメータは実装のために内部的に維持されます。ランキングや重み付けされたメッセージ キューなどのシナリオに適しています。

特別なデータ型:

1、Bitmap: ビットマップ、ビット単位の配列とみなすことができます。配列 各ユニットは 0 または 1 のみを格納できます。配列の添え字は、ビットマップではオフセットと呼ばれます。ビットマップの長さはコレクション内の要素の数とは関係ありませんが、カーディナリティの上限に関係します。

2、ハイパーログログ。 HyperLogLog はカーディナリティ統計に使用されるアルゴリズムで、その利点は、入力要素の数またはボリュームが非常に大きい場合でも、カーディナリティの計算に必要なスペースが常に固定され、非常に小さいことです。一般的な使用シナリオは、ユニーク訪問者の数をカウントすることです。

3、地理空間: 主に地理的位置情報を保存し、保存された情報を操作するために使用されます。適用可能なシナリオには、測位、近くの人々などがあります。

Redis トランザクション

トランザクションの原理は、トランザクション スコープ内の複数のコマンドを Redis に送信し、Redis にこれらのコマンドを順番に実行させることです。

トランザクション ライフ サイクル:

  • MULTI を使用してトランザクションを開きます。

  • はトランザクションを開きます。トランザクション では、各操作のコマンドがキューに挿入され、コマンドは実際には実行されません。

  • EXEC コマンドがトランザクションをコミットします。

Redis でマスターしなければならない 20 の質問、ぜひ集めてください。 !

トランザクション スコープ内のコマンドのエラーは、他のコマンドの実行には影響せず、アトミック性は保証されません:

first:0>MULTI
"OK"
first:0>set a 1
"QUEUED"
first:0>set b 2 3 4
"QUEUED"
first:0>set c 6
"QUEUED"
first:0>EXEC
1) "OK"
2) "OK"
3) "OK"
4) "ERR syntax error"
5) "OK"
6) "OK"
7) "OK"

WATCH コマンド

WATCH コマンドは 1 つ以上のキーを監視できます。キーの 1 つが変更されると、後続のトランザクションは実行されなくなります (オプティミスティック ロックと同様) )。 EXECコマンド実行後、監視は自動的に解除されます。

first:0>watch name
"OK"
first:0>set name 1
"OK"
first:0>MULTI
"OK"
first:0>set name 2
"QUEUED"
first:0>set gender 1
"QUEUED"
first:0>EXEC
(nil)
first:0>get gender
(nil)

たとえば、上記のコードでは:

  1. watch namenamekey## の監視をオンにします。
  2. #name
  3. name
  4. gender## がトランザクションに設定されているトランザクションを開く
  5. name
  6. の値を変更しますa #の値。
  7. EXEC
  8. コマンドを使用してトランザクションを送信します。コマンド
  9. get gender
  10. を使用して、存在しないことを確認します。つまり、トランザクション a は実行されません
UNWATCH

を使用して、WATCH コマンドによる key の監視をキャンセルし、すべての監視ロックが解除されます。 永続化メカニズム

永続化とは、サービスのダウンタイムによるメモリ データの損失を防ぐために、

メモリ データをディスク

に書き込むことです。 Redis は 2 つの永続化メソッドをサポートしています。1 つは

RDB

メソッド、もう 1 つは AOF メソッドです。 前者は、指定されたルールに従って定期的にデータをハードディスクのメモリに保存します。一方、後者は、コマンドを実行するたびにコマンドを記録します。一般に、この 2 つを組み合わせて使用​​します。 RDB メソッド

RDB

は、Redis のデフォルトの永続化ソリューションです。 RDB が永続化されると、メモリ内のデータがディスクに書き込まれ、指定したディレクトリに

dump.rdb ファイルが生成されます。 Redis を再起動すると、dump.rdb ファイルがロードされてデータが復元されます。 bgsave

は RDB 永続化をトリガーする主流の方法であり、実行プロセスは次のとおりです:

Redis でマスターしなければならない 20 の質問、ぜひ集めてください。 !Execution

BGSAVE
    Command
  • Redis 親プロセスは、現在実行中の子プロセス があるかどうかを判断します。存在する場合、
  • BGSAVE
  • コマンドは直接戻ります。 親プロセスは fork 操作を実行します
  • 子プロセスを作成します
  • 。親プロセスはフォーク操作中はブロックされます。 親プロセスfork完了後、
  • 親プロセスは引き続きクライアントのリクエストを受信して​​処理します
  • 、そして 子プロセスはデータを一時ファイル;子プロセスがすべてのデータの書き込みを完了すると、古い RDB ファイルをこの一時ファイルに置き換えます。
  • Redis が起動すると、RDB スナップショット ファイルが読み取られ、データがハードディスクからメモリにロードされます。 RDB 永続化により、Redis が異常終了すると、最後の永続化以降に変更されたデータは失われます。 RDB 永続性をトリガーする方法:
  1. 手动触发:用户执行SAVEBGSAVE命令。SAVE命令执行快照的过程会阻塞所有客户端的请求,应避免在生产环境使用此命令。BGSAVE命令可以在后台异步进行快照操作,快照的同时服务器还可以继续响应客户端的请求,因此需要手动执行快照时推荐使用BGSAVE命令。

  2. 被动触发

    • 根据配置规则进行自动快照,如SAVE 100 10,100秒内至少有10个键被修改则进行快照。
    • 如果从节点执行全量复制操作,主节点会自动执行BGSAVE生成 RDB 文件并发送给从节点。
    • 默认情况下执行shutdown命令时,如果没有开启 AOF 持久化功能则自动执行·BGSAVE·。

优点

  • Redis 加载 RDB 恢复数据远远快于 AOF 的方式

  • 使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 Redis 的高性能

缺点

  • RDB方式数据无法做到实时持久化。因为BGSAVE每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本比较高。

  • RDB 文件使用特定二进制格式保存,Redis 版本升级过程中有多个格式的 RDB 版本,存在老版本 Redis 无法兼容新版 RDB 格式的问题

AOF方式

AOF(append only file)持久化:以独立日志的方式记录每次写命令,Redis重启时会重新执行AOF文件中的命令达到恢复数据的目的。AOF的主要作用是解决了数据持久化的实时性,AOF 是Redis持久化的主流方式。

默认情况下Redis没有开启AOF方式的持久化,可以通过appendonly参数启用:appendonly yes。开启AOF方式持久化后每执行一条写命令,Redis就会将该命令写进aof_buf缓冲区,AOF缓冲区根据对应的策略向硬盘做同步操作。

默认情况下系统每30秒会执行一次同步操作。为了防止缓冲区数据丢失,可以在Redis写入AOF文件后主动要求系统将缓冲区数据同步到硬盘上。可以通过appendfsync参数设置同步的时机。

appendfsync always //每次写入aof文件都会执行同步,最安全最慢,不建议配置
appendfsync everysec  //既保证性能也保证安全,建议配置
appendfsync no //由操作系统决定何时进行同步操作

接下来看一下 AOF 持久化执行流程:

Redis でマスターしなければならない 20 の質問、ぜひ集めてください。 !

  • 所有的写入命令会追加到 AOP 缓冲区中。

  • AOF 缓冲区根据对应的策略向硬盘同步。

  • 随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩文件体积的目的。AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。

  • 当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复。

优点

  • AOF可以更好的保护数据不丢失,可以配置 AOF 每秒执行一次fsync操作,如果Redis进程挂掉,最多丢失1秒的数据。

  • AOF以append-only的模式写入,所以没有磁盘寻址的开销,写入性能非常高。

缺点

  • 对于同一份文件AOF文件比RDB数据快照要大。

  • 数据恢复比较慢。

主从复制

Redis的复制功能是支持多个数据库之间的数据同步。主数据库可以进行读写操作,当主数据库的数据发生变化时会自动将数据同步到从数据库。从数据库一般是只读的,它会接收主数据库同步过来的数据。一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库。

//启动Redis实例作为主数据库
redis-server  
//启动另一个实例作为从数据库
redis-server --port 6380 --slaveof  127.0.0.1 6379   
slaveof 127.0.0.1 6379
//停止接收其他数据库的同步并转化为主数据库
SLAVEOF NO ONE

主从复制的原理?

  • 当启动一个从节点时,它会发送一个 PSYNC 命令给主节点;

  • 如果是从节点初次连接到主节点,那么会触发一次全量复制。此时主节点会启动一个后台线程,开始生成一份 RDB 快照文件;

  • 同时还会将从客户端 client 新收到的所有写命令缓存在内存中。RDB 文件生成完毕后, 主节点会将RDB文件发送给从节点,从节点会先将RDB文件写入本地磁盘,然后再从本地磁盘加载到内存中

  • その後、マスター ノードはメモリにキャッシュされた書き込みコマンドをスレーブ ノードに送信し、スレーブ ノードはデータを同期します。スレーブ ノードは、ネットワークに障害が発生して接続が切断された場合、自動的に再接続します。接続後、マスター ノードは欠落しているデータの一部のみをスレーブ ノードに同期します。

  • Sentinel

  • マスター/スレーブ レプリケーションには、自動フェイルオーバーや高可用性などの問題があります。セントリーモードはこれらの問題を解決します。センチネル メカニズムは、マスター ノードとスレーブ ノードを自動的に切り替えることができます。

クライアントが Redis に接続するとき、最初に Sentinel に接続します。Sentinel はクライアントに Redis マスター ノードのアドレスを伝え、その後クライアントは Redis に接続して後続の操作を実行します。マスター ノードがダウンすると、Sentinel はマスター ノードがダウンしていることを検出し、パフォーマンスの良いスレーブ ノードを新しいマスター ノードとして再選択し、パブリッシュ/サブスクライブ モードを通じて他のスレーブ サーバーに通知して切り替えられるようにします。ホスト。

動作原理Redis でマスターしなければならない 20 の質問、ぜひ集めてください。 !

Sentinel

は 1 秒に 1 回メッセージを送信します 既知
    Master
  • Slave、およびその他の Sentinel インスタンスは、PING コマンドを送信します。 インスタンスの PING コマンドに対する最後の有効な応答からの時間が指定された値を超えた場合、インスタンスは
  • Sentine
  • によって主観的にオフラインとしてマークされます。 Master が主観的オフラインとしてマークされている場合、この
  • Master
  • を監視しているすべての Sentinel は 1 秒に 1 回の頻度で確認する必要があります Master本当に主観的なオフライン状態に入ったかどうか。 十分な数の Sentinel (構成ファイルで指定された値以上) により、
  • Master
  • が実際に主観的オフライン状態に入ったことが確認されると、指定された時間範囲を指定すると、Master は客観的にオフラインとしてマークされます。 Master がオフラインであることに同意するのに十分な Sentinel がいない場合、Master の客観的なオフライン ステータスは解除されます。 MasterSentinelPING コマンドに対して再度有効な応答を返した場合、Master の主観的なオフライン ステータスは削除されます。 センチネル ノードは、フェイルオーバーを担当するセンチネル リーダーを選出します。 センチネル リーダーは、パフォーマンスの良いスレーブ ノードを新しいマスター ノードとして選出し、他のスレーブ ノードにマスター ノード情報を更新するように通知します。
  • Redis クラスター
  • センチネル モードは、マスター/スレーブ レプリケーションが自動的にフェイルオーバーできず、高可用性を実現できないという問題を解決しますが、マスター ノードの書き込み能力と容量は依然として制限されています。 . 単一マシン構成の問題。クラスターモードはRedisの分散ストレージを実現し、各ノードが異なるコンテンツを保存するため、マスターノードの書き込み能力と容量がシングルマシン構成によって制限される問題を解決します。

Redis クラスタークラスターノードの最小構成は 6 ノード (3 つのマスターと 3 つのスレーブ) を超えます。マスター ノードは読み取りおよび書き込み操作を提供し、スレーブ ノードはバックアップ ノードとして機能します。リクエストを処理し、フェイルオーバーのみに使用されます。

Redis クラスターは

仮想スロット パーティショニング

を使用します。すべてのキーはハッシュ関数に従って 0 ~ 16383 の整数スロットにマッピングされます。各ノードはスロットの一部とキー値を維持する責任があります。スロットデータによってマッピングされます。

#ハッシュ スロットは Redis インスタンスにどのようにマッピングされますか? Redis でマスターしなければならない 20 の質問、ぜひ集めてください。 !

crc16
    アルゴリズムを使用して、キーと値のペア
  • key

    の結果を計算します。 結果の残りを 16384 にすると、取得された値は key

  • に基づいて対応するインスタンスを見つけます。スロット情報

  • 利点:

中央アーキテクチャはなく、

容量の動的な拡張をサポートします。

データは
    スロットに続きます
  • ストレージは複数のノードに分散され、データはノード間で共有されます。データ分散は動的に調整可能;
  • 高可用性。一部のノードが使用不可になった場合でも、クラスターは引き続き使用可能です。クラスター モードでは、自動フェイルオーバー (フェイルオーバー) を実現し、gossip プロトコルを通じてノード間でステータス情報を交換し、投票メカニズムを使用して
  • Slave
  • から Master への役割の移行を完了できます。 欠点:
    • バッチ操作 (パイプライン) はサポートされていません。
    • データは非同期的にレプリケートされます。データの強力な一貫性は保証されません
    • トランザクション操作のサポートは制限されています。複数の key が異なるノードに分散されている場合、同じノード上の複数の key トランザクション操作のみをサポートします。この期間中はトランザクション機能はご利用いただけません。
    • key データ分割の最小粒度として、hashlist などの大きなキーと値のオブジェクトをマッピングすることはできません。別のノードに。
    • 複数のデータベース スペースはサポートされません. スタンドアロン モードの Redis は最大 16 個のデータベースをサポートできますが、クラスター モードで使用できるデータベース スペースは 1 つだけです。

    期限切れのキーの削除戦略?

    1、受動的削除 (遅延)。キーにアクセスしたときに、キーの有効期限が切れていることが判明した場合、キーは削除されます。

    2、積極的に (定期的に) 削除します。定期的にキーをクリーンアップします。各クリーンアップは、すべての DB を順番に走査し、データベースから 20 個のキーをランダムに取り出し、期限切れになった場合は削除します。5 つのキーの期限が切れた場合は、この DB のクリーンアップを続行し、それ以外の場合は次の DB のクリーンアップを開始します。

    3.

    メモリ不足時のクリーンアップ。 Redis には最大メモリ制限があります。最大メモリは maxmemory パラメータで設定できます。使用されているメモリが設定された最大メモリを超えると、メモリを解放する必要があります。メモリが解放されると、構成された削除戦略に従ってメモリがクリーンアップされます。

    メモリ除去戦略とは何ですか?

    Redis のメモリが最大許容メモリを超えると、Redis サーバーの正常な動作を確保するために、Redis はメモリ削除戦略をトリガーし、使用頻度の低いデータを削除します。

    Redisv4.0 より前では、6 つのデータ削除戦略が提供されていました :

    • volatile-lru: LRU (Least Recently)中古 )、最近使用しました。 LRU アルゴリズムを使用して、有効期限が設定されたキーを削除します
    • allkeys-lru: 新しく書き込まれたデータを収容するにはメモリが不十分な場合、最も最近使用されていないキーをデータ セットから削除します
    • volatile-ttl: 有効期限を設定したデータ セットから期限切れになるデータを選択して削除します。
    • volatile-random: 選択します有効期限が設定されているデータ セットから期限切れになるデータ データ セットから削除するデータをランダムに選択します
    • allkeys-random: データ セットから削除するデータをランダムに選択します
    • no-eviction: メモリが新しく書き込まれたデータを収容するのに十分ではない場合、新しい書き込み操作でエラーが報告される場合、データの削除を禁止します

    Redisv4.0 以降、次の 2 つの が追加されます:

    • volatile-lfu: LFU、Least Frequently Used、最も使用頻度の低いものを選択します。有効期限のあるデータをデータセットから削除し、削除します。
    • allkeys-lfu: 新しく書き込まれたデータを収容するにはメモリが不十分な場合は、最も使用頻度の低いキーをデータ セットから削除します。

    メモリ削除ポリシーは、構成ファイルを通じて 変更できます。対応する構成項目は maxmemory-policy で、デフォルト構成は です。ノエビクション

    キャッシュとデータベース間の二重書き込み中にデータの一貫性を確保するにはどうすればよいですか?

    1. 最初にキャッシュを削除してからデータベースを更新します。

    更新操作を実行する場合は、最初にキャッシュを削除してからデータベースを更新します。後続のリクエストが読み取られるとき再度、データベースからデータが読み取られ、読み取られた後、新しいデータがキャッシュに更新されます。

    既存の問題: キャッシュされたデータを削除した後、データベースを更新する前に、この期間中に新しい読み取りリクエストがあると、古いデータがデータベースから読み取られてキャッシュに再書き込みされ、再び不整合が発生します。そして、それ以降の読み取りはすべて古いデータになります。

    2. 最初にデータベースを更新してからキャッシュを削除します。

    更新操作を実行するときは、最初に MySQL を更新します。成功したら、キャッシュを削除してから、新しいデータを後続の読み取りリクエストに送信するライトバック キャッシュ。

    既存の問題: MySQL の更新からキャッシュの削除までの期間、読み取りリクエストはキャッシュされた古いデータのままですが、データベースの更新が完了すると一貫性があり、影響は比較的小さくなります。小さい。

    3. 非同期更新キャッシュ

    データベース更新操作完了後、キャッシュは直接操作されず、操作コマンドがメッセージにカプセル化されて投げ込まれます。メッセージ キュー、そして Redis 自体がデータを消費して更新します。メッセージ キューはデータ操作シーケンスの一貫性を確保し、キャッシュ システム内のデータが正常であることを保証します。

    キャッシュ ペネトレーション、キャッシュ アバランシェ、キャッシュ ブレークダウン [詳細説明]

    Redis キャッシュ ブレークダウン、ペネトレーション、アバランシェの概念とソリューション

    キャッシュ ペネトレーション

    キャッシュペネトレーションとは、

    存在しないデータをクエリすることを指します。ミスがあった場合、キャッシュは受動的に書き込まれるため、データがDBから見つからない場合、データはDBに書き込まれません。これにより、この存在しないデータが要求されるたびに DB 内でクエリが行われることになり、キャッシュの意味が失われます。トラフィックが多い場合、DB がハングする可能性があります。

    • キャッシュ空の値、データベースはチェックされません。

    • 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,查询不存在的数据会被这个bitmap拦截掉,从而避免了对DB的查询压力。

    布隆过滤器的原理:当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。查询时,将元素通过散列函数映射之后会得到k个点,如果这些点有任何一个0,则被检元素一定不在,直接返回;如果都是1,则查询元素很可能存在,就会去查询Redis和数据库。

    缓存雪崩

    缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重挂掉。

    解决方法:在原有的失效时间基础上增加一个随机值,使得过期时间分散一些。

    缓存击穿

    缓存击穿:大量的请求同时查询一个 key 时,此时这个 key 正好失效了,就会导致大量的请求都落到数据库。缓存击穿是查询缓存中失效的 key,而缓存穿透是查询不存在的 key。

    解决方法:加分布式锁,第一个请求的线程可以拿到锁,拿到锁的线程查询到了数据之后设置缓存,其他的线程获取锁失败会等待50ms然后重新到缓存取数据,这样便可以避免大量的请求落到数据库。

    public String get(String key) {
        String value = redis.get(key);
        if (value == null) { 
            //缓存值过期
            String unique_key = systemId + ":" + key;
            //设置30s的超时
            if (redis.set(unique_key, 1, 'NX', 'PX', 30000) == 1) {  //设置成功
                value = db.get(key);
                redis.set(key, value, expire_secs);
                redis.del(unique_key);
            } else {  
                //其他线程已经到数据库取值并回写到缓存了,可以重试获取缓存值
                sleep(50);
                get(key);  //重试
            }
        } else {
            return value;
        }
    }

    pipeline的作用?

    redis客户端执行一条命令分4个过程:发送命令、命令排队、命令执行、返回结果。使用pipeline可以批量请求,批量返回结果,执行速度比逐条执行要快。

    使用pipeline组装的命令个数不能太多,不然数据量过大,增加客户端的等待时间,还可能造成网络阻塞,可以将大量命令的拆分多个小的pipeline命令完成。

    原生批命令(mset和mget)与pipeline对比:

    • 原生批命令是原子性,pipeline非原子性。pipeline命令中途异常退出,之前执行成功的命令不会回滚

    • 原生批命令只有一个命令,但pipeline支持多命令

    LUA脚本

    Redis 通过 LUA 脚本创建具有原子性的命令:当lua脚本命令正在运行的时候,不会有其他脚本或 Redis 命令被执行,实现组合命令的原子操作。

    在Redis中执行Lua脚本有两种方法:evalevalshaeval命令使用内置的 Lua 解释器,对 Lua 脚本进行求值。

    //第一个参数是lua脚本,第二个参数是键名参数个数,剩下的是键名参数和附加参数
    > eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
    1) "key1"
    2) "key2"
    3) "first"
    4) "second"

    lua脚本作用

    1、Lua脚本在Redis中是原子执行的,执行过程中间不会插入其他命令。

    2、Lua脚本可以将多条命令一次性打包,有效地减少网络开销。

    应用场景

    举例:限制接口访问频率。

    在Redis维护一个接口访问次数的键值对,key是接口名称,value是访问次数。每次访问接口时,会执行以下操作:

    • 通过aop拦截接口的请求,对接口请求进行计数,每次进来一个请求,相应的接口访问次数count加1,存入redis。
    • 如果是第一次请求,则会设置count=1,并设置过期时间。因为这里set()expire()组合操作不是原子操作,所以引入lua脚本,实现原子操作,避免并发访问问题。
    • 如果给定时间范围内超过最大访问次数,则会抛出异常。
    private String buildLuaScript() {
        return "local c" +
            "\nc = redis.call('get',KEYS[1])" +
            "\nif c and tonumber(c) > tonumber(ARGV[1]) then" +
            "\nreturn c;" +
            "\nend" +
            "\nc = redis.call('incr',KEYS[1])" +
            "\nif tonumber(c) == 1 then" +
            "\nredis.call('expire',KEYS[1],ARGV[2])" +
            "\nend" +
            "\nreturn c;";
    }
    
    String luaScript = buildLuaScript();
    RedisScript<Number> redisScript = new DefaultRedisScript<>(luaScript, Number.class);
    Number count = redisTemplate.execute(redisScript, keys, limit.count(), limit.period());

    PS:这种接口限流的实现方式比较简单,问题也比较多,一般不会使用,接口限流用的比较多的是令牌桶算法和漏桶算法。

    更多编程相关知识,请访问:编程入门!!

以上がRedis でマスターしなければならない 20 の質問、ぜひ集めてください。 !の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。