首頁  >  文章  >  資料庫  >  Redis優化實例分析

Redis優化實例分析

WBOY
WBOY轉載
2023-06-01 08:38:05650瀏覽

記憶體維度

控制key的長度

key的一般都是採用字串,而字串的底層資料結構為SDS,SDS 結構中會包含字串長度、分配空間大小等元資料訊息,當key字串的長度增加時,SDS中的元資料也會佔用更多記憶體空間,為了減少key的佔用空間,我們可用根據業務名來使用對應的英文縮寫來表示。例如user用u表示,message 用m來表示。

避免儲存bigkey

我們既要注意key的長度,同時也需要關注value的大小,Redis是使用單線程讀寫數據,bigkey 的讀寫操作會阻塞線程,降低Redis的處理效率。

如何查詢bigkey

我們可以透過--bigkey的命令來查看Redis中所佔用的bigkey的信息,具體的命令如下:

redis-cli -h 127.0.0.1 -p 6379 -a 'xxx' --bigkeys

Redis優化實例分析

從上述圖所示,我們可以查看到Redis中的key佔用了32098個bytes,需要進行相關優化的。

建議:

  • 如果key為string類型,建議value的存放值的大小為10KB左右。

  • 如果key為List/Hash/Set/ZSet類型,建議存放元素的數量控制在1萬以下的。

選擇合適的資料類型

Redis針對所儲存的資料類型進行了最佳化,同時也對記憶體進行了對應的最佳化。關乎數據結果的相關知識,可以參考先前的文章。

例如:String和set在儲存int資料時,會採用整數編碼儲存。 Hash、ZSet在元素數量比較少時,會採用壓縮列表(ziplist)存儲,在存儲比較多的數據時,才會轉換為哈希表和跳表。

採用高效的序列化和壓縮方法

Redis中的字串都是使用二進位安全的位元組陣列來保存的,所以我們可以把業務的序列化成二進位寫入Redis ,但是採用不同的序列化,所佔用的空間大少不一樣。 Protostuff的序列化比Java內建的序列化更有效率,且佔用的空間更少。為了減少空間佔用,我們可以對JSON和XML資料格式進行壓縮存儲,可選的壓縮演算法包括Gzip和Snappy。

設定Redis最大記憶體和淘汰策略

我們根據業務的資料量提前預估記憶體大小,從而避免Redis的記憶體持續膨脹,導致佔用過多資源。

關於如何設定淘汰策略,需要集合實際的業務特性來選擇:

  • #volatile-lru / allkeys-lru: 優先保留最近訪問過的資料

  • volatile-lfu / allkeys-lfu:優先保留存取次數最頻繁的資料

  • #volatile-ttl :優先淘汰即將過期的資料

  • volatile-random / allkeys-random:隨機淘汰資料

控制Redis實例的大小

Redis單一實例的記憶體大小建議設定在2~6GB之間。由於RDB快照和主從叢集資料同步都能快速完成,因此不會阻塞正常請求的處理。

定時清除記憶體碎片

頻繁的新增修改會導致記憶體碎片的增多,因此需要及時清理記憶體碎片。

Redis提供了Info memory指令可以查看記憶體使用訊息,如下:

Redis優化實例分析

##說明:

  • used_memory_rss是作業系統實際分配給Redis的實體記憶體空間。

  • used_memory 是 Redis 為了保存資料實際申請使用的空間。

  • mem_fragmentation_ratio=used_memory_rss/ used_memory

  • mem_fragmentation_ratio 大於1但小於1.5。這種情況是合理的。

  • 如果mem_fragmentation_ratio大於1.5,表示記憶體碎片率已經達到50%以上。在這種情況下,通常需要採取一些措施來減少記憶體碎片率。具體的記憶體清理措施,將在後續的文章中進行講解。

效能維度

禁止使用KEYS、FLUSHALL、FLUSHDB指令

  • KEYS 依照key內容進行匹配,傳回符合匹配條件的鍵值對,此指令需要對Redis的全域雜湊表進行全表掃描,嚴重阻塞Redis主執行緒。

  • FLUSHALL 刪除Redis實例上的所有數據,如果資料量很大,會嚴重阻塞Redis主執行緒。

  • FLUSHDB,刪除目前資料庫中的數據,如果資料量很大,會阻塞Redis主執行緒。

優化建議
我們需要在線上要停用這些命令。具體的做法是,管理者採用rename-command指令在設定檔中對這些指令進行重新命名,讓客戶端無法使用這些指令。

慎用全量操作的命令

对于集合类型的来说,在未清楚集合数据大小的情况下,慎用查询集合中的全量数据,例如Hash的HetALL、Set的SMEMBERS命令、LRANGE key 0 -1 或者ZRANGE key 0 -1等命令,因为这些命令会对Hash或者Set类型的底层数据进行全量扫描,当集合数据量比较大时,会阻塞Redis的主线程。

优化建议:

当元素数据量较多时,可以用SSCAN、HSCAN 命令分批返回集合中的数据,减少对主线程的阻塞。

慎用复杂度过高命令

Redis执行复杂度过高的命令,会消耗更多的 CPU 资源,导致主线程中的其它请求只能等待。常见的复杂命令如下:SORT、SINTER、SINTERSTORE、ZUNIONSTORE、ZINTERSTORE 等聚合类命令。

优化建议:

当需要执行排序、交集、并集操作时,可以在客户端完成,避免让Redis进行过多计算,从而影响Redis性能。

设置合适的过期时间

Redis通常用于保存热数据。热数据一般都有使用的时效性。因此,在数据存储的过程中,应根据业务对数据的使用时间合理地设置数据的过期时间。否则写入Redis的数据会一直占用内存,如果数据持续增增长,会达到机器的内存上限,造成内存溢出,导致服务崩溃。

采用批量命令代替个命令

当我们需要一次性操作多个key时,可以使用批量命令来处理,批量命令可以减少客户端与服务端的来回网络IO次数。

  • String或者Hash类型可以使用 MGET/MSET替代 GET/SET,HMGET/HMSET替代HGET/HSET

  • 其它数据类型使用Pipeline命令,一次性打包发送多个命令到服务端执行。

Pipeline具体使用:
redisTemplate.executePipelined(new RedisCallback<String>() {
            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
                for (int i = 0; i < 5; i++) 
                {
                    connection.set(("test:" + i).getBytes(), "test".getBytes());
                }
                return null;
            }
        });

高可用维度

按照业务部署不同的实例

不同的业务线来部署 Redis 实例,这样当其中一个实例发生故障时,不会影响到其它业务。

避免单点问题

业务上根据实际情况采用主从、哨兵、集群方案,避免单点故障,影响业务的正常使用。

合理的设置相关参数

针对主从环境,我们需要合理设置相关参数,具体内容如下:

  • 合理的设置repl-backlog参数:如果repl-backlog设置过小,当写流量比较大的场景下,主从复制中断可能会引发全量复制数据的风险。

  • 合理设置slave client-output-buffer-limit:当从库复制发生问题时,过小的 buffer会导致从库缓冲区溢出,从而导致复制中断。

以上是Redis優化實例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除