Redis が突然遅くなりましたか? Redis にパフォーマンスの問題があるかどうかを判断する方法とその解決方法を分析してみましょう

リリース: 2022-03-01 09:45:28
転載
2662 人が閲覧しました

この記事は、Redis に関する関連知識を提供します。Redis の過度の遅延はさまざまな問題を引き起こす可能性があります。Redis にパフォーマンスの問題があるかどうかを判断する方法と解決策を分析してみましょう。皆さんのお役に立てれば幸いです。

Redis が突然遅くなりましたか? Redis にパフォーマンスの問題があるかどうかを判断する方法とその解決方法を分析してみましょう

推奨される学習: Redis チュートリアル

Redis は通常、キャッシュ、アカウント ログインなど、ビジネス システムの重要なコンポーネントです。情報やランキングなど。

Redis リクエストの遅延が増加すると、ビジネス システムの「雪崩」が発生する可能性があります。

私は独身仲人型のインターネット会社に勤めているのですが、ダブルイレブンの期間中に、注文すると彼女にプレゼントを贈るというキャンペーンを始めました。

午前 12 時を過ぎるとユーザー数が急増し、技術的な不具合が発生してユーザーが注文できなくなるなど、その時、古い火災が発生するとは誰が想像したでしょうか。

検索した結果、Redis が プールからリソースを取得できませんでした と報告していることがわかりました。

接続リソースを取得できず、クラスター内の 1 つの Redis への接続数が非常に多くなっています。

大量のトラフィックが Redis のキャッシュされた応答を失い、MySQL を直接攻撃し、最終的にはデータベースもクラッシュしました...

そのため、最大接続数にさまざまな変更が加えられましたエラー メッセージは報告されましたが、接続待機の数は減少しましたが、エラーはまだ続いています。

その後、オフライン テストを行った結果、Redis に保存されている文字データが非常に大きく、データが返されるまでに平均 1 秒かかることが判明しました。

Redis の遅延が大きくなりすぎると、さまざまな問題が発生することがわかります。

今日は、Redis にパフォーマンスの問題があるかどうかを判断する方法とその解決策を分析しましょう。

Redis のパフォーマンスに問題はありますか?

最大遅延は、クライアントがコマンドを発行してから、クライアントがコマンドに対する応答を受信するまでの時間であり、通常の状況では、Redis の処理時間はマイクロ秒レベルで非常に短いです。

Redis に数秒から 10 秒以上に達するなど、パフォーマンスの変動がある場合、Redis のパフォーマンスが低下していると結論付けることができるのは明らかです。

一部のハードウェア構成は比較的高く、遅延が 0.6ms の場合は遅いと考えられる場合があります。ハードウェアが比較的貧弱な場合、問題があると判断されるまでに 3 ミリ秒かかることがあります。

では、Redis が本当に遅いかどうかをどのように定義すればよいでしょうか?

したがって、現在の環境の Redis ベースライン パフォーマンスを測定する必要があります。これは、低圧で干渉がない状態でのシステムの基本パフォーマンスです。

Redis ランタイムのレイテンシがベースライン パフォーマンスの 2 倍を超えていることが判明した場合は、Redis のパフォーマンスが低下していると判断できます。

レイテンシのベースライン測定

redis-cli コマンドには、テスト期間中の最大レイテンシを監視およびカウントするための –intrinsic-latency オプションが用意されています。 (ミリ秒単位で測定)、この遅延は Redis のベースライン パフォーマンスとして使用できます。

redis-cli --latency -h `host` -p `port`
ログイン後にコピー

たとえば、次のコマンドを実行します。

redis-cli --intrinsic-latency 100
Max latency so far: 4 microseconds.
Max latency so far: 18 microseconds.
Max latency so far: 41 microseconds.
Max latency so far: 57 microseconds.
Max latency so far: 78 microseconds.
Max latency so far: 170 microseconds.
Max latency so far: 342 microseconds.
Max latency so far: 3079 microseconds.
45026981 total runs (avg latency: 2.2209 microseconds / 2220.89 nanoseconds per run).
Worst run took 1386x longer than the average latency.
ログイン後にコピー

注: パラメータ 100 は、テストが実行される秒数です。テストを長く実行するほど、遅延のスパイクが見つかる可能性が高くなります。

通常は 100 秒間実行するのが適切ですが、これで遅延の問題を検出するには十分です。もちろん、エラーを避けるために、異なる時間に数回実行することもできます。

最大実行遅延は 3079 マイクロ秒であるため、ベースライン パフォーマンスは 3079 (3 ミリ秒) マイクロ秒になります。

クライアントではなく、Redis サーバー上で実行する必要があることに注意してください。このようにして、ベースライン パフォーマンスに対するネットワークの影響を回避できます。

You can connect to the server through -h host -p port . Redis パフォーマンスに対するネットワークの影響を監視する場合は、Iperf を使用してネットワーク遅延を測定できます。クライアントからサーバーへ。

ネットワークが数百ミリ秒遅れる場合は、ネットワーク上で他の高トラフィックのプログラムが実行されており、ネットワークの混雑が発生している可能性があるため、ネットワーク トラフィックの分散を調整する運用保守が必要です。

遅い命令の監視

それが遅い命令であるかどうかを判断するにはどうすればよいですか?

操作の複雑さが O(N) かどうかを確認します。公式ドキュメントでは各コマンドの複雑さが紹介されているため、できるだけ O(1) および O(log N) コマンドを使用してください。

フルセット クエリ HGETALL、SMEMBERS、およびセット集計操作 (SORT、LREM、SUNION など) などのセット操作に伴う複雑さは、通常 O(N) です。

観察できる監視データはありますか?私がコードを書いたわけではないので、遅い命令を使った人がいるかどうかはわかりません。

#確認するには 2 つの方法があります:

  • Redis のスロー ログ機能を使用して、遅いコマンドを検出します。 #遅延監視ツール。

  • さらに、自分自身 (top、htop、prstat など) を使用して、Redis メイン プロセスの CPU 消費量をすばやく確認できます。 CPU 使用率が高くてもトラフィックが少ない場合は、通常、遅いコマンドが使用されていることを示します。

    慢日志功能

    Redis 中的 slowlog 命令可以让我们快速定位到那些超出指定执行时间的慢命令,默认情况下命令若是执行时间超过 10ms 就会被记录到日志。

    slowlog 只会记录其命令执行的时间,不包含 io 往返操作,也不记录单由网络延迟引起的响应慢。

    我们可以根据基线性能来自定义慢命令的标准(配置成基线性能最大延迟的 2 倍),调整触发记录慢命令的阈值。

    可以在 redis-cli 中输入以下命令配置记录 6 毫秒以上的指令:

    redis-cli CONFIG SET slowlog-log-slower-than 6000
    ログイン後にコピー

    也可以在 Redis.config 配置文件中设置,以微秒为单位。

    想要查看所有执行时间比较慢的命令,可以通过使用 Redis-cli 工具,输入 slowlog get 命令查看,返回结果的第三个字段以微秒位单位显示命令的执行时间。

    假如只需要查看最后 2 个慢命令,输入 slowlog get 2 即可。

    示例:获取最近2个慢查询命令

    127.0.0.1:6381> SLOWLOG get 2
    1) 1) (integer) 6
       2) (integer) 1458734263
       3) (integer) 74372
       4) 1) "hgetall"
          2) "max.dsp.blacklist"
    2) 1) (integer) 5
       2) (integer) 1458734258
       3) (integer) 5411075
       4) 1) "keys"
          2) "max.dsp.blacklist"
    ログイン後にコピー

    以第一个 HGET 命令为例分析,每个 slowlog 实体共 4 个字段:

    • 字段 1:1 个整数,表示这个 slowlog 出现的序号,server 启动后递增,当前为 6。

    • 字段 2:表示查询执行时的 Unix 时间戳。

    • 字段 3:表示查询执行微秒数,当前是 74372 微秒,约 74ms。

    • 字段 4: 表示查询的命令和参数,如果参数很多或很大,只会显示部分参数个数。当前命令是hgetall max.dsp.blacklist。

    Latency Monitoring

    Redis 在 2.8.13 版本引入了 Latency Monitoring 功能,用于以秒为粒度监控各种事件的发生频率。

    启用延迟监视器的第一步是设置延迟阈值(单位毫秒)。只有超过该阈值的时间才会被记录,比如我们根据基线性能(3ms)的 3 倍设置阈值为 9 ms。

    可以用 redis-cli 设置也可以在 Redis.config 中设置;

    CONFIG SET latency-monitor-threshold 9
    ログイン後にコピー

    工具记录的相关事件的详情可查看官方文档:https://redis.io/topics/latency-monitor

    如获取最近的 latency

    127.0.0.1:6379> debug sleep 2
    OK
    (2.00s)
    127.0.0.1:6379> latency latest
    1) 1) "command"
       2) (integer) 1645330616
       3) (integer) 2003
       4) (integer) 2003
    ログイン後にコピー

    事件的名称;

    事件发生的最新延迟的 Unix 时间戳;

    毫秒为单位的时间延迟;

    该事件的最大延迟。

    如何解决 Redis 变慢?

    Redis 的数据读写由单线程执行,如果主线程执行的操作时间太长,就会导致主线程阻塞。

    一起分析下都有哪些操作会阻塞主线程,我们又该如何解决?

    网络通信导致的延迟

    客户端使用 TCP/IP 连接或 Unix 域连接连接到 Redis。1 Gbit/s 网络的典型延迟约为 200 us。

    redis 客户端执行一条命令分 4 个过程:

    发送命令-〉 命令排队 -〉 命令执行-〉 返回结果

    这个过程称为 Round trip time(简称 RTT, 往返时间),mget mset 有效节约了 RTT,但大部分命令(如 hgetall,并没有 mhgetall)不支持批量操作,需要消耗 N 次 RTT ,这个时候需要 pipeline 来解决这个问题。

    Redis pipeline 将多个命令连接在一起来减少网络响应往返次数。

    Redis が突然遅くなりましたか? Redis にパフォーマンスの問題があるかどうかを判断する方法とその解決方法を分析してみましょう

    redis-pipeline

    慢指令导致的延迟

    根据上文的慢指令监控查询文档,查询到慢查询指令。可以通过以下两种方式解决:

    比如在 Cluster 集群中,将聚合运算等 O(N) 操作运行在 slave 上,或者在客户端完成。

    使用高效的命令代替。使用增量迭代的方式,避免一次查询大量数据,具体请查看SCAN、SSCAN、HSCAN和ZSCAN命令。

    除此之外,生产中禁用KEYS 命令,它只适用于调试。因为它会遍历所有的键值对,所以操作延时高。

    Fork 生成 RDB 导致的延迟

    生成 RDB 快照,Redis 必须 fork 后台进程。fork 操作(在主线程中运行)本身会导致延迟。

    Redis 使用操作系统的多进程写时复制技术 COW(Copy On Write) 来实现快照持久化,减少内存占用。

    Redis が突然遅くなりましたか? Redis にパフォーマンスの問題があるかどうかを判断する方法とその解決方法を分析してみましょう

    写时复制技术保证快照期间数据可修改

    但 fork 会涉及到复制大量链接对象,一个 24 GB 的大型 Redis 实例需要 24 GB / 4 kB * 8 = 48 MB 的页表。

    执行 bgsave 时,这将涉及分配和复制 48 MB 内存。

    此外,从库加载 RDB 期间无法提供读写服务,所以主库的数据量大小控制在 2~4G 左右,让从库快速的加载完成。

    内存大页(transparent huge pages)

    常规的内存页是按照 4 KB 来分配,Linux 内核从 2.6.38 开始支持内存大页机制,该机制支持 2MB 大小的内存页分配。

    Redis 使用了 fork 生成 RDB 做持久化提供了数据可靠性保证。

    当生成 RDB 快照的过程中,Redis 采用**写时复制**技术使得主线程依然可以接收客户端的写请求。

    也就是当数据被修改的时候,Redis 会复制一份这个数据,再进行修改。

    采用了内存大页,生成 RDB 期间,即使客户端修改的数据只有 50B 的数据,Redis 需要复制 2MB 的大页。当写的指令比较多的时候就会导致大量的拷贝,导致性能变慢。

    使用以下指令禁用 Linux 内存大页即可:

    echo never > /sys/kernel/mm/transparent_hugepage/enabled
    ログイン後にコピー

    swap:操作系统分页

    当物理内存(内存条)不够用的时候,将部分内存上的数据交换到 swap 空间上,以便让系统不会因内存不够用而导致 oom 或者更致命的情况出现。

    当某进程向 OS 请求内存发现不足时,OS 会把内存中暂时不用的数据交换出去,放在 SWAP 分区中,这个过程称为 SWAP OUT。

    当某进程又需要这些数据且 OS 发现还有空闲物理内存时,又会把 SWAP 分区中的数据交换回物理内存中,这个过程称为 SWAP IN。

    内存 swap 是操作系统里将内存数据在内存和磁盘间来回换入和换出的机制,涉及到磁盘的读写。

    触发 swap 的情况有哪些呢?

    对于 Redis 而言,有两种常见的情况:

    Redis 使用了比可用内存更多的内存;

    与 Redis 在同一机器运行的其他进程在执行大量的文件读写 I/O 操作(包括生成大文件的 RDB 文件和 AOF 后台线程),文件读写占用内存,导致 Redis 获得的内存减少,触发了 swap。

    我要如何排查是否因为 swap 导致的性能变慢呢?
    ログイン後にコピー

    Linux 提供了很好的工具来排查这个问题,所以当怀疑由于交换导致的延迟时,只需按照以下步骤排查。

    获取 Redis 实例 pid

    $ redis-cli info | grep process_id
    process_id:13160
    ログイン後にコピー

    进入此进程的 /proc 文件系统目录:

    cd /proc/13160
    ログイン後にコピー

    在这里有一个 smaps 的文件,该文件描述了 Redis 进程的内存布局,运行以下指令,用 grep 查找所有文件中的 Swap 字段。

    $ cat smaps | egrep '^(Swap|Size)'
    Size:                316 kB
    Swap:                  0 kB
    Size:                  4 kB
    Swap:                  0 kB
    Size:                  8 kB
    Swap:                  0 kB
    Size:                 40 kB
    Swap:                  0 kB
    Size:                132 kB
    Swap:                  0 kB
    Size:             720896 kB
    Swap:                 12 kB
    ログイン後にコピー

    每行 Size 表示 Redis 实例所用的一块内存大小,和 Size 下方的 Swap 对应这块 Size 大小的内存区域有多少数据已经被换出到磁盘上了。

    如果 Size == Swap 则说明数据被完全换出了。

    可以看到有一个 720896 kB 的内存大小有 12 kb 被换出到了磁盘上(仅交换了 12 kB),这就没什么问题。

    Redis 本身会使用很多大小不一的内存块,所以,你可以看到有很多 Size 行,有的很小,就是 4KB,而有的很大,例如 720896KB。不同内存块被换出到磁盘上的大小也不一样。

    敲重点了

    如果 Swap 一切都是 0 kb,或者零星的 4k ,那么一切正常。

    当出现百 MB,甚至 GB 级别的 swap 大小时,就表明,此时,Redis 实例的内存压力很大,很有可能会变慢。

    解决方案

    增加机器内存;

    Redis のメモリ要件を満たすために同じマシン上で大量のメモリを必要とするプロセスを実行しないように、別のマシンで Redis を実行します。

    データ量を共有するためにクラスタの数を増やします。インスタンスに必要な各メモリを削減します。

    AOF とディスク I/O による遅延

    データの信頼性を確保するために、Redis は AOF と RDB スナップショットを使用して高速リカバリを実現します。そして耐久性も変化。

    appendfsync 構成を使用して、3 つの異なる方法でディスク上で書き込みまたは fsync を実行するように AOF を構成できます (この設定は、redis-cli CONFIG SET appendfsync などの CONFIG SET コマンドを使用して実行時に変更できます)いいえ) 。

    • no: Redis は fsync を実行しません。唯一の遅延は書き込み呼び出しから発生します。書き込みは、戻る前にログ レコードをカーネル バッファに書き込む必要があるだけです。

    • everysec: Redis は 1 秒に 1 回 fsync を実行します。バックグラウンドのサブスレッドを使用して、fsync 操作を非同期的に完了します。最大で 1 個のデータが失われます。

    • always: 各書き込み操作は fsync を実行し、OK コードでクライアントに応答します (実際には、Redis は同時に実行される多くのコマンドを 1 つの fsync に集約しようとします)。データは失われません。 。このモードでは通常、パフォーマンスが非常に遅くなるため、短時間で fsync を実行できる高速ディスクとファイル システム実装を使用することを強くお勧めします。

    通常、キャッシュには Redis を使用します。データ損失は完全に悪意があり、データから取得されます。高いデータ信頼性は必要ありません。no または Everysec に設定することをお勧めします。

    さらに、AOF ファイルが大きくなりすぎないように、Redis は AOF を書き換えて、縮小された AOF ファイルを生成します。

    設定項目 no-appendfsync-on-rewrite を yes に設定できます。これは、AOF が書き換えられるときに fsync 操作が実行されないことを意味します。

    つまり、Redis インスタンスはメモリに書き込みコマンドを書き込んだ後、バックグラウンド スレッドを呼び出して fsync 操作を実行することなく、直接戻ります。

    expires 期限切れデータの削除

    Redis には、期限切れデータを削除する 2 つの方法があります。

    • Lazy削除: リクエストを受信すると、キーの有効期限が切れていることがわかり、削除が実行されます。

    • スケジュールされた削除: 100 ミリ秒ごとに期限切れのキーをいくつか削除します。

    スケジュールされた削除のアルゴリズムは次のとおりです:

    ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP 個のキーをランダムにサンプリングし、期限切れのキーをすべて削除します。キーの有効期限が 25 % を超えている場合は、ステップ 1 に進みます。

    ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP はデフォルトで 20 に設定されており、1 秒あたり 10 回実行されます。200 個のキーを削除しても大きな問題はありません。

    2 番目の項目がトリガーされると、Redis はメモリを解放するために期限切れのデータを一貫して削除します。そして削除はブロックです。

    発動条件は何ですか?

    つまり、多数のキーが同じ時間パラメータを設定します。同じ秒内に多数のキーの有効期限が切れるため、25% 未満に減らすには複数回削除する必要があります。

    要するに: 多数のキーが同時に期限切れになると、パフォーマンスが変動する可能性があります。

    解決策キーのバッチが同時に期限切れになる場合は、EXPIREAT の有効期限パラメータに特定の値を追加できます。 EXPIRE サイズ範囲内の乱数。これにより、キーが近い時間範囲内に削除されることが保証されるだけでなく、同時有効期限によって引き起こされるプレッシャーも回避されます。

    bigkey 通常、大規模なデータ、または多数のメンバーやリストを含むキーをビッグ キーと呼びます。いくつかの実際的な例を使用して、大きなキーの特性を説明します。

    ##STRING 型のキー、その値は 5MB (データが大きすぎます)
    • #A タイプ LIST のキー、リストの数は 10,000 (リストの数が多すぎます)

    • A タイプ ZSET のキー、そのメンバーの数は 10,000 (メンバーが多すぎます)

    • #HASH 形式のキーには 1000 メンバーしかありませんが、これらのメンバーの値の合計サイズは 10MB です (メンバー サイズが大きすぎます)

    • Bigkey は次の問題を引き起こします:

    Redis メモリが増大し続けて OOM が発生するか、maxmemory 設定値に達して書き込みがブロックされたり、重要なキーが削除されたりします。

  • Redis クラスター内の特定のノードのメモリは他のノードのメモリをはるかに上回っていますが、Redis クラスター内のデータ移行の最小粒度がキーであるため、ノード上のメモリのバランスをとることができません。

  • Bigkey の読み取りリクエストは帯域幅を占有しすぎ、速度が低下し、サーバー上の他のサービスに影響を及ぼします。

  • bigkey を削除すると、メイン データベースが長時間ダウンするとブロックされ、同期の中断やマスター/スレーブの切り替えが発生します;

  • bigkey を見つける

    Redis を使用する-rdb-tools カスタマイズされた方法でビッグ キーを検索するツール。

    解決策

    大きなキーを分割する

    たとえば、数万のメンバーを含む HASH キーを複数に分割します。キーをハッシュし、各キーのメンバーの数が適切な範囲内であることを確認します。Redis クラスター構造では、大きなキーの分割がノード間のメモリ バランスに重要な役割を果たす可能性があります。

    大きなキーの非同期クリーンアップ

    Redis は 4.0 以降、非ブロック的な方法で受信キーをゆっくりと段階的にクリーンアップできる UNLINK コマンドを提供しています。UNLINK を通じて、安全に削除できます。ラージ キーまたはエクストラ ラージ キーです。

    概要

    次のチェックリストは、Redis のパフォーマンスの低下が発生した場合に問題を効率的に解決するのに役立ちます。

    Redis の現在のベースライン パフォーマンスを取得する;

    遅いコマンドの監視を有効にし、遅いコマンドによって引き起こされる問題を特定する;

    遅いコマンドを見つけてスキャンを使用する;

    大きすぎる RDB ファイルのロードによるマスター/スレーブ レプリケーションのブロックを避けるために、インスタンスのデータ サイズを 2 ~ 4GB に制御します;

    メモリ ラージ ページを無効にし、メモリ ラージ ページを使用します。クライアントの変更 データはわずか 50B のデータであり、Redis は 2MB の大きなページをコピーする必要があります。大量の命令を記述するとコピーが大量に発生し、パフォーマンスが低下します。

    Redis によって使用されるメモリが大きすぎてスワップが発生するかどうか;

    AOF 構成が適切であるかどうか、構成項目 no-appendfsync-on-rewrite を yes に設定して AOF を回避できます。再書き込みと fsync がディスク IO リソースをめぐって競合するため、Redis の遅延が増加します。

    Bigkey は一連の問題を引き起こすため、bigkey が表示されないように分割し、UNLINK を通じて非同期に削除する必要があります。

    推奨学習: Redis 学習チュートリアル

    以上がRedis が突然遅くなりましたか? Redis にパフォーマンスの問題があるかどうかを判断する方法とその解決方法を分析してみましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:苏三说技术公众号
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート