自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

替你踩過Redis緩存的坑,奉上使用規(guī)范和監(jiān)控方法

數(shù)據(jù)庫 其他數(shù)據(jù)庫 Redis
在互聯(lián)網(wǎng)應(yīng)用中,緩存成為高并發(fā)架構(gòu)的關(guān)鍵組件。本文主要介紹緩存使用的典型場景、實操案例分析、Redis使用規(guī)范及常規(guī)Redis監(jiān)控。

 一、前言

在互聯(lián)網(wǎng)應(yīng)用中,緩存成為高并發(fā)架構(gòu)的關(guān)鍵組件。本文主要介紹緩存使用的典型場景、實操案例分析、Redis使用規(guī)范及常規(guī)Redis監(jiān)控。

二、常見緩存對比

常見的緩存方案:本地緩存包括HashMap/ConcurrentHashMap、Ehcache、Memcache、Guava Cache等,緩存中間件包括Redis、Tair等。

三、Redis使用場景

1、計數(shù)

Redis實現(xiàn)快速計數(shù)及緩存功能。

例如:視頻或直播在線觀看人數(shù),用戶每播放一次,就會自增1。

2、Session集中管理

Session可以存儲在應(yīng)用服務(wù)是JVM中,但這一種方案會有一致性的問題,還有高并發(fā)下,會引發(fā)JVM內(nèi)存溢出。Redis將用戶的Session集中管理,這種情況下只要保證Redis的高可用和擴(kuò)展性,每次用戶更新或查詢登錄都直接從Redis中信息獲取。

3、限速

例如:高并發(fā)的秒殺活動,使用incrby命令實現(xiàn)原子性遞增。

例如:業(yè)務(wù)要求用戶一分鐘內(nèi),只能獲取5次驗證碼。

4、排行榜

關(guān)系型數(shù)據(jù)庫在排行榜方面查詢速度普遍偏慢,所以可以借助redis的SortedSet進(jìn)行熱點數(shù)據(jù)的排序。

比如在項目中,如果需要統(tǒng)計主播的吸金排行榜,可以以主播的id作為member, 當(dāng)天打賞的活動禮物對應(yīng)的熱度值作為 score, 通過zrangebyscore就可以獲取主播活動日榜。

5、分布式鎖

在實際的多進(jìn)程并發(fā)場景下,使用分布式鎖來限制程序的并發(fā)執(zhí)行。多用于防止高并發(fā)場景下,緩存被擊穿的可能。

分布式鎖的實際就是"占坑",當(dāng)另一個進(jìn)程來執(zhí)行setnx時,發(fā)現(xiàn)標(biāo)識位已經(jīng)為1,只好放棄或者等待。

四、案例解析

1、過期設(shè)置- set命令會去掉過期時間

Redis所有的數(shù)據(jù)結(jié)構(gòu),都可以設(shè)置過期時間。如果一個字符串已經(jīng)設(shè)置了過期時間,然后重新設(shè)置它,會導(dǎo)致過期時間消失。所以在項目中需要合理評估Redis容量,避免因為頻繁set導(dǎo)致沒有過期策略,間接導(dǎo)致內(nèi)存被占滿。

如下是 Redis 源碼截圖:

2、Jedis 2.9.0及以下版本過期設(shè)置BUG

發(fā)現(xiàn)Jedis在進(jìn)行expiredAt命令調(diào)用時有bug,最終調(diào)用的是pexpire命令,這個bug會導(dǎo)致key過期時間很長,導(dǎo)致Redis內(nèi)存溢出等問題。建議升級到Jedis 2.9.1及以上版本。

BinaryJedisCluster.java源碼如下: 

  1. @Override  
  2.   public Long pexpireAt(final byte[] key, final long millisecondsTimestamp) {  
  3.     return new JedisClusterCommand<Long>(connectionHandler, maxAttempts) {  
  4.       @Override  
  5.       public Long execute(Jedis connection) {  
  6.         return connection.pexpire(key, millisecondsTimestamp); //此處pexpire應(yīng)該是pexpireAt  
  7.       }  
  8.     }.runBinary(key);  
  9.   } 

對比pexpire和pexpireAt:

比如我們當(dāng)前使用的時間是2018-06-14 17:00:00,它的unix時間戳為1528966800000毫秒,當(dāng)我們使用PEXPIREAT命令時,由于是過去的時間,相應(yīng)的key會立即過期。

而我們誤用了PEXPIRE命令時,key不會立即過期,而是等到1528966800000毫秒后才過期,key過期時間會相當(dāng)長,約幾W天后,從而可能導(dǎo)致Redis內(nèi)存溢出、服務(wù)器崩潰等問題。

3、緩存被擊穿

緩存的key有過期策略,如果恰好在這個時間點對這個Key有大量的并發(fā)請求,這些請求發(fā)現(xiàn)緩存過期一般都會從后端DB回源數(shù)據(jù)并回設(shè)到緩存,這個時候大并發(fā)的請求可能會瞬間把后端DB壓掛。

業(yè)界常用優(yōu)化方案有兩種:

  •  第一種:使用分布式鎖,保證高并發(fā)下,僅有一個線程能回源后端DB;
  •  第二種:保證高并發(fā)的請求到的Redis key始終是有效的,使用非用戶請求回源后端,改成主動回源。一般可以使用異步任務(wù)進(jìn)行緩存的主動刷新。

4、Redis-standalone架構(gòu)禁止使用非0庫

Redis執(zhí)行命令select 0和select 1切換,造成性能損耗。

RedisTemplate在執(zhí)行execute方法的時候會先獲取鏈接。

執(zhí)行到RedisConnectionUtils.java,會有一段獲取鏈接的方法。

JedisConnectionFactory.java 會調(diào)用

JedisConnection構(gòu)造器,注意這邊的dbIndex就是數(shù)據(jù)庫編號,如:1

繼續(xù)跟進(jìn)JedisConnection代碼,當(dāng)選擇庫大于1時,會有select db操作。如果一直使用0庫是不需要額外執(zhí)行切庫命令的。知道了第一個切庫select 1的地方,那么select 0是哪來的呢?

其實客戶端使用Redis也會是要釋放鏈接的,只不過RedisTemplate已經(jīng)幫我們自動釋放了,讓我們再回到一開始RedisTemplate執(zhí)行execute(...)方法的地方。

下面還是RedisConnectionUtils.java,執(zhí)行鏈接關(guān)閉的代碼。

按代碼注釋的意思,如果選擇庫編號不為0,spring-data-redis框架每次都會執(zhí)行重置select 0!

筆者在vivo商城業(yè)務(wù)中,商品詳情頁接口經(jīng)過上面的調(diào)優(yōu),性能提高了3倍多。

進(jìn)一步驗證數(shù)據(jù)庫切換至少影響性能3倍左右(視具體業(yè)務(wù)而定)。

Rediscluster集群數(shù)據(jù)庫,默認(rèn)0庫,無法選擇其他數(shù)據(jù)庫,也就避免了這個問題。

5、當(dāng)心時間復(fù)雜度o(n)Redis命令

Redis是單線程的,所以線程安全的。

Redis使用非阻塞IO,并且大部分命令的時間復(fù)雜度O(1)。

使用高耗時的命令是非常危險的,會占用唯一的一個線程的大量處理時間,導(dǎo)致所有的請求都被拖慢。

例如:獲取所有set集合中的元素 smembers myset,返回指定Hash中所有的member,時間復(fù)雜度O(N)。

緩存的Value集合變大,當(dāng)高并接口請求時,會從Redis讀取相關(guān)數(shù)據(jù),每個請求讀取的時間變長,不斷的疊加,導(dǎo)致出現(xiàn)熱點KEY情況,Redis某個分片處于阻塞,CPU使用率達(dá)到100%。

6、緩存熱key

在Redis中,訪問頻率高的key稱為熱點key,當(dāng)某一熱點key的請求到Server主機(jī)時,由于請求量特別大,導(dǎo)致主機(jī)資源不足,甚至宕機(jī),影響正常的服務(wù)。

熱key問題的產(chǎn)生,有如下兩種原因:

  •  用戶消費的數(shù)據(jù)遠(yuǎn)大于生產(chǎn)的數(shù)據(jù),比如熱賣商品或秒殺商品、熱點新聞、熱點評論等,這些典型的讀多寫少的場景會產(chǎn)生熱點問題;
  •  請求分片集中,超過單Server的性能極限,比如 固定名稱key,哈希落入一臺Server,訪問量極大的情況,超過Server極限時,就會導(dǎo)致熱點Key問題的產(chǎn)生。

那么在實際業(yè)務(wù)中,如何識別到熱點key呢?

  •  憑借業(yè)務(wù)經(jīng)驗,進(jìn)行預(yù)估哪些是熱key;
  •  客戶端統(tǒng)計收集,本地統(tǒng)計或者上報;
  •  如果服務(wù)端有代理層,可以在代理層進(jìn)行收集上報。

當(dāng)我們識別到熱key,如何解決熱key問題?

  •  Redis集群擴(kuò)容:增加分片副本,均衡讀流量;
  •  進(jìn)一步對熱key進(jìn)行散列,比如將一個key備份為key1,key2……keyN,同樣的數(shù)據(jù)N個備份,N個備份分布到不同分片,訪問時可隨機(jī)訪問N個備份中的一個,進(jìn)一步分擔(dān)讀流量;
  •  使用二級緩存,即本地緩存。

當(dāng)發(fā)現(xiàn)熱key后,將熱key對應(yīng)數(shù)據(jù)首先加載到應(yīng)用服務(wù)器本地緩存中,減少對Redis的讀請求。

五、Redis規(guī)范

1、禁止使用非database 0

說明:

Redis-standalone架構(gòu),禁止使用Redis中的其他database。

原由:

  •  為以后業(yè)務(wù)遷移 Redis Cluster 保持兼容性;
  •  多個 database 用 select 切換時,更消耗CPU資源;
  •  更易自動化運維管理,如 scan/dbsize 命令只用于當(dāng)database;
  •  部分 Redis Clients 因線程安全問題,不支持單實例多 database。

2、Key設(shè)計規(guī)范

按業(yè)務(wù)功能命名key前綴,防止key沖突覆蓋,推薦 用冒號分隔,例如,業(yè)務(wù)名:表名:id:,如 live:rank:user:weekly:1:202003。

Key的長度小于30個字符,Key名字本身是String對象,Redis硬編碼限制最大長度512MB。

在Redis緩存場景,推薦Key都設(shè)置TTL值,保證不使用的Key能被及時清理或淘汰。

Key設(shè)計時禁止包含特殊字符,如空格、換行、單雙引號以及其他轉(zhuǎn)義字符。

3、Value設(shè)計規(guī)范

單個Value大小必須控制10KB以內(nèi),單實例鍵個數(shù)過大,可能導(dǎo)致過期鍵的回收不及時。

set、hash、list等復(fù)雜數(shù)據(jù)類型,要盡量降低數(shù)據(jù)結(jié)構(gòu)中的元素個數(shù),建議個數(shù)不要超過1000。

4、關(guān)注命令時間復(fù)雜度

推薦使用O(1)命令,如get scard等。

O(N)命令關(guān)注N的數(shù)量,如下命令需要對N值在業(yè)務(wù)層面做控制。

  •  hgetall
  •  lrange
  •  smembers
  •  zrange

例如:smember命令時間復(fù)雜度為O(n),當(dāng)n持續(xù)增加時,會導(dǎo)致 Redis CPU 持續(xù)飆高,阻塞其他命令的執(zhí)行。

5、Pipeline使用

說明:Pipeline是Redis批量提交的一種方式,也就是把多個命令操作建立一次連接發(fā)給Redis去執(zhí)行,會比循環(huán)的單次提交性能更優(yōu)。

Redis客戶端執(zhí)行一條命令分4個過程:發(fā)送命令 -> 命令排隊 ->命令執(zhí)行 -> 返回結(jié)果。

常用的mget、mset命令,有效節(jié)約RTT(命令執(zhí)行往返時間),但hgetall并沒有mhgetall,是不支持批量操作的。此時,需要使用Pipeline命令

例如:直播中臺項目中,需要同時查詢主播日、周、月排行榜,使用PIPELINE一次提交多個命令,同時返回三個榜單數(shù)據(jù)。

6、線上禁用命令

  •  禁止使用Monitor

    禁止生產(chǎn)環(huán)境使用monitor命令,monitor命令在高并發(fā)條件下,會存在內(nèi)存暴增和影響Redis性能的隱患

  •  禁止使用Keys

    keys操作是遍歷所有的key,如果key非常多的情況下導(dǎo)致慢查詢,會阻塞其他命令。所以禁止使用keys及keys pattern命令。

    建議線上使用scan命令代替keys命令。

  •  禁止使用Flushall、Flushdb

           刪除Redis中所有數(shù)據(jù)庫中的所有記錄,并且該命令是原子性的,不會終止執(zhí)行,一旦執(zhí)行,將不會執(zhí)行失敗。

  •  禁止使用Save

          阻塞當(dāng)前redis服務(wù)器,直到持久化操作完成為止,對于內(nèi)存較大的實例會造成長時間的阻塞

  •  BGREWRITEAOF

          手動AOF,手動持久化對于內(nèi)存較大的實例會造成長時間的阻塞

  •  Config

          Config是客戶端配置方式,不利于Redis運維。建議在Redis配置文件中設(shè)置。

六、Redis監(jiān)控

1、慢查詢

方法一:slowlog獲取慢查詢?nèi)罩?nbsp;

  1. 127.0.0.1:{port}> slowlog get 5  
  2. 1) 1) (integer) 47  
  3.    2) (integer) 1533810300  
  4.    3) (integer) 175833  
  5.    4) 1) "DEL"  
  6.       2) "spring:session:expirations:1533810300000"  
  7. 2) 1) (integer) 46  
  8.    2) (integer) 1533810300  
  9.    3) (integer) 117400  
  10.    4) 1) "SMEMBERS" 

方法二:更全面的慢查詢可以通過CacheCloud工具監(jiān)控。

路徑:"應(yīng)用列表"-點擊相關(guān)應(yīng)用名-點擊"慢查詢"Tab頁。

點擊"慢查詢",重點關(guān)注慢查詢個數(shù)及相關(guān)命令。

2、監(jiān)控Redis實例綁定的CPU核心使用率

由于Redis是單線程,重點監(jiān)控Redis實例綁定的CPU核心使用率。

一般CPU資源使用率為10%左右,如果使用率高于20%時,考慮是否使用了RDB持久化。

3、Redis分片負(fù)載均衡

當(dāng)前redis-cluster架構(gòu)模式,3個master和3個Slave組成的集群,關(guān)注 Redis-cluster每個分片requests流量均衡情況;

通過命令獲?。?/p>

  1. redis-cli -p{port} -h{host} --stat 

一般情況,超過12W需要告警。

4、關(guān)注大key BigKey

通過Redis提供的工具,redis-cli定時掃描相應(yīng)Redis大Key,進(jìn)行優(yōu)化。

具體命令如下: 

  1. redis-cli -h 127.0.0.1 -p {port} --bigkeys 

或 

  1. redis-memory-for-key -s {IP} -p {port} XXX_KEY 

一般超過10K為大key,需要重點關(guān)注,建議從業(yè)務(wù)層面優(yōu)化。

5、監(jiān)控Redis占用內(nèi)存大小

Info memory 命令查看,避免在高并發(fā)場景下,由于分配的MaxMemory被耗盡,帶來的性能問題。

重點關(guān)注 used_memory_human 配置項對應(yīng)的value值,增量過高時,需要重點評估。

七、總結(jié)

結(jié)合具體業(yè)務(wù)特性,合理評估Redis所需內(nèi)存容量、選擇數(shù)據(jù)類型、設(shè)置單key大小,才能更好地服務(wù)于業(yè)務(wù),為業(yè)務(wù)提供高性能的保障。

 

責(zé)任編輯:龐桂玉 來源: DBAplus社群
相關(guān)推薦

2024-05-06 00:00:00

緩存高并發(fā)數(shù)據(jù)

2024-04-01 08:05:27

Go開發(fā)Java

2017-07-17 15:46:20

Oracle并行機(jī)制

2018-09-11 09:14:52

面試公司缺點

2023-03-13 13:36:00

Go擴(kuò)容切片

2025-04-29 10:17:42

2015-03-24 16:29:55

默認(rèn)線程池java

2022-04-26 21:49:55

Spring事務(wù)數(shù)據(jù)庫

2019-12-12 14:32:26

SQL語句數(shù)據(jù)庫

2018-01-10 13:40:03

數(shù)據(jù)庫MySQL表設(shè)計

2019-10-30 14:44:41

Prometheus開源監(jiān)控系統(tǒng)

2018-08-01 14:45:16

PHP編程語言

2025-04-15 02:00:00

API版本項目

2019-09-25 15:30:15

2024-06-26 10:37:05

2022-07-06 11:47:27

JAVAfor循環(huán)

2018-04-08 22:16:21

2014-03-09 23:29:12

2018-01-10 06:17:24

2015-07-07 10:39:02

點贊
收藏

51CTO技術(shù)棧公眾號