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

Redis 很屌,不懂使用規(guī)范就糟蹋了

數(shù)據(jù)庫(kù) 其他數(shù)據(jù)庫(kù) Redis
通過(guò) Redis 為什么這么快?這篇文章我們知道 Redis 為了高性能和節(jié)省內(nèi)存費(fèi)勁心思。所以,只有規(guī)范的使用 Redis,才能實(shí)現(xiàn)高性能和節(jié)省內(nèi)存,否則再屌的 Redis 也禁不起我們瞎折騰。

碼哥,昨天我被公司 Leader 批評(píng)了。

我在單身紅娘婚戀類型互聯(lián)網(wǎng)公司工作,在雙十一推出下單就送女朋友的活動(dòng)。

誰(shuí)曾想,凌晨 12 點(diǎn)之后,用戶量暴增,出現(xiàn)了一個(gè)技術(shù)故障,用戶無(wú)法下單,當(dāng)時(shí)老大火冒三丈!

經(jīng)過(guò)查找發(fā)現(xiàn) Redis 報(bào) Could not get a resource from the pool。

獲取不到連接資源,并且集群中的單臺(tái) Redis 連接量很高。

于是各種更改最大連接數(shù)、連接等待數(shù),雖然報(bào)錯(cuò)信息頻率有所緩解,但還是持續(xù)報(bào)錯(cuò)。

后來(lái)經(jīng)過(guò)線下測(cè)試,發(fā)現(xiàn)存放 Redis 中的字符數(shù)據(jù)很大,平均 1s 返回?cái)?shù)據(jù)。

碼哥,可以分享下使用 Redis 的規(guī)范么?我想做一個(gè)唯快不破的真男人!

通過(guò) Redis 為什么這么快?這篇文章我們知道 Redis 為了高性能和節(jié)省內(nèi)存費(fèi)勁心思。

所以,只有規(guī)范的使用 Redis,才能實(shí)現(xiàn)高性能和節(jié)省內(nèi)存,否則再屌的 Redis 也禁不起我們瞎折騰。

Redis 使用規(guī)范圍繞如下幾個(gè)緯度展開(kāi):

  • 鍵值對(duì)使用規(guī)范;
  • 命令使用規(guī)范;
  • 數(shù)據(jù)保存規(guī)范;
  • 運(yùn)維規(guī)范。

鍵值對(duì)使用規(guī)范

有兩點(diǎn)需要注意:

  1. 好的 key 命名,才能提供可讀性強(qiáng)、可維護(hù)性高的 key,便于定位問(wèn)題和尋找數(shù)據(jù)。
  2. value要避免出現(xiàn) bigkey、選擇高效的序列化和壓縮、使用對(duì)象共享池、選擇高效恰當(dāng)?shù)臄?shù)據(jù)類型(可參考《Redis 實(shí)戰(zhàn)篇:巧用數(shù)據(jù)類型實(shí)現(xiàn)億級(jí)數(shù)據(jù)統(tǒng)計(jì)》)。

key 命名規(guī)范規(guī)范

的 key命名,在遇到問(wèn)題的時(shí)候能夠方便定位。Redis 屬于 沒(méi)有 Scheme的 NoSQL數(shù)據(jù)庫(kù)。

所以要靠規(guī)范來(lái)建立其 Scheme 語(yǔ)意,就好比根據(jù)不同的場(chǎng)景我們建立不同的數(shù)據(jù)庫(kù)。

敲黑板

把「業(yè)務(wù)模塊名」作為前綴(好比數(shù)據(jù)庫(kù) Scheme),通過(guò)「冒號(hào)」分隔,再加上「具體業(yè)務(wù)名」。

這樣我們就可以通過(guò) key 前綴來(lái)區(qū)分不同的業(yè)務(wù)數(shù)據(jù),清晰明了。

總結(jié)起來(lái)就是:「業(yè)務(wù)名:表名:id」

比如我們要統(tǒng)計(jì)公眾號(hào)屬于技術(shù)類型的博主「碼哥字節(jié)」的粉絲數(shù)。

  1. set 公眾號(hào):技術(shù)類:碼哥字節(jié) 100000 

碼哥,key 太長(zhǎng)的話有什么問(wèn)題么?

key 是字符串,底層的數(shù)據(jù)結(jié)構(gòu)是 SDS,SDS 結(jié)構(gòu)中會(huì)包含字符串長(zhǎng)度、分配空間大小等元數(shù)據(jù)信息。

字符串長(zhǎng)度增加,SDS 的元數(shù)據(jù)也會(huì)占用更多的內(nèi)存空間。

所以當(dāng)字符串太長(zhǎng)的時(shí)候,我們可以采用適當(dāng)縮寫(xiě)的形式。

不要使用 bigkey❝

碼哥,我就中招了,導(dǎo)致報(bào)錯(cuò)獲取不到連接。

因?yàn)?Redis 是單線程執(zhí)行讀寫(xiě)指令,如果出現(xiàn)bigkey 的讀寫(xiě)操作就會(huì)阻塞線程,降低 Redis 的處理效率。

bigkey包含兩種情況:

  • 鍵值對(duì)的 value很大,比如 value保存了 2MB的 String數(shù)據(jù);
  • 鍵值對(duì)的 value是集合類型,元素很多,比如保存了 5 萬(wàn)個(gè)元素的 List 集合。

雖然 Redis 官方說(shuō)明了 key和string類型 value限制均為512MB。

防止網(wǎng)卡流量、慢查詢,string類型控制在10KB以內(nèi),hash、list、set、zset元素個(gè)數(shù)不要超過(guò) 5000。

碼哥,如果業(yè)務(wù)數(shù)據(jù)就是這么大咋辦?比如保存的是《金瓶梅》這個(gè)大作。

我們還可以通過(guò) gzip 數(shù)據(jù)壓縮來(lái)減小數(shù)據(jù)大小:

  1. /** 
  2.  * 使用gzip壓縮字符串 
  3.  */ 
  4. public static String compress(String str) { 
  5.     if (str == null || str.length() == 0) { 
  6.         return str; 
  7.     } 
  8.  
  9.     try (ByteArrayOutputStream out = new ByteArrayOutputStream(); 
  10.     GZIPOutputStream gzip = new GZIPOutputStream(out)) { 
  11.         gzip.write(str.getBytes()); 
  12.     } catch (IOException e) { 
  13.         e.printStackTrace(); 
  14.     } 
  15.     return new sun.misc.BASE64Encoder().encode(out.toByteArray()); 
  16.  
  17. /** 
  18.  * 使用gzip解壓縮 
  19.  */ 
  20. public static String uncompress(String compressedStr) { 
  21.     if (compressedStr == null || compressedStr.length() == 0) { 
  22.         return compressedStr; 
  23.     } 
  24.     byte[] compressed = new sun.misc.BASE64Decoder().decodeBuffer(compressedStr);; 
  25.     String decompressed = null
  26.     try (ByteArrayOutputStream out = new ByteArrayOutputStream(); 
  27.     ByteArrayInputStream in = new ByteArrayInputStream(compressed); 
  28.     GZIPInputStream ginzip = new GZIPInputStream(in);) { 
  29.         byte[] buffer = new byte[1024]; 
  30.         int offset = -1; 
  31.         while ((offset = ginzip.read(buffer)) != -1) { 
  32.             out.write(buffer, 0, offset); 
  33.         } 
  34.         decompressed = out.toString(); 
  35.     } catch (IOException e) { 
  36.         e.printStackTrace(); 
  37.     } 
  38.     return decompressed; 

集合類型

如果集合類型的元素的確很多,我們可以將一個(gè)大集合拆分成多個(gè)小集合來(lái)保存。

使用高效序列化和壓縮方法

為了節(jié)省內(nèi)存,我們可以使用高效的序列化方法和壓縮方法去減少 value的大小。

protostuff和 kryo這兩種序列化方法,就要比 Java內(nèi)置的序列化方法效率更高。

上述的兩種序列化方式雖然省內(nèi)存,但是序列化后都是二進(jìn)制數(shù)據(jù),可讀性太差。

通常我們會(huì)序列化成 JSON或者 XML,為了避免數(shù)據(jù)占用空間大,我們可以使用壓縮工具(snappy、 gzip)將數(shù)據(jù)壓縮再存到 Redis 中。

使用整數(shù)對(duì)象共享池

Redis 內(nèi)部維護(hù)了 0 到 9999 這 1 萬(wàn)個(gè)整數(shù)對(duì)象,并把這些整數(shù)作為一個(gè)共享池使用。

即使大量鍵值對(duì)保存了 0 到 9999 范圍內(nèi)的整數(shù),在 Redis 實(shí)例中,其實(shí)只保存了一份整數(shù)對(duì)象,可以節(jié)省內(nèi)存空間。

需要注意的是,有兩種情況是不生效的:

Redis 中設(shè)置了 maxmemory,而且啟用了 LRU策略(allkeys-lru 或 volatile-lru 策略),那么,整數(shù)對(duì)象共享池就無(wú)法使用了。

  • 這是因?yàn)?LRU 需要統(tǒng)計(jì)每個(gè)鍵值對(duì)的使用時(shí)間,如果不同的鍵值對(duì)都復(fù)用一個(gè)整數(shù)對(duì)象就無(wú)法統(tǒng)計(jì)了。

如果集合類型數(shù)據(jù)采用 ziplist 編碼,而集合元素是整數(shù),這個(gè)時(shí)候,也不能使用共享池。

  • 因?yàn)?ziplist 使用了緊湊型內(nèi)存結(jié)構(gòu),判斷整數(shù)對(duì)象的共享情況效率低。

命令使用規(guī)范

有的命令的執(zhí)行會(huì)造成很大的性能問(wèn)題,我們需要格外注意。

生產(chǎn)禁用的指令

Redis 是單線程處理請(qǐng)求操作,如果我們執(zhí)行一些涉及大量操作、耗時(shí)長(zhǎng)的命令,就會(huì)嚴(yán)重阻塞主線程,導(dǎo)致其它請(qǐng)求無(wú)法得到正常處理。

KEYS:該命令需要對(duì) Redis 的全局哈希表進(jìn)行全表掃描,嚴(yán)重阻塞 Redis 主線程;

  • 應(yīng)該使用 SCAN 來(lái)代替,分批返回符合條件的鍵值對(duì),避免主線程阻塞。

FLUSHALL:刪除 Redis 實(shí)例上的所有數(shù)據(jù),如果數(shù)據(jù)量很大,會(huì)嚴(yán)重阻塞 Redis 主線程;

FLUSHDB,刪除當(dāng)前數(shù)據(jù)庫(kù)中的數(shù)據(jù),如果數(shù)據(jù)量很大,同樣會(huì)阻塞 Redis 主線程。

  • 加上 ASYNC 選項(xiàng),讓 FLUSHALL,F(xiàn)LUSHDB 異步執(zhí)行。

我們也可以直接禁用,用rename-command命令在配置文件中對(duì)這些命令進(jìn)行重命名,讓客戶端無(wú)法使用這些命令。

慎用 MONITOR 命令MONITOR 命令

會(huì)把監(jiān)控到的內(nèi)容持續(xù)寫(xiě)入輸出緩沖區(qū)。

如果線上命令的操作很多,輸出緩沖區(qū)很快就會(huì)溢出了,這就會(huì)對(duì) Redis 性能造成影響,甚至引起服務(wù)崩潰。

所以,除非十分需要監(jiān)測(cè)某些命令的執(zhí)行(例如,Redis 性能突然變慢,我們想查看下客戶端執(zhí)行了哪些命令)我們才使用。

慎用全量操作命令

比如獲取集合中的所有元素(HASH 類型的 hgetall、List 類型的 lrange、Set 類型的 smembers、zrange 等命令)。

這些操作會(huì)對(duì)整個(gè)底層數(shù)據(jù)結(jié)構(gòu)進(jìn)行全量掃描 ,導(dǎo)致阻塞 Redis 主線程。

  • 碼哥,如果業(yè)務(wù)場(chǎng)景就是需要獲取全量數(shù)據(jù)咋辦?

有兩個(gè)方式可以解決:

  1. 使用 SSCAN、HSCAN等命令分批返回集合數(shù)據(jù);
  2. 把大集合拆成小集合,比如按照時(shí)間、區(qū)域等劃分。

數(shù)據(jù)保存規(guī)范

冷熱數(shù)據(jù)分離

雖然 Redis 支持使用 RDB 快照和 AOF 日志持久化保存數(shù)據(jù),但是,這兩個(gè)機(jī)制都是用來(lái)提供數(shù)據(jù)可靠性保證的,并不是用來(lái)擴(kuò)充數(shù)據(jù)容量的。

不要什么數(shù)據(jù)都存在 Redis,應(yīng)該作為緩存保存熱數(shù)據(jù),這樣既可以充分利用 Redis 的高性能特性,還可以把寶貴的內(nèi)存資源用在服務(wù)熱數(shù)據(jù)上。

業(yè)務(wù)數(shù)據(jù)隔離

不要將不相關(guān)的數(shù)據(jù)業(yè)務(wù)都放到一個(gè) Redis 中。一方面避免業(yè)務(wù)相互影響,另一方面避免單實(shí)例膨脹,并能在故障時(shí)降低影響面,快速恢復(fù)。

設(shè)置過(guò)期時(shí)間

在數(shù)據(jù)保存時(shí),我建議你根據(jù)業(yè)務(wù)使用數(shù)據(jù)的時(shí)長(zhǎng),設(shè)置數(shù)據(jù)的過(guò)期時(shí)間。

寫(xiě)入 Redis 的數(shù)據(jù)會(huì)一直占用內(nèi)存,如果數(shù)據(jù)持續(xù)增多,就可能達(dá)到機(jī)器的內(nèi)存上限,造成內(nèi)存溢出,導(dǎo)致服務(wù)崩潰。

控制單實(shí)例的內(nèi)存容量

建議設(shè)置在 2~6 GB 。這樣一來(lái),無(wú)論是 RDB 快照,還是主從集群進(jìn)行數(shù)據(jù)同步,都能很快完成,不會(huì)阻塞正常請(qǐng)求的處理。

防止緩存雪崩

避免集中過(guò)期 key 導(dǎo)致緩存雪崩。

  • 碼哥,什么是緩存雪崩?

當(dāng)某一個(gè)時(shí)刻出現(xiàn)大規(guī)模的緩存失效的情況,那么就會(huì)導(dǎo)致大量的請(qǐng)求直接打在數(shù)據(jù)庫(kù)上面,導(dǎo)致數(shù)據(jù)庫(kù)壓力巨大,如果在高并發(fā)的情況下,可能瞬間就會(huì)導(dǎo)致數(shù)據(jù)庫(kù)宕機(jī)。

運(yùn)維規(guī)范

  1. 使用 Cluster 集群或者哨兵集群,做到高可用;
  2. 實(shí)例設(shè)置最大連接數(shù),防止過(guò)多客戶端連接導(dǎo)致實(shí)例負(fù)載過(guò)高,影響性能。
  3. 不開(kāi)啟 AOF 或開(kāi)啟 AOF 配置為每秒刷盤,避免磁盤 IO 拖慢 Redis 性能。
  4. 設(shè)置合理的 repl-backlog,降低主從全量同步的概率
  5. 設(shè)置合理的 slave client-output-buffer-limit,避免主從復(fù)制中斷情況發(fā)生。
  6. 根據(jù)實(shí)際場(chǎng)景設(shè)置合適的內(nèi)存淘汰策略。
  7. 使用連接池操作 Redis。

本文轉(zhuǎn)載自微信公眾號(hào)「碼哥字節(jié)」

 

責(zé)任編輯:姜華 來(lái)源: 碼哥字節(jié)
相關(guān)推薦

2014-08-14 11:18:22

程序員

2018-01-15 10:51:42

2019-12-25 10:45:30

Java悲觀鎖

2019-12-19 17:00:01

Java線程

2022-05-20 16:50:33

區(qū)塊鏈Web3加密資產(chǎn)

2021-11-03 16:10:16

RedisJava內(nèi)存

2020-04-07 08:00:02

Redis緩存數(shù)據(jù)

2022-05-27 21:56:55

索引存儲(chǔ)MySQL 存儲(chǔ)引擎

2014-06-09 10:51:59

2019-05-17 15:48:16

神經(jīng)網(wǎng)絡(luò)卷積神經(jīng)網(wǎng)絡(luò)人工智能

2023-09-07 16:53:57

2023-03-06 08:56:57

2020-07-22 07:43:11

Python開(kāi)發(fā)工具

2011-01-07 15:50:26

2020-04-13 14:16:30

微軟Windows操作系統(tǒng)

2019-06-27 16:03:28

通信5G網(wǎng)絡(luò)

2020-03-06 11:30:08

JavaGitHub編程

2018-09-28 09:32:57

2015-10-21 10:36:47

技術(shù)實(shí)現(xiàn)項(xiàng)目

2012-05-08 10:43:13

技術(shù)網(wǎng)站
點(diǎn)贊
收藏

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