Redis 通常是我們業務系統中重要的元件,例如:快取、帳號登入資訊、排行榜等。
一旦 Redis 請求延遲增加,可能就會導致業務系統「雪崩」。
我在單身紅娘婚戀類型網路公司工作,在雙十一推出下單就送女友的活動。
誰曾想,凌晨 12 點以後,用戶量暴增,出現了一個技術故障,用戶無法下單,當時老大火冒三丈!
經過查找發現 Redis 報 Could not get a resource from the pool
。
取得不到連線資源,且叢集中的單一 Redis 連線量很高。
大量的流量沒了Redis 的快取回應,直接打到了MySQL,最後資料庫也宕機了…
於是各種更改最大連線數、連線等待數,雖然報錯訊息頻率有所緩解,但還是持續報錯。
後來經過線下測試,發現存放 Redis 中的字元資料很大,平均 1s 回傳資料。
可以發現,一旦 Redis 延遲過高,會引發各種問題。
今天跟大家一起來分析下如何確定 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
來連接服務端,如果想要監控網路對 Redis 的效能影響,可以使用 Iperf 測量客戶端到服務端的網路延遲。
若網路延遲達到幾百毫秒,可能表示其他高流量程式運作導致網路擁塞,需聯絡維運人員協調網路流量分配。
慢指令監控
如何判斷是否為慢指令?
看操作複雜度是否是O(N)。官方文件對每個指令的複雜度都有介紹,盡可能使用O(1) 和 O(log N)指令。
涉及到集合運算的複雜度一般為O(N),例如集合全量查詢HGETALL、SMEMBERS,以及集合的聚合操作:SORT、LREM、 SUNION等。
有監控資料可以觀測呢?程式碼不是我寫的,不知道有沒有人用了慢指令。
有兩種方式可以排查到:
使用Redis 慢日誌功能查出慢指令;
latency-monitor(延遲監控)工具。
此外,可以使用自己(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-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 实例的内存压力很大,很有可能会变慢。
解决方案
增加机器内存;
将 Redis 放在单独的机器上运行,避免在同一机器上运行需要大量内存的进程,从而满足 Redis 的内存需求;
增加 Cluster 集群的数量分担数据量,减少每个实例所需的内存。
AOF 和磁盘 I/O 导致的延迟
为了保证数据可靠性,Redis 使用 AOF 和 RDB 快照实现快速恢复和持久化。
可以使用 appendfsync 配置将 AOF 配置为以三种不同的方式在磁盘上执行 write 或者 fsync (可以在运行时使用 CONFIG SET命令修改此设置,比如:redis-cli CONFIG SET appendfsync no)。
no:Redis 不执行 fsync,唯一的延迟来自于 write 调用,write 只需要把日志记录写到内核缓冲区就可以返回。
everysec:Redis 每秒执行一次 fsync。使用后台子线程异步完成 fsync 操作。最多丢失 1s 的数据。
always:每次写入操作都会执行 fsync,然后用 OK 代码回复客户端(实际上 Redis 会尝试将同时执行的许多命令聚集到单个 fsync 中),没有数据丢失。建议使用能够快速执行 fsync 并搭配快速的磁盘的文件系统实现,因为在这种模式下性能通常非常低。
我们通常将 Redis 用于缓存,数据丢失完全恶意从数据获取,并不需要很高的数据可靠性,建议设置成 no 或者 everysec。
除此之外,避免 AOF 文件过大, Redis 会进行 AOF 重写,生成缩小的 AOF 文件。
可以把配置项 no-appendfsync-on-rewrite设置为 yes,表示在 AOF 重写时,不进行 fsync 操作。
也就是说,Redis 实例把写命令写到内存后,不调用后台线程进行 fsync 操作,就直接返回了。
expires 淘汰过期数据
Redis 有两种方式淘汰过期数据:
惰性删除:当接收请求的时候发现 key 已经过期,才执行删除;
定时删除:每 100 毫秒删除一些过期的 key。
定时删除的算法如下:
随机采样 ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP个数的 key,删除所有过期的 key;
如果发现还有超过 25% 的 key 已过期,则执行步骤一。
ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP默认设置为 20,每秒执行 10 次,删除 200 个 key 问题不大。
如果觸發了第二條,就會導致 Redis 一致在刪除過期資料去釋放記憶體。而刪除是阻塞的。
觸發條件是什麼呀?
也就是大量的 key 設定了相同的時間參數。需要多次重複刪除才能將過期鍵的數量降至低於 25%。這些鍵在同一秒內大量過期。
簡而言之:大量同時到期的 key 可能會導致效能波動。
解
如果一批key 的確是同時過期,可以在EXPIREAT 和EXPIRE 的過期時間參數上,加上一個一定大小範圍內的隨機數,這樣,既保證了key 在一個鄰近時間範圍內被刪除,又避免了同時過期造成的壓力。
bigkey
通常我們會將含有較大資料或含有大量成員、清單數的Key 稱之為大Key,下面我們將用幾個實際的範例對大Key 的特徵進行描述:
一個STRING 類型的Key,它的值為5MB(資料過大)
一個LIST 類型的Key,它的清單數量為10000 個(清單數量過多)
一個ZSET 類型的Key,它的成員數量為10000 個(成員數量過多)
一個HASH 格式的Key,它的成員數量雖然只有1000 個但這些成員的value 總大小為10MB(成員體積過大)
#bigkey 帶來問題如下:
Redis 記憶體不斷變大引發OOM,或是達到maxmemory 設定值引發寫阻塞或重要Key 被逐出;
#Redis Cluster 中的某個node 記憶體遠超其餘node,但因Redis Cluster 的資料遷移最小粒度為Key 而無法將node 上的記憶體均衡化;
#bigkey 的讀取請求佔用過大頻寬,自身變慢的同時影響到該伺服器上的其它服務;
刪除一個bigkey 造成主庫較長時間的阻塞並引發同步中斷或主從切換;
尋找bigkey
#使用redis-rdb-tools 工具以客製化方式找出大Key。
解
對大key 拆分
如將一個含有數萬成員的HASH Key 拆分為多個HASH Key,並確保每個Key 的成員數量在合理範圍,在Redis Cluster 結構中,大Key 的拆分對node 間的記憶體平衡能夠起到顯著作用。
非同步清理大key
Redis 自4.0 起提供了UNLINK 指令,該指令能夠以非阻塞的方式緩慢逐步的清理傳入的Key,透過UNLINK,你可以安全的刪除大Key 甚至特大Key。
以上是怎麼確定Redis有效能問題及如何解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Redis和SQL數據庫的主要區別在於:Redis是內存數據庫,適用於高性能和靈活性需求;SQL數據庫是關係型數據庫,適用於復雜查詢和數據一致性需求。具體來說,1)Redis提供高速數據訪問和緩存服務,支持多種數據類型,適用於緩存和實時數據處理;2)SQL數據庫通過表格結構管理數據,支持複雜查詢和事務處理,適用於電商和金融系統等需要數據一致性的場景。

REDISACTSASBOTHADATASTOREANDASERVICE.1)ASADATASTORE,ITUSESIN-MEMORYSTOOGATOFORFOFFASTESITION,支持VariousDatharptructuresLikeKey-valuepairsandsortedsetsetsetsetsetsetsets.2)asaservice,ItprovidespunctionslikeItionitionslikepunikeLikePublikePublikePlikePlikePlikeAndluikeAndluAascriptingiationsmpleplepleclexplectiations

Redis與其他數據庫相比,具有以下獨特優勢:1)速度極快,讀寫操作通常在微秒級別;2)支持豐富的數據結構和操作;3)靈活的使用場景,如緩存、計數器和發布訂閱。選擇Redis還是其他數據庫需根據具體需求和場景,Redis在高性能、低延遲應用中表現出色。

Redis在數據存儲和管理中扮演著關鍵角色,通過其多種數據結構和持久化機製成為現代應用的核心。 1)Redis支持字符串、列表、集合、有序集合和哈希表等數據結構,適用於緩存和復雜業務邏輯。 2)通過RDB和AOF兩種持久化方式,Redis確保數據的可靠存儲和快速恢復。

Redis是一種NoSQL數據庫,適用於大規模數據的高效存儲和訪問。 1.Redis是開源的內存數據結構存儲系統,支持多種數據結構。 2.它提供極快的讀寫速度,適合緩存、會話管理等。 3.Redis支持持久化,通過RDB和AOF方式確保數據安全。 4.使用示例包括基本的鍵值對操作和高級的集合去重功能。 5.常見錯誤包括連接問題、數據類型不匹配和內存溢出,需注意調試。 6.性能優化建議包括選擇合適的數據結構和設置內存淘汰策略。

Redis在現實世界中的應用包括:1.作為緩存系統加速數據庫查詢,2.存儲Web應用的會話數據,3.實現實時排行榜,4.作為消息隊列簡化消息傳遞。 Redis的多功能性和高性能使其在這些場景中大放異彩。

Redis脫穎而出是因為其高速、多功能性和豐富的數據結構。 1)Redis支持字符串、列表、集合、散列和有序集合等數據結構。 2)它通過內存存儲數據,支持RDB和AOF持久化。 3)從Redis6.0開始引入多線程處理I/O操作,提升了高並發場景下的性能。

RedisisclassifiedasaNoSQLdatabasebecauseitusesakey-valuedatamodelinsteadofthetraditionalrelationaldatabasemodel.Itoffersspeedandflexibility,makingitidealforreal-timeapplicationsandcaching,butitmaynotbesuitableforscenariosrequiringstrictdataintegrityo


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

記事本++7.3.1
好用且免費的程式碼編輯器

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器