Redis-數據類型-應用場景


一些小問題

Redis一共有幾種數據類型?(注意是數據類型不是數據結構)

一共是八種,String、Hash、Set、List、Zset、Hyperloglog、Geo、Streams。

為什么要把數據放在內存中?

內存的速度更快,10W QPS

減少計算的時間,減輕數據庫壓力

如果是用內存的數據結構作為緩存,為什么不用HashMap或者Memcached?

更豐富的數據類型

支持多種編程語言

功能豐富:持久化機制、內存淘汰策略、事務、發布訂閱、pipeline、LUA

支持集群、分布式

Memcached和redis的區別是什么?

Memcached只能存儲KV、沒有持久化機制、不支持主從復制、是多線程的。

Redis Key的最大長度限制是512M,值的限制不同,有的是用長度限制的,有的是用個數限制的。

關於其他有趣的 Reids 的內容可以移步這兒:https://www.cnblogs.com/zwtblog/tag/Redis/

String

get和set命令就是String的操作命令,Redis的字符串被叫做二進制安全的字符串(Binary-safe strings)。

String可以存儲三種類型,INT(整數)、float(單精度浮點數)、string(字符串)

操作命令

# 存值(如果對同一個key set多次會直接覆蓋舊值)
set jack 2673
# 取值
get jack
# 查看所有鍵
keys *
# 獲取鍵總數(生產環境數據量大,慎用)
dbsize
# 查看鍵是否存在
exists jack
# 刪除鍵
del jack tonny
# 重命名鍵
rename jack tonny
# 查看類型
type jack 
# 獲取指定范圍的字符
getrange jack 0 1
# 獲取值長度
strlen jack
# 字符串追加內容
append jack good
# 設置多個值(批量操作,原子性)
mset jack 2673 tonny 2674
# 獲取多個值
mget jack tonny
# 設置值,如果key存在,則不成功
setnx jack shuaige
# 基於此實現分布式鎖
set key value [expiration EX seconds|PX milliseconds][NX|XX]
# (整數)值遞增(值不存在會得到1)
incr jack
incrby jack 100
# (整數)值遞減
decr jack
decrby jack 100
# 浮點數增量
set mf 2.6
incrbyfloat mf 7.3

應用場景

1、緩存

String類型,這是最常用的,可以緩存一些熱點數據,比如首頁新聞,可以顯著提升熱點數據的訪問速度,同時減輕DB壓力。

2、分布式數據共享

String 類型,因為Redis是分布式的獨立服務,可以在多個應用之間共享。

例如:分布式Session

<dependency>
  <groupId>org.springframework.session</groupId>
  <artifactId>spring-session-data-redis</artifactId>
</dependency>

3、分布式鎖

詳情見博客:https://www.cnblogs.com/zwtblog/p/15185894.html

4、全局ID

INT類型,INCRBY,利用原子性

incrby userid 1000(分表分庫的場景,一次性拿一段) 

5、計數器

INT類型,INCR方法

例如:文章的閱讀量,微博點贊數,允許一定的延遲,先寫入Redis再定時同步到數據庫

6、限流

INT類型,INCR方法

以訪問者的IP和其他信息作為key,訪問一次增加一次計數,超過次數則返回false。

Hash

這樣也便於集中管理,划分的粒度不同,可以按照實際場景,key 的過期時間,靈活度考慮選取哪一種存儲方式。

Hash用來存儲多個無序的鍵值對,最大存儲數量2^32-1(40億左右)。

優點:

  1. 把所有相關的值聚集到一個Key中,節省內存空間
  2. 只使用一個Key,減少Key沖突
  3. 當需要批量獲取值的時候,只需要使用一個命令,減少內存/IO/CPU的消耗

缺點:

  1. Field不能單獨設置過期時間
  2. 需要考慮數據量分布的問題(field非常多的時候,無法分布到多個節點)

操作命令

# 設置、批量設置值
hset h1 f 6
hset h1 e 5
hmset h1 a 1 b 2 c 3 d 4
# 取值
hget h1 a
# 批量取值
hmget h1 a b c d
# 獲取所有field
hkeys h1
# 獲取所有field的值
hvals h1
# 返回哈希表中,所有的字段和值
hgetall h1
# 刪除field
hdel h1 a
# 獲取哈希表中字段的數量
hlen h1

應用場景

String可以做的事情,Hash都可以做。

再補充一個場景,購物車

List

存儲有序的字符串(從左到右),元素可以重復,最大存儲數量2^32-1(40億左右)。

操作命令

# 左推
lpush queue a
lpush queue b c
# 右推
rpush queue d e
# 左邊移除並返回列表的第一個元素
lpop queue
# 右邊移除並返回列表的第一個元素
rpop queue
# 通過索引獲取列表中的元素
lindex queue 0
# 返回列表中指定區間內的元素
lrange queue 0 -1

應用場景

1、列表

例如用戶的消息列表、網站的公告列表、活動列表、博客的文章列表、評論列表等,通過 LRANGE 取出一頁,按順序顯示。

2、隊列/棧

List還可以當做分布式環境的 隊列 / 棧 使用。

隊列:先進先出,rpush 和 blpop

棧:先進后出,rpush 和 brpop

這里介紹兩個阻塞的彈出操作:blpop/brpop,可以設置超時時間(單位:秒)

blpop:blpop key1 timeout,
移出並獲取列表的第一個元素, 
如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素為止。

brpop:brpop key1 timeout,
移出並獲取列表的最后一個元素,
如果列表沒有元素會阻塞列表直到等待超時或發現可彈出元素為止。

Set

Set 存儲 String 類型的無序集合,最大存儲數量 2^32-1(40億左右)。

操作命令

# 添加一個或多個元素
sadd myset a b c d e f g
# 獲取所有元素
smembers myset
# 統計元素個數
scard myset
# 隨機獲取一個元素
srandmember myset
# 隨機彈出一個元素
spop myset
# 移除一個或者多個元素
srem myset d e f
# 查看元素是否存在
sismember myset a
# 獲取差集
sdiff set1 set2
# 獲取交集
sinter set1 set2
# 獲取並集
sunion set1 set2

應用場景

1、抽獎

隨機獲取元素:spop myset

2、點贊、簽到、打卡

我們以微博舉例子,假設這條微博的ID是t1001,用戶ID是u6001,
    
用  dianzan:t1001  來維護  t1001  這條微博的所有點贊用戶。
    
點贊了這條微博:sadd dianzan:t1001 u6001
取消點贊:srem dianzan:t1001 u6001
是否點贊:sismember dianzan:t1001 u6001
點贊的所有用戶:smembers dianzan:t1001
點贊數:scard dianzan:t1001
    
比關系型數據庫簡單了許多。

3、商品標簽

用 tags : i8001 來維護商品所有的標簽。

sadd tags:i8001 畫面清晰細膩

sadd tags:i8001 真彩清晰顯示屏

sadd tags:i8001 流暢至極

4、商品篩選

華為P50上線了,支持民族品牌,加到各個標簽中去。

sadd brand:huawei p50

sadd os:android p50

sadd screensize:6.0-6.24 p50

買的時候篩選,牌子是華為,操作系統是安卓,屏幕大小在6.0-6.24之間的,取交集:

sinter brand:huawei os:android screensize:6.0-6.24

ZSet

sorted set 存儲有序的元素。每個元素都有個 score,按照 score 從小到大排序。

score 相同時,按照 key 的ASCII碼排序。

操作命令

# 添加元素
zadd myzset 10 java 20 php 30 ruby 40 cpp 50 python
# 獲取全部元素
zrange myset 0 -1 withscores
zrevrange myzset 0 -1 withscores
# 根據分數區間獲取元素
zrangebyscore myzset 20 30
# 移除元素(也可以根據score rank刪除)
zrem myzset php cpp
# 統計元素個數
zcard myzset
# 分值增加
zincrby myzset 5 python
# 根據分值min和max統計個數
zcount myzset 20 60
# 獲取python排名
zrank myzset python
# 獲取元素分數
zscore myzset python

應用場景

1、排行榜

今天是2021年5月23號,建一個 key 為 hotSearch:20210523 的 zset。

這條新聞的id是n1234,每點擊一下:zincrby hotSearch:20210523 1 n1234

獲取熱搜排行榜前十條:zrevrange hotSearch:20210523 0 10 withscores

BitMaps

BitMaps是在字符串類型上定義的位操作,一個字節由8個二進制位組成。

操作命令

# 設置字符串key為k1,value為mic
set k1 mic
# 取k1的第七位,結果是0
getbit k1 6
# 取k1的第八位為0,此時的ASCII碼是108,對應字母是l
setbit k1 7 0
# 所以取出來值為lic
get k1
# 統計二進制中1的個數,一共是12個
bitcount k1
# 獲取第一個1或者0的位置
bitpos k1 1
bitpos k1 1

BITOP AND destkey key [key ...],對一個或多個key求邏輯並,並將結果保存到 destkey。

BITOP OR destkey key [key ...],對一個或多個key求邏輯或,並將結果保存到 destkey。

BITOP XOR destkey key [key ...],對一個或多個key求邏輯異或,並將結果保存到 destkey。

BITOP NOT destkey key,對給定key求邏輯非,並將結果保存到 destkey。

應用場景

1、連續在線用戶

setbit firstday 0 1 //設置第一天uid是0的用戶登錄
setbit firstday 1 0 //設置第一天uid是1的用戶未登錄
setbit firstday 2 1 //設置第一天uid是2的用戶登錄
...
setbit secondday 0 0 //設置第二天uid是0的用戶未登錄
setbit secondday 1 1 //設置第二天uid是1的用戶登錄
setbit secondday 2 1 //設置第二天uid是2的用戶登錄
... //以此類推

那么在算連續七天在線用戶就是:
BITOP AND 7_both_online_users firstday secondday thirdday fourthday fifthday sixthday seventhday

2、應用訪問統計

3、在線用戶統計

Hyperloglog

Hyperloglog 提供了一種不太精確的基數統計方法,用來統計一個集合中不重復的元素個數,

在 Redis 中實現的 Hyperloglog,只需要12k內存就能統計2^64個數據。

    public static void main(String[] args) {
        Jedis jedis = new Jedis("39.103.144.86", 6379);
        float size = 100000;
        for (int i = 0; i < size; i++) {
            jedis.pfadd("hll", "hll-" + i);
        }
        long total = jedis.pfcount("hll");
        System.out.println(String.format("統計個數: %s", total));
        System.out.println(String.format("正確率: %s", (total / size)));
        System.out.println(String.format("誤差率: %s", 1 - (total / size)));
        jedis.close();
    }

操作命令

PFADD key element [element ...]
添加指定元素到 HyperLogLog 中。


PFCOUNT key [key ...]
返回給定 HyperLogLog 的基數估算值。


PFMERGE destkey sourcekey [sourcekey ...]
將多個 HyperLogLog 合並為一個 HyperLogLog

應用場景

1、統計網站的UV,或者應用的日活、月活,存在一定的誤差。

Geo

操作命令

# 存經緯度
geoadd location 121.445	31.213 shanghai
# 取經緯度
geopos location shanghai

應用場景

1、增加地址位置信息、獲取地址位置信息

2、計算兩個位置的距離

3、獲取指定范圍內的地理位置集合

    public static void main(String[] args) {
        Jedis jedis = new Jedis("39.103.144.86", 6379);
        Map<String, GeoCoordinate> geoMap = new HashMap<>();
        GeoCoordinate coordinate = new GeoCoordinate(121.445, 31.213);
        geoMap.put("shanghai", coordinate);
        jedis.geoadd("positions", geoMap);
        System.out.println(jedis.geopos("positions", "shanghai"));
        jedis.close();
    }

Streams

Redis Stream 是 Redis 5.0 版本新增加的數據結構。

Redis Stream 主要用於消息隊列(MQ,Message Queue),Redis 本身是有一個 Redis 發布訂閱 (pub/sub) 來實現消息隊列的功能,但它有個缺點就是消息無法持久化,如果出現網絡斷開、Redis 宕機等,消息就會被丟棄。

簡單來說發布訂閱 (pub/sub) 可以分發消息,但無法記錄歷史消息。

Redis Stream 提供了消息的持久化和主備復制功能,可以讓任何客戶端訪問任何時刻的數據,並且能記住每一個客戶端的訪問位置,還能保證消息不丟失。

Redis Stream 的結構如下所示,它有一個消息鏈表,將所有加入的消息都串起來,每個消息都有一個唯一的 ID 和對應的內容:

每個 Stream 都有唯一的名稱,它就是 Redis 的 key,在我們首次使用 xadd 指令追加消息時自動創建。

上圖解析:

  • Consumer Group :消費組,使用 XGROUP CREATE 命令創建,一個消費組有多個消費者(Consumer)。
  • last_delivered_id :游標,每個消費組會有個游標 last_delivered_id,任意一個消費者讀取了消息都會使游標 last_delivered_id 往前移動。
  • pending_ids :消費者(Consumer)的狀態變量,作用是維護消費者的未確認的 id。 pending_ids 記錄了當前已經被客戶端讀取的消息,但是還沒有 ack (Acknowledge character:確認字符)。

操作命令

消息隊列相關命令:
XADD - 添加消息到末尾
XTRIM - 對流進行修剪,限制長度
XDEL - 刪除消息
XLEN - 獲取流包含的元素數量,即消息長度
XRANGE - 獲取消息列表,會自動過濾已經刪除的消息
XREVRANGE - 反向獲取消息列表,ID 從大到小
XREAD - 以阻塞或非阻塞方式獲取消息列表


消費者組相關命令:
XGROUP CREATE - 創建消費者組
XREADGROUP GROUP - 讀取消費者組中的消息
XACK - 將消息標記為"已處理"
XGROUP SETID - 為消費者組設置新的最后遞送消息ID
XGROUP DELCONSUMER - 刪除消費者
XGROUP DESTROY - 刪除消費者組
XPENDING - 顯示待處理消息的相關信息
XCLAIM - 轉移消息的歸屬權
XINFO - 查看流和消費者組的相關信息;
XINFO GROUPS - 打印消費者組的信息;
XINFO STREAM - 打印流信息

應用場景

應用場景小結

緩存======提升熱點數據的訪問速度

共享數據======數據的存儲和共享的問題

全局ID======分布式全局ID的生成方案(分庫分表)

分布式鎖======進程間共享數據的原子操作保證

在線用戶統計和計數

隊列、棧======跨進程的隊列/棧

消息隊列======異步解耦的消息機制

服務注冊與發現======RPC通信機制的服務協調中心(Dubbo支持Redis)

購物車

新浪用戶消息時間線

抽獎邏輯(禮物、轉發)

點贊、簽到、打卡

商品標簽

用戶(商品)關注(推薦)模型

電商產品篩選

排行榜


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM