Redis核心數據結構與高性能原理

點贊再看,養成習慣,公衆號搜一搜【一角錢技術】關注更多原創技術文章。本文 GitHub org_hejianhui/JavaStudy 已收錄,有個人系列文章。java

五種經常使用數據結構

String 結構

字符串經常使用操做

SET key value 	//存入字符串鍵值對
MSET key value [key value ...] 	//批量存儲字符串鍵值對
SETNX key value 	//存入一個不存在的字符串鍵值對
GET key 	//獲取一個字符串鍵值
MGET key [key ...]	//批量獲取字符串鍵值
DEL key [key ...] 	//刪除一個鍵
EXPIRE key seconds //設置一個鍵的過時時間(秒)
複製代碼

原子加減

INCR key //將key中儲存的數字值加1
DECR key //將key中儲存的數字值減1
INCRBY key increment //將key所儲存的值加上increment
DECRBY key decrement //將key所儲存的值減去decrement
複製代碼

String 應用場景

  • 單值緩存
  • 對象緩存
  • 分佈式鎖
  • 計數器
  • Web集羣Session共享
  • 分佈式系統全局序列號
  1. 單值緩存
SET key value
Get key
複製代碼
  1. 對象緩存
SET user:1 value(json格式數據)
MSET user:1:name yijiaoqian user:1:balance 1888
MGET user:1:name user:1:balance 
複製代碼
  1. 分佈式鎖
SETNX product:10001  true //返回1表明獲取鎖成功
SETNX product:10001  true //返回0表明獲取鎖失敗
...執行業務操做...
DEL product:10001	//執行完業務釋放鎖

SET product:10001 true  ex  10  nx	//防止程序意外終止致使死鎖

複製代碼
  1. 計數器
INCR article:readcount:{文章id}  	
GET article:readcount:{文章id}  
複製代碼
  1. Web集羣Session共享

Spring session + redis 實現sessio共享android

  1. 分佈式系統全局序列號
INCRBY orderId 1000	//redis批量生成序列號提高性能
複製代碼

Hash 結構

Hash經常使用操做

HSET key field value 	//存儲一個哈希表key的鍵值
HSETNX key field value 	//存儲一個不存在的哈希表key的鍵值
HMSET key field  value [field value ...] //在一個哈希表key中存儲多個鍵值對
HGET key field 	//獲取哈希表key對應的field鍵值
HMGET key field [field ...] //批量獲取哈希表key中多個field鍵值
HDEL key field [field ...] 	//刪除哈希表key中的field鍵值
HLEN key	//返回哈希表key中field的數量
HGETALL key	//返回哈希表key中全部的鍵值

HINCRBY key field increment //爲哈希表key中field鍵的值加上增量increment
複製代碼

Hash應用場景

  • 對象存儲
HMSET user {userId}:name  yijiaoqian {userId}:balance  1888
HMSET user 1:name yijiaoqian 1:balance 1888
HMGET user 1:name 1:balance  
複製代碼
  • 電商購物車
  1. 以用戶id爲key
  2. 商品id爲field
  3. 商品數量爲value  

購物車操做:git

  1. 添加商品:hset cart:1001 10088 1
  2. 增長數量:hincrby cart:1001 10088 1
  3. 商品總數:hlen cart:1001
  4. 刪除商品:hdel cart:1001 10088
  5. 獲取購物車全部商品:hgetall cart:1001  

Hash結構優缺點

優勢:github

  1. 同類數據歸類整合儲存,方便數據管理
  2. 相比string操做消耗內存與cpu更小
  3. 相比string儲存更節省空間  

缺點:redis

  1. 過時功能不能使用在field上,只能用在key上
  2. Redis集羣架構下不適合大規模使用  

List 結構

List經常使用操做

LPUSH key value [value ...] //將一個或多個值value插入到key列表的表頭(最左邊)
RPUSH key value [value ...]	 //將一個或多個值value插入到key列表的表尾(最右邊)
LPOP key	//移除並返回key列表的頭元素
RPOP key	//移除並返回key列表的尾元素
LRANGE key start stop	//返回列表key中指定區間內的元素,區間以偏移量start和stop指定

BLPOP key [key ...] timeout	//從key列表表頭彈出一個元素,若列表中沒有元素,阻塞等待timeout秒,若是timeout=0,一直阻塞等待
BRPOP key [key ...] timeout //從key列表表尾彈出一個元素,若列表中沒有元素,阻塞等待timeout秒,若是timeout=0,一直阻塞等待
複製代碼

List應用場景

  • 經常使用數據結構
  1. Stack(棧) = LPUSH + LPOP (FILO
  2. Queue(隊列)= LPUSH + RPOP (FIFO
  3. Blocking MQ(阻塞隊列)= LPUSH + BRPOP  

  • 微博和微信公號消息流

一角錢關注了雷軍、馬雲等大V
1)雷布斯發微博,消息ID爲10018
LPUSH  msg:{一角錢-ID}  10018
2)馬雲發微博,消息ID爲10086
LPUSH  msg:{一角錢-ID} 10086
3)查看最新微博消息
LRANGE  msg:{一角錢-ID}  0  4
複製代碼

Set 結構

Set經常使用操做

SADD key member [member ...]	//往集合key中存入元素,元素存在則忽略,若key不存在則新建
SREM key member [member ...]	//從集合key中刪除元素
SMEMBERS key	//獲取集合key中全部元素
SCARD key	//獲取集合key的元素個數
SISMEMBER key member	//判斷member元素是否存在於集合key中
SRANDMEMBER key [count]	//從集合key中選出count個元素,元素不從key中刪除
SPOP key [count]	//從集合key中選出count個元素,元素從key中刪除
複製代碼

Set運算操做

SINTER key [key ...] //交集運算
SINTERSTORE destination key [key ..] //將交集結果存入新集合destination中
SUNION key [key ..] //並集運算
SUNIONSTORE destination key [key ...]	//將並集結果存入新集合destination中
SDIFF key [key ...] //差集運算
SDIFFSTORE destination key [key ...]	//將差集結果存入新集合destination中
複製代碼

Set應用場景

  • 微信抽獎小程序

1.點擊參與抽獎加入集合: SADD key {userID} 
2.查看參與抽獎全部用戶:SMEMBERS key
3.抽取count名中獎者:SRANDMEMBER key [count]/ SPOP key [count]
複製代碼
  • 微信微博點贊、收藏、標籤

1.點贊: SADD  like:{消息ID}  {用戶ID} 
2.取消點贊: SREM like:{消息ID}  {用戶ID} 
3.檢查用戶是否點過贊: SISMEMBER  like:{消息ID}  {用戶ID} 
4.獲取點讚的用戶列表: SMEMBERS like:{消息ID} 
5.獲取點贊用戶數: SCARD like:{消息ID}
複製代碼
  • 集合操做

SINTER set1 set2 set3 -> { c } 	// 交集
SUNION set1 set2 set3 -> { a,b,c,d,e }	// 並集
SDIFF set1 set2 set3  -> { a }	// 差集
複製代碼
  • 集合操做實現微博微信關注模型

1) 張三關注的人: 
zhangsanSet-> {lisi, wangwu}
2) 一角錢關注的人:
 yijiaoqianSet--> {zhangsan, zhaoliu, lisi, wangwu}
3) 李四關注的人: 
lisiSet-> {zhangsan, yijiaoqian, zhaoliu, wangwu, xunyu)
4) 我和一角錢共同關注: 
SINTER zhangsanSet yijiaoqianSet--> {lisi, wangwu}
5) 我關注的人也關注他(一角錢): 
SISMEMBER lisiSet yijiaoqian 
SISMEMBER wangwuSet yijiaoqian
6) 我可能認識的人: 
SDIFF yijiaoqianSet zhangsanSet->(zhangsan, zhaoliu}
複製代碼
  • 集合操做實現電商商品篩選

SADD brand:huawei  P40
SADD brand:xiaomi  mi-10
SADD brand:iPhone iphone12
SADD os:android P40 mi-10
SADD cpu:brand:intel P40 mi-10
SADD ram:8G P40 mi-10 iphone12

SINTER os:android cpu:brand:intel ram:8G >  {P40,mi-10}

複製代碼

ZSet 有序集合結構

ZSet經常使用操做

ZADD key score member [[score member]…]	//往有序集合key中加入帶分值元素
ZREM key member [member …]	//從有序集合key中刪除元素
ZSCORE key member 	//返回有序集合key中元素member的分值
ZINCRBY key increment member	//爲有序集合key中元素member的分值加上increment 
ZCARD key	//返回有序集合key中元素個數
ZRANGE key start stop [WITHSCORES]	//正序獲取有序集合key從start下標到stop下標的元素
ZREVRANGE key start stop [WITHSCORES]//倒序獲取有序集合key從start下標到stop下標的元素
複製代碼

ZSet集合操做

ZUNIONSTORE destkey numkeys key [key ...] 	//並集計算
ZINTERSTORE destkey numkeys key [key …]		//交集計算
複製代碼

ZSet應用場景

  • ZSet集合操做實現排行榜

1. 點擊新聞:
ZINCRBY hotNews:20201221 1 完善低齡未成年人犯罪規定
2. 展現當日排行前十:
ZREVRANGE hotNews:20201221 0 9 WITHSCORES
3. 七日搜索榜單計算:
ZUNIONSTORE hotNews:20201215-20201221  7 
hotNews:20201215 hotNews:20201216... hotNews:20201221
4. 展現七日排行前十:
ZREVRANGE hotNews:20201215-20201221 0 9 WITHSCORES
複製代碼

Redis的單線程和高性能

Redis是單線程嗎?

Redis的單線程主要是指 Redis 的網絡IO和鍵值對讀寫是由一個線程來完成的,這也是Redis對外提供鍵值存儲服務的主要流程。可是Redis的其餘功能,好比持久化、異步刪除、集羣數據同步等,其實由額外的線程執行的。shell

Redis 單線程爲何還能這麼快?

由於它全部的數據都在內存中,全部的運算都是內存級別的運算,並且單線程避免來多線程的切換性能損耗問題,正由於Redis是單線程,因此要當心使用Redis 指令,對於那些耗時的指令(好比keys),必定要謹慎使用,一不當心就可能會致使 Redis 卡頓。json

Redis 單線程如何處理那麼多的併發客戶端鏈接?

Redis 的IO多路複用:redis利用epoll實現IO多路複用,將鏈接信息和事件放到隊列中,依次放到文件事件分派器,事件分派器將事件分發給事件處理器。 小程序

# 查看redis支持的最大鏈接數,在redis.conf文件中可修改,# maxclients 10000
127.0.0.1:6379> CONFIG GET maxclients
    ##1) "maxclients"
    ##2) "10000"
複製代碼

其餘高級命令

keys:全量遍歷鍵

用來列出全部知足特定正則字符串規則的key,當redis數據量比較大時,性能比較差,要避免使用。緩存

127.0.0.1:6379> set codehole1 a
OK
127.0.0.1:6379> set codehole2 b
OK
127.0.0.1:6379> set codehole3 c
OK
127.0.0.1:6379> set code1hole a
OK
127.0.0.1:6379> set code2hole b
OK
127.0.0.1:6379> set code3hole c
OK
127.0.0.1:6379> keys *
1) "codehole1"
2) "codehole3"
3) "codehole2"
4) "code3hole"
5) "code1hole"
6) "code2hole"
127.0.0.1:6379> keys codehole*
1) "codehole1"
2) "codehole3"
3) "codehole2"
127.0.0.1:6379> keys code*hole
1) "code3hole"
2) "code1hole"
3) "code2hole"
複製代碼

scan:漸進式遍歷鍵

SCAN cursor [MATCH pattern] [COUNT count]
複製代碼

scan 參數提供了三個參數:bash

  • 第一個參數 cursor 整數值(hash桶的索引值)
  • 第二個是 key 的正則模式
  • 第三個是一次遍歷的key的數量(參考值,底層遍歷的數量不必定),並很多符合條件的結果數量。

第一次遍歷時,cursor 值爲0,而後將返回結果中的第一個整數值做爲下一次遍歷的 cursor。一直遍歷到返回的 cursor 值爲0時結束。

注意:可是scan並不是完美無暇,若是在scan的過程當中若是有鍵的變化(增長、刪除、修改),那麼遍歷效果可能會碰到以下問題:新增的鍵可能沒有遍歷到,遍歷出了重複的鍵等狀況,也就是說scan並不能保證完整的遍歷出來全部的鍵,這些是咱們在開發時須要考慮的。

info:查看redis服務運行信息

分爲 9 大塊,每一個塊都有很是多的參數:

  • Server 服務器運行的環境參數
  • Clients 客戶端相關信息
  • Memory 服務器運行內存的統計數據
  • Persistence 持久化信息
  • Stats 通用統計數據
  • Replication 主從複製相關信息
  • CPU CPU使用狀況
  • Cluster 集羣信息
  • KeySpace 鍵值對統計數量信息

核心屬性說明

connected_clients:2                  # 正在鏈接的客戶端數量

instantaneous_ops_per_sec:789        # 每秒執行多少次指令

used_memory:929864                   # Redis分配的內存總量(byte),包含redis進程內部的開銷和數據佔用的內存
used_memory_human:908.07K            # Redis分配的內存總量(Kb,human會展現出單位)
used_memory_rss_human:2.28M          # 向操做系統申請的內存大小(Mb)(這個值通常是大於used_memory的,由於Redis的內存分配策略會產生內存碎片)
used_memory_peak:929864              # redis的內存消耗峯值(byte)
used_memory_peak_human:908.07K       # redis的內存消耗峯值(KB)

maxmemory:0                         # 配置中設置的最大可以使用內存值(byte),默認0,不限制
maxmemory_human:0B                  # 配置中設置的最大可以使用內存值
maxmemory_policy:noeviction         # 當達到maxmemory時的淘汰策略
複製代碼

文章持續更新,能夠公衆號搜一搜「 一角錢技術 」第一時間閱讀, 本文 GitHub org_hejianhui/JavaStudy 已經收錄,歡迎 Star。

相關文章
相關標籤/搜索