Dieser Artikel bringt Ihnen relevantes Wissen über Redis. Lassen Sie uns analysieren, wie Sie feststellen können, ob es bei Redis zu Leistungsproblemen kommt.
Empfohlenes Lernen: Redis-Tutorial
Redis ist normalerweise eine wichtige Komponente in unserem Geschäftssystem, z. B. Cache, Kontoanmeldeinformationen, Rankings usw.
Sobald die Verzögerung der Redis-Anfrage zunimmt, kann es zu einer „Lawine“ des Geschäftssystems kommen.
Ich arbeite für ein Internetunternehmen vom Typ Single-Matchmaker. Während Double Eleven habe ich eine Kampagne gestartet, um meiner Freundin ein Geschenk zu machen, wenn ich eine Bestellung aufgegeben habe.
Wer hätte gedacht, dass nach 12 Uhr morgens die Zahl der Nutzer stark anstieg und es eine technische Panne gab, die Nutzer daran hinderte, Bestellungen aufzugeben. Damals brach der alte Brand aus!
Nach der Suche habe ich festgestellt, dass Redis gemeldet hat, dass Ressource nicht aus dem Pool abgerufen werden konnte
. Could not get a resource from the pool
。
获取不到连接资源,并且集群中的单台 Redis 连接量很高。
大量的流量没了 Redis 的缓存响应,直接打到了 MySQL,最后数据库也宕机了……
于是各种更改最大连接数、连接等待数,虽然报错信息频率有所缓解,但还是持续报错。
后来经过线下测试,发现存放 Redis 中的字符数据很大,平均 1s 返回数据。
可以发现,一旦 Redis 延迟过高,会引发各种问题。
今天跟大家一起来分析下如何确定 Redis 有性能问题和解决方案。
最大延迟是客户端发出命令到客户端收到命令的响应的时间,正常情况下 Redis 处理的时间极短,在微秒级别。
当 Redis 出现性能波动的时候,比如达到几秒到十几秒,这个很明显我们可以认定 Redis 性能变慢了。
有的硬件配置比较高,当延迟 0.6ms,我们可能就认定变慢了。硬件比较差的可能 3 ms 我们才认为出现问题。
那我们该如何定义 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 的服务端运行,而不是客户端。这样,可以避免网络对基线性能的影响。
可以通过 -h host -p port
Es kann festgestellt werden, dass eine zu hohe Latenz von Redis verschiedene Probleme verursacht. Lassen Sie uns heute mit Ihnen analysieren, wie Sie feststellen können, ob Redis Leistungsprobleme und Lösungen hat. Gibt es ein Problem mit der Redis-Leistung?Später wurde nach Offline-Tests festgestellt, dass die in Redis gespeicherten Zeichendaten sehr groß sind und die Daten im Durchschnitt in 1 Sekunde zurückgegeben werden.
Wenn die Leistung von Redis schwankt, beispielsweise einige Sekunden bis mehr als zehn Sekunden erreicht, können wir offensichtlich daraus schließen, dass sich die Leistung von Redis verlangsamt hat. Einige Hardwarekonfigurationen sind relativ hoch. Wenn die Verzögerung 0,6 ms beträgt, können wir sie als langsam betrachten. Wenn die Hardware relativ schlecht ist, kann es 3 ms dauern, bis wir denken, dass ein Problem vorliegt.Die maximale Verzögerung ist die Zeit von der Ausgabe eines Befehls durch den Client bis zum Empfang der Antwort auf den Befehl. Unter normalen Umständen ist die Verarbeitungszeit von Redis sehr kurz und liegt im Mikrosekundenbereich.
Wie sollten wir also definieren, ob Redis wirklich langsam ist?
redis-cli CONFIG SET slowlog-log-slower-than 6000
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"
-h host -p port
eine Verbindung zum Server herstellen. Wenn Sie die Auswirkungen des Netzwerks auf die Redis-Leistung überwachen möchten, können Sie Iperf verwenden, um die Netzwerkverzögerung vom Client zum zu messen Der Server. 🎜🎜Wenn das Netzwerk mehrere hundert Millisekunden verzögert ist, bedeutet dies, dass möglicherweise andere Programme mit hohem Datenverkehr im Netzwerk ausgeführt werden, was zu einer Überlastung des Netzwerks führt. Sie müssen einen Betrieb und eine Wartung finden, um die Verkehrsverteilung des Netzwerks zu koordinieren. 🎜🎜Überwachung langsamer Befehle🎜🎜🎜Wie kann man beurteilen, ob es sich um einen langsamen Befehl handelt? 🎜🎜🎜Überprüfen Sie, ob die Operationskomplexität O(N) ist. Die offizielle Dokumentation stellt die Komplexität jedes Befehls vor. Verwenden Sie so oft wie möglich die Befehle O(1) und O(log N). 🎜🎜Die Komplexität von Mengenoperationen ist im Allgemeinen O(N), wie z. B. vollständige Mengenabfragen HGETALL, SMEMBERS und Mengenaggregationsoperationen: SORT, LREM, SUNION usw. 🎜🎜🎜Gibt es Überwachungsdaten, die beobachtet werden können? Ich habe den Code nicht geschrieben. Ich weiß nicht, ob jemand langsame Anweisungen verwendet hat. 🎜🎜🎜Es gibt zwei Möglichkeiten zur Fehlerbehebung: 🎜🎜🎜🎜Verwenden Sie die Redis-Slow-Log-Funktion, um langsame Befehle zu erkennen; 🎜🎜🎜🎜latency-monitor (Latenzüberwachung). 🎜🎜🎜🎜Darüber hinaus können Sie sich selbst (top, htop, prstat usw.) verwenden, um schnell den CPU-Verbrauch des Redis-Hauptprozesses zu überprüfen. Wenn die CPU-Auslastung hoch ist, der Datenverkehr jedoch gering ist, deutet dies normalerweise darauf hin, dass langsame Befehle verwendet werden. 🎜慢日志功能
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 的数据读写由单线程执行,如果主线程执行的操作时间太长,就会导致主线程阻塞。
一起分析下都有哪些操作会阻塞主线程,我们又该如何解决?
网络通信导致的延迟
客户端使用 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-pipeline
慢指令导致的延迟
根据上文的慢指令监控查询文档,查询到慢查询指令。可以通过以下两种方式解决:
比如在 Cluster 集群中,将聚合运算等 O(N) 操作运行在 slave 上,或者在客户端完成。
使用高效的命令代替。使用增量迭代的方式,避免一次查询大量数据,具体请查看SCAN、SSCAN、HSCAN和ZSCAN命令。
除此之外,生产中禁用KEYS 命令,它只适用于调试。因为它会遍历所有的键值对,所以操作延时高。
Fork 生成 RDB 导致的延迟
生成 RDB 快照,Redis 必须 fork 后台进程。fork 操作(在主线程中运行)本身会导致延迟。
Redis 使用操作系统的多进程写时复制技术 COW(Copy On Write) 来实现快照持久化,减少内存占用。
写时复制技术保证快照期间数据可修改
但 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 实例的内存压力很大,很有可能会变慢。
解决方案
增加机器内存;
Führen Sie Redis auf einem separaten Computer aus, um zu vermeiden, dass Prozesse ausgeführt werden, die viel Speicher auf demselben Computer benötigen, um den Speicherbedarf von Redis zu decken.
Erhöhen Sie die Anzahl der Cluster-Cluster, um die Datenmenge zu teilen und den erforderlichen Speicher zu reduzieren jede Instanz.
Verzögerung durch AOF und Festplatten-E/A
Um die Datenzuverlässigkeit sicherzustellen, verwendet Redis AOF- und RDB-Snapshots, um eine schnelle Wiederherstellung und Persistenz zu erreichen.
Sie können die appendfsync-Konfiguration verwenden, um AOF so zu konfigurieren, dass auf der Festplatte auf drei verschiedene Arten geschrieben oder fsync ausgeführt wird (diese Einstellung kann zur Laufzeit mit dem Befehl CONFIG SET geändert werden, z. B.: redis-cli CONFIG SET appendfsync no).
Nein: Redis führt kein Fsync durch. Die einzige Verzögerung entsteht durch den Schreibaufruf, bei dem nur der Protokolldatensatz in den Kernelpuffer geschrieben werden muss.
everysec: Redis führt fsync einmal pro Sekunde aus. Verwenden Sie Hintergrund-Subthreads, um fsync-Vorgänge asynchron abzuschließen. Es gehen höchstens 1 Sekunde an Daten verloren.
immer: fsync wird bei jedem Schreibvorgang ausgeführt und dann wird dem Client mit einem OK-Code geantwortet (tatsächlich versucht Redis, viele gleichzeitig ausgeführte Befehle in einem einzigen fsync zusammenzufassen), es gehen keine Daten verloren. In diesem Modus ist die Leistung normalerweise sehr langsam, und es wird dringend empfohlen, schnelle Festplatten und Dateisystemimplementierungen zu verwenden, die fsync in kurzer Zeit ausführen können.
Wir verwenden normalerweise Redis für das Caching. Datenverlust ist völlig bösartig und erfordert keine hohe Datenzuverlässigkeit. Es wird empfohlen, es auf „Nein“ oder „Alle Sekunden“ einzustellen.
Um außerdem zu vermeiden, dass die AOF-Datei zu groß wird, schreibt Redis die AOF neu und generiert eine reduzierte AOF-Datei.
Sie können das Konfigurationselement no-appendfsync-on-rewrite auf „Ja“ setzen, was bedeutet, dass der Fsync-Vorgang beim Umschreiben von AOF nicht ausgeführt wird.
Mit anderen Worten: Nachdem die Redis-Instanz den Schreibbefehl in den Speicher geschrieben hat, kehrt sie direkt zurück, ohne den Hintergrundthread aufzurufen, um den Fsync-Vorgang auszuführen.
expires Abgelaufene Daten entfernen
Redis bietet zwei Möglichkeiten, abgelaufene Daten zu entfernen:
Verzögertes Löschen: Beim Empfang der Anfrage wird festgestellt, dass der Schlüssel abgelaufen ist, und dann wird der Löschvorgang durchgeführt;
Zeitgesteuertes Löschen: alle 100 Millisekunden, um einige abgelaufene Schlüssel zu löschen. 🔜
Wenn das zweite Element ausgelöst wird, führt dies dazu, dass Redis abgelaufene Daten konsequent löscht, um Speicher freizugeben. Und das Löschen blockiert.
Was sind die auslösenden Bedingungen?Das heißt, eine große Anzahl von Tasten ist mit den gleichen Zeitparametern eingestellt. In derselben Sekunde verfallen viele Schlüssel und müssen mehrmals gelöscht werden, um sie auf weniger als 25 % zu reduzieren.
Kurz gesagt: Eine große Anzahl gleichzeitig ablaufender Schlüssel kann zu Leistungsschwankungen führen.
Lösung
Wenn ein Schlüsselstapel gleichzeitig abläuft, können Sie den Ablaufzeitparametern von EXPIREAT und EXPIRE eine Zufallszahl innerhalb eines bestimmten Größenbereichs hinzufügen, um sicherzustellen, dass die Schlüssel ablaufen in der Nähe Es wird innerhalb des Zeitbereichs gelöscht und vermeidet gleichzeitig den durch den Ablauf verursachten Druck.
bigkey
Normalerweise bezeichnen wir Schlüssel, die große Datenmengen oder eine große Anzahl von Mitgliedern oder Listen enthalten, als große Schlüssel. Im Folgenden werden wir einige praktische Beispiele verwenden, um die Eigenschaften großer Schlüssel zu beschreiben:
EIN STRING Typ Schlüssel, sein Wert beträgt 5 MB (die Daten sind zu groß)
Ein Schlüssel vom Typ LIST, seine Anzahl der Listen beträgt 10000 (die Anzahl der Listen ist zu groß)
Ein Schlüssel vom Typ ZSET, seine Anzahl Mitglieder beträgt 10.000 (zu viele Mitglieder)
Ein Schlüssel im HASH-Format, obwohl die Anzahl seiner Mitglieder nur 1.000 beträgt, beträgt die Gesamtwertgröße dieser Mitglieder 10 MB (Mitgliedsgröße ist zu groß)
bigkey bringt das Folgende Probleme:
Der Redis-Speicher wächst weiter, was zu OOM führt oder den maxmemory-Einstellungswert erreicht, was zu Schreibblockaden oder der Entfernung wichtiger Schlüssel führt
Der Speicher eines bestimmten Knotens im Redis-Cluster übersteigt den anderer Knoten bei weitem, aber da die Mindestgranularität der Datenmigration im Redis-Cluster der Schlüssel ist, kann der Speicher auf dem Knoten nicht ausgeglichen werden.
Die Leseanforderung von Bigkey belegt zu viel Bandbreite. Wenn es langsamer wird, wirkt es sich auch auf andere Dienste auf dem Server aus
Lösung
Große Schlüssel aufteilen
Teilen Sie beispielsweise einen HASH-Schlüssel mit Zehntausenden von Mitgliedern in mehrere HASH-Schlüssel auf und stellen Sie sicher, dass die Anzahl der Mitglieder jedes Schlüssels in Redis innerhalb eines angemessenen Bereichs liegt Cluster In der Struktur kann die Aufteilung großer Schlüssel eine wichtige Rolle bei der Speicherbalance zwischen Knoten spielen. Asynchrone Reinigung großer SchlüsselRedis stellt seit 4.0 den UNLINK-Befehl zur Verfügung, der eingehende Schlüssel langsam und schrittweise auf nicht blockierende Weise bereinigen kann. Mit UNLINK können Sie große Schlüssel oder sogar besonders große Schlüssel sicher löschen.
Zusammenfassung
Die folgende Checkliste hilft Ihnen, das Problem effizient zu lösen, wenn Sie auf eine langsame Leistung von Redis stoßen.
Erhalten Sie die aktuelle Basisleistung von Redis.
Aktivieren Sie die Überwachung langsamer Befehle, um durch langsame Befehle verursachte Probleme zu lokalisieren.
Deaktivieren Sie große Speicherseiten und verwenden Sie große Speicherseiten. Selbst wenn die vom Client geänderten Daten nur 50 MB groß sind, muss Redis 2 MB kopieren riesige Seiten. Wenn eine große Anzahl von Anweisungen geschrieben wird, wird eine große Anzahl von Kopien verursacht, was zu einer langsameren Leistung führt.
Ob der von Redis verwendete Speicher zu groß ist, was zu Auslagerungen führt;
Unabhängig davon, ob die AOF-Konfiguration angemessen ist, können Sie das Konfigurationselement „no-appendfsync-on-rewrite“ auf „Ja“ setzen, um zu verhindern, dass AOF neu geschrieben und fsync um Festplatten-IO-Ressourcen konkurriert , was zu einer erhöhten Redis-Latenz führt.
bigkey wird eine Reihe von Problemen mit sich bringen. Wir müssen es aufteilen, um zu verhindern, dass bigkey angezeigt wird, und es asynchron über UNLINK löschen.
Empfohlenes Lernen:
Redis-LerntutorialDas obige ist der detaillierte Inhalt vonRedis wird plötzlich langsamer? Lassen Sie uns analysieren, wie Sie feststellen können, ob Redis Leistungsprobleme hat, und wie Sie diese lösen können. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!