【Redis深度歷險】那些年Redis的數據結構


Redis端口號6379的來源

Redis的端口號是6379,但這個端口號並不是隨機選擇的,源於"MERZ",這個單詞在手機當中的對應數字就是6379。"MERZ"在Redis作者Antirez的好友圈當中代表愚蠢的意思。

數據結構

Redis的key只能是字符串,value可以是String,Hash,List,Sorted Set(Zset)。

String

Redis的字符串是動態字符串(SDS Simple Dynamic String ),內部結構有點兒類似於java的ArrayList,都是采取預分配來減少內存的頻繁擴容。如圖len是實際字符串的長度,capacity是預分配的空間(數組容量)。創建字符串時,len和capacity一樣長,使用字節數組存放內容。

struct SDS<T> {
    T capacity; // 數組容量
    T len; // 數組長度
    byte flags; // 特殊標識位
    byte[] content; // 數組內容
}

  • 如果在1M以內,都是加倍擴充容量
  • 如果超過1M則,每次擴容1M
  • 字符串的最大容量是512M

String的一些基礎操作

  • 普通get set
127.0.0.1:6379> set name amber
OK
127.0.0.1:6379> get name
"amber"
127.0.0.1:6379> exists name
(integer) 1
127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> 

  • 批量mset,mget
127.0.0.1:6379> set name amber
OK
127.0.0.1:6379> set name2 nick
OK
127.0.0.1:6379> mget name name2
1) "amber"
2) "nick"
127.0.0.1:6379> mset name3 wade name4 hellen
OK
127.0.0.1:6379> mget name name2 name3 name4
1) "amber"
2) "nick"
3) "wade"
4) "hellen"
127.0.0.1:6379> 

  • 設置過期時間
  1. 第一種 expire
127.0.0.1:6379> set name amber
OK
127.0.0.1:6379> expire name 5
(integer) 1
127.0.0.1:6379> get name
"amber"
//等待5s
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> 
  1. 利用setex
    setex name 時間 value
127.0.0.1:6379> setex name 5 amber
OK
127.0.0.1:6379> get name
"amber"
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> 

  • 自增自減
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> incr age
(integer) 19
127.0.0.1:6379> incrby age 5
(integer) 24
127.0.0.1:6379> incrby age -5
(integer) 19
127.0.0.1:6379> decr age
(integer) 18
127.0.0.1:6379> 

List

Redis的list結構有點像Java中的LinkedList,但實際上地產不僅僅是簡單的linkedlist,底層是quicklist(太深入了等待作者以后學習...)

特點

list的插入刪除效率很高,時間復雜度為O(1),但是索引的定位就很慢,即O(n)

操作

  • 左進右出(隊列)
127.0.0.1:6379> lpush names amber nick wade
(integer) 3
127.0.0.1:6379> rpop names
"amber"
127.0.0.1:6379> rpop names
"nick"
127.0.0.1:6379> rpop names
"wade"
127.0.0.1:6379> rpop names
(nil)
127.0.0.1:6379> 

當然你也可以左近左出(棧),可以自己實驗一下。

  • 索引操作
  1. lindex相當於java的get(int index)根據索引取值,但是因為要遍歷鏈表,如果數據很大,導致開銷增大
  2. ltrim key index1 index2 保留index1和index2之間的數據
127.0.0.1:6379> lpush names amber nick wade
(integer) 3
127.0.0.1:6379> lindex names 0
"wade"
127.0.0.1:6379> lindex names 1
"nick"
127.0.0.1:6379> lindex names 2
"amber"
127.0.0.1:6379> ltrim names 0 1
127.0.0.1:6379> lindex names 0
"wade"
127.0.0.1:6379> lindex names 1
"nick"
127.0.0.1:6379> lindex names 2
(nil)
127.0.0.1:6379> 

hash(散列)

Redis的hash類似java中的HashMap

特點

Redis中的Hash進行rehash時區別於java中的HashMap。
在redis進行rehash時會同時保留新舊兩個結構,並在后續的定時任務當中慢慢把舊的數據移動到新數據。

操作

127.0.0.1:6379> hmset person name amber age 18
OK
127.0.0.1:6379> hgetall person
1) "name"
2) "amber"
3) "age"
4) "18"
127.0.0.1:6379> hget person name
"amber"
127.0.0.1:6379> hset person gender 1
(integer) 1
127.0.0.1:6379> hgetall person
1) "name"
2) "amber"
3) "age"
4) "18"
5) "gender"
6) "1"

set

Redis中的set相當於java中的HashSet,內部相當於實現了一個字典

特點

value唯一

操作

127.0.0.1:6379> sadd names amber
(integer) 1
127.0.0.1:6379> sadd names amber
(integer) 0
127.0.0.1:6379> sadd names nick wade
(integer) 2
127.0.0.1:6379> smembers names
1) "amber"
2) "wade"
3) "nick"

zset(sorted set)

Redis中的zset相當於java中sorted set和HashMap的結合。在set的基礎上還可以給value賦予score(排序的權重)

特點

zset因為有score需要排序,但是采用普通的鏈表查找銷量過低。因此zst采用層級制度。有點類似於國家->省級->市->xxx。最底層的鄉鎮肯帝就是我們的L0層級了,所有的元素都串聯在一起,每個幾個元素就選出市位於L2,同樣的道理每隔幾個L2層級的元素就選出省位於L3層級。當我們插入新的節點的時候,只需要從最頂層開始進行查找定位到相應位置就行了。是不是有點兒像數組的二分查找。

操作

其實還有一些操作,不過這里就不展示了

127.0.0.1:6379> zadd names 2 amber
(integer) 1
127.0.0.1:6379> zadd names 3 wade
(integer) 1
127.0.0.1:6379> zadd names 1 nick
(integer) 1
127.0.0.1:6379> zrange names 0 2
1) "nick"
2) "amber"
3) "wade"
127.0.0.1:6379> 

數據結構知識點拓展

  • redis的所有數據結構都可以設置時間
1. 設置時間
expire key 時間
2. 查看時間
ttl key


免責聲明!

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



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