總結篇4:redis 核心數據存儲結構及核心業務模型實現應用場景

總結篇4:redis 核心數據存儲結構及核心業務模型實現應用場景

redis 和memcached 有什麼區別?爲什麼在高併發下,單線程的redis 比多線程的效率高?

  • mc 可以緩存圖片和視頻,redis 支持除更多的數據結構。redis 典型的應用場景是用戶訂單列表,用戶消息,帖子評論等。
  • redis 可以使用虛擬內存,redis 可持久化和aof 災難恢復,支持主從數據備份。如果redis 掛了,內存能夠快速恢復熱數據,不會將壓力瞬間壓在數據庫上,沒有cache 預熱的過程。對於只讀和數據一致性要求不高的場景可以採用持久化存儲。
  • redis 可以做消息隊列。redis 支持集羣,可以實現主動複製,讀寫分離,mc 如果想實現高可用,需要進行二次開發。
  • mc 存儲的vlaue 最大爲1M。

選擇mc 的場景:

  • 1 純kv, 數據量非常大的業務。
    原因是:
  • 1 mc 的內存分配採用的是預分配內存池的管理方式,能夠省去內存分配的時間。redis 是臨時申請空間,可以導致碎片化
  • 2 虛擬內存使用,mc 將所有的數據存儲在物理內存裏,redis 有自己的vm 機制,理論上能夠存儲比物理內在更多的數據,當數據超量時,引發swap, 把冷數據刷新到磁盤上。從這點上看,數據量大時,mc 更快
  • 3 網絡模型。mc 使用非阻塞的io 複用模型,redis 也是使用非阻塞的io 複用模型,但是redis 還提供了一些非kv 存儲之外的排序,聚合功能,複雜的cpu 計算,會阻塞整個io 調度,從這點上由於redis 提供的功能較多,mc 更快一些。
  • 4 線程模型,mc 使用多線程,主線程監聽,worker 子線程接受請求,執行讀寫,這個過程可能存在鎖衝突。redis 使用單線程,雖然無鎖衝突,但是難以利用多核的特性提升吞吐量。

選擇redis 場景:

  • 1 存儲方式上:mc 會把數據全部存儲在內存中,斷電後會掛掉,數據不能超過內存的大小。redis 有部分數據存在硬盤上,這樣能保證數據持久性。
  • 2 數據支持類型上:redis 支持更豐富的數據類型
  • 3 使用底層模型不同:底層實現方式以及客戶端之間通信的應用協議不同。redis 直接構建了vm 機制,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
  • 4 value 大小。redis 可以達到1 G,而mc 只有1 M。

mc 多線程模型引入了緩存一致性和鎖,加鎖帶來了性能損耗。爲什麼 redis 單線程還如此快?因爲底層有高效數據存儲結構。整個redis 存儲結構是全局哈希表,哈希運算非常快,時間複雜度爲常量。

redis 常見性能問題和解決方案

  • 1 master 最好不要做持久化工作,如RDB 內存快照和AOF 日誌文件
  • 2 如果數據比較重要,某個slave 開啓AOF 備份,策略設置成每秒同步一次
  • 3 爲了主從複製的速度和連接的穩定性,master 和slave 最好在一個局域網內
  • 4 儘量避免在壓力大得主庫上增加從庫
  • 主從複製不要採用網狀結構,儘量是線性結構。

redis set key value, 其中key 類型都是string 類型。五種基本類型都是對應的value。

String 應用場景

  • 字符串常用操作
set key value // 存入字符串鍵值對
mset key value [key value] // 批量存儲字符串鍵值對


  • 單值緩存
1 set key value

2 get key
  • 對象緩存
1 set user:1 value(json 格式數據)
2 mset user:1 name zhuge user:1:balance 888
  mget user:1:name user:1:balance
  • 分佈式鎖
setnx product:100001 true // 返回1 代表獲取鎖成功
setnx product:100001 true // 返回0代表獲取鎖失敗
。。。執行業務操作
del product:100001  // 執行完業務釋放鎖

set product:100001 true ex 10 nx // 防止程序意外終止導致死鎖


  • 計數器
incr article:readcount:{文章id}   // 文章點贊數
get article:readcount:{文章id}
  • 分佈式系統全局序列號
incrby orderid 100  、、 redis 批量生成序列號提升性能

一般我們設置數據庫自增主鍵,並設置相應索引。如果數據量很大,分庫分表時就實現不了。可以用緩存實現。爲提升性能,我們可以優化,做一個批量內存的自增,比如一次生成100個。

hash 常用操作

優點:

  • 同類數據歸類整合儲存,方便數據管理
  • 相比 string 操作消耗內在與cpu 更小

缺點:

  • 過期功能不能使用在field 上,只能用在key 上
  • redis 集羣架構下不適合大規模使用
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

場景:購物車


以用戶id 爲key
以商品id 爲field
商品數據爲value



購物車操作
添加商品 hset cart:1001 10088 1
增加商品 hincrby cart:1001 10088 1
商品數量 hlen cart:1001
刪除商品 hdel cart:1001 10088
獲取購物車所有商品 hgetall cart:1001

image

list 結構

list 常用操作

lpush key value [value..] //插入到列表最左邊
rpush key value [value...] //插入到列表最右邊
lpop key // 移除列表的頭元素
rpop key // 移除列表的尾元素
lrange key start stop // 列表區間內元素

blpop key [key ...] timeout // 從列表表頭中彈出第一個元素。如果元素爲空,陰塞等待timeout 秒。如果timeout 爲0, 一直等待
brpop key [key ...] timeout  // 從列表表尾彈出元素

常用數據結構
stack (棧) = lpush + lpop = filo
queue (隊列) = lpush + rpop
blocking MQ(陰塞隊列) = lpush + brpop

場景:
消息流頁面:訂閱號,微博等

(這塊功能如果用數據庫也可實現,但是一般性能比較慢。如果有order by 等排序功能,還容易導致索失效。)

1 發消息id爲18 lpush msh:{nameId} 18
2 發消息id爲20 lpush msh:{nameId} 20
3 查看消息流 lrange msg:{nameId} 0 9

每個消息流推送給每個粉絲,如果粉絲量大,lpush 命令需要優化。如pipeline,或優先推送在線用戶。

set 結構

 set 常用操作

sadd key member [member ...] // 往集合key 中存入元素, 元素存在則忽略
srem key member [member ...] // 從集合key 中刪除元素
smembers key // 獲取集合key 中所有元素
scard key // 獲取集合key 的元素個數
sismember key member // 判斷member 元素是否存在集合key 中
srandmember key [count] // 從集合key k 中選出count 個元素,元素不從key 中刪除
spop key [count] // 從集合key 中選出count 個元素,元素從key 中刪除


 

應用場景:

抽獎
1 點擊抽獎加入集合 sadd key {userid}
2 查看所有抽獎用戶 smembers key
3 抽取count 名中獎者
srandmember key [count] / spop key [count]

點贊
sadd like:{消息id}{用戶id}
取消點贊 
srem like:{消息id}{用戶id}
檢查用戶是否點過贊
sismember like:{消息id}{用戶id}
獲取點贊用戶列表
smembers like:{消息id}
獲取點贊用戶數
scard like:{消息id}

社交類產品的重要場景,叫社交關注模型

 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 中

社交關注模型

應用場景:
1 nameA關注的人 nameAset
2 nameB關注的人 nameBset
3 nameC關注的人 nameCset
4 我和nameA共同關注的人 sinter 
5 我關注的人也關注了他 sismember 
6 我可能認識的人 sdiff

商品篩選模型 

zset 有序集合

常用操作
zadd key score member [[score member]...] // 往有序集合key 中加入帶分值元素
zrem key member [member ...] // 從有序集合中刪除元素
zcore 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] // 倒序

集合操作
zunionstore destkey numkeys key [key ...] 並集計算
zinterstore destkey numkeys key [key ...] 交集計算

應用場景

1 點擊新聞 
zincrby hotnews:202008 1 name
2 單日排行榜 
zrevrange hotnews:202208 0 9 withscores 
3 七日搜索榜單計算
zunionstore hotnews:20220801-20220807 7
4 展示七日榜前十
zrevrange hotnews:20220801-20220807 0 9 withscores

redis 數據結構

image

數組:根據序號隨機查找很快,但是插入與刪除很慢,需要挪動很多元素。

鏈表:插入與刪除很快,只需要修改相鄰元素指針,但是查找很慢,需要從第一個元素逐個遍歷查找。

有序數組支持折半查找,鏈表不支持折半查找。

有序數組的折半查找操作速度很快,但是插入、刪除操作很慢。

跳錶(O(logN)):將有序列表改造爲支持“折半查找”算法,可以進行快速的插入、刪除、查找操作。

文:一隻阿木木

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章