1、什么是Redis?
Redis本質上是一個Key-Value類型的內存數據庫,整個數據庫統統加載在內存當中進行操作,定期通過異步操作把數據庫數據flush到硬盤上進行保存。因為是純內存操作,Redis的性能非常出色,每秒可以處理超過 10萬次讀寫操作,是已知性能最快的Key-Value DB。
Redis的出色之處不僅僅是性能,Redis最大的魅力是支持保存多種數據結構,此外單個value的最大限制是1GB,不像 memcached只能保存1MB的數據,因此Redis可以用來實現很多有用的功能,比如用List來做FIFO雙向鏈表,實現一個輕量級的高性能消息隊列服務,用Set可以做高性能的tag系統等等。
另外Redis也可以對存入的Key-Value設置expire時間,因此也可以被當作一 個功能加強版的memcached來用。 Redis的主要缺點是數據庫容量受到物理內存的限制,不能用作海量數據的高性能讀寫,因此Redis適合的場景主要局限在較小數據量的高性能操作和運算上。
2、Redis 的特點有哪些?
- Redis支持數據的持久化,可以將內存中的數據保持在磁盤中,重啟的時候可以再次加載進行使用。
- Redis不僅僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
- Redis支持數據的備份,即master-slave模式的數據備份。
3、Redis 支持哪幾種數據結構,底層原理解釋一下
Redis支持5種數據類型
- string:字符串
- list:列表
- hash:散列表
- set:無序集合
- zset:有序集合
底層原理
字符串(String)
與其它編程語言或其它鍵值存儲提供的字符串非常相似,鍵(key)------值(value) (字符串格式),字符串擁有一些操作命令,如:get set del 還有一些比如自增或自減操作等等。redis是使用C語言開發,但C中并沒有字符串類型,只能使用指針或符數組的形式表示一個字符串,所以redis設計了一種簡單動態字符串(SDS[Simple Dynamic String])作為底實現:
定義SDS對象,此對象中包含三個屬性:
- len buf中已經占有的長度(表示此字符串的實際長度)
- free buf中未使用的緩沖區長度
- buf[] 實際保存字符串數據的地方
所以取字符串的長度的時間復雜度為O(1),另,buf[]中依然采用了C語言的以\0結尾可以直接使用C語言的部分標準C字符串庫函數。
空間分配原則:當len小于IMB(1024*1024)時增加字符串分配空間大小為原來的2倍,當len大于等于1M時每次分配 額外多分配1M的空間。
由此可以得出以下特性:
- redis為字符分配空間的次數是小于等于字符串的長度N,而原C語言中的分配原則必為N。降低了分配次數提高了追加速度,代價就是多占用一些內存空間,且這些空間不會自動釋放。
- 二進制安全的
- 高效的計算字符串長度(時間復雜度為O(1))
- 高效的追加字符串操作。
列表(List)
redis對鍵表的結構支持使得它在鍵值存儲的世界中獨樹一幟,一個列表結構可以有序地存儲多個字符串,擁有例如:lpush lpop rpush rpop等等操作命令。在3.2版本之前,列表是使用ziplist和linkedlist實現的,在這些老版本中,當列表對象同時滿足以下兩個條件時,列表對象使用ziplist編碼:
- 列表對象保存的所有字符串元素的長度都小于64字節
- 列表對象保存的元素數量小于512個
- 當有任一條件 不滿足時將會進行一次轉碼,使用linkedlist。
哈希(hash)
redis的散列可以存儲多個鍵 值 對之間的映射,散列存儲的值既可以是字符串又可以是數字值,并且用戶同樣可以對散列存儲的數字值執行自增操作或者自減操作。散列可以看作是一個文檔或關系數據庫里的一行。hash底層的數據結構實現有兩種:
一種是ziplist,上面已經提到過。當存儲的數據超過配置的閥值時就是轉用hashtable的結構。這種轉換比較消耗性能,所以應該盡量避免這種轉換操作。同時滿足以下兩個條件時才會使用這種結構:
- 當鍵的個數小于hash-max-ziplist-entries(默認512)
- 當所有值都小于hash-max-ziplist-value(默認64)
另一種就是hashtable。這種結構的時間復雜度為O(1),但是會消耗比較多的內存空間。
集合(Set)
redis的集合和列表都可以存儲多個字符串,它們之間的不同在于,列表可以存儲多個相同的字符串,而集合則通過使用散列表(hashtable)來保證自已存儲的每個字符串都是各不相同的(這些散列表只有鍵,但沒有與鍵相關聯的值),redis中的集合是無序的。還可能存在另一種集合,那就是intset,它是用于存儲整數的有序集合,里面存放同一類型的整數。共有三種整數:int16_t、int32_t、int64_t。查找的時間復雜度為O(logN),但是插入的時候,有可能會涉及到升級(比如:原來是int16_t的集合,當插入int32_t的整數的時候就會為每個元素升級為int32_t)這時候會對內存重新分配,所以此時的時間復雜度就是O(N)級別的了。注意:intset只支持升級不支持降級操作。
intset在redis.conf中也有一個配置參數set-max-intset-entries默認值為512。表示如果entry的個數小于此值,則可以編碼成REDIS_ENCODING_INTSET類型存儲,節約內存。否則采用dict的形式存儲。
有序集合(zset)
有序集合和散列一樣,都用于存儲鍵值對:有序集合的鍵被稱為成員(member),每個成員都是各不相同的。有序集合的值則被稱為分值(score),分值必須為浮點數。有序集合是redis里面唯一一個既可以根據成員訪問元素(這一點和散列一樣),又可以根據分值以及分值的排列順序訪問元素的結構。它的存儲方式也有兩種:
- 是ziplist結構。(與上面的hash中的ziplist類似,member和score順序存放并按score的順序排列)
- 另一種是skiplist與dict的結合。(skiplist是一種跳躍表結構,用于有序集合中快速查找,大多數情況下它的效率與平衡樹差不多,但比平衡樹實現簡單。redis的作者對普通的跳躍表進行了修改,包括添加span\tail\backward指針、score的值可重復這些設計,從而實現排序功能和反向遍歷的功能。)
一般跳躍表的實現,主要包含以下幾個部分:
- 表頭(head):指向頭節點
- 表尾(tail):指向尾節點
- 節點(node):實際保存的元素節點,每個節點可以有多層,層數是在創建此節點的時候隨機生成的一個數值,而且每一層都是一個指向后面某個節點的指針。
- 層(level):目前表內節點的最大層數
- 長度(length):節點的數量。
跳躍表的遍歷總是從高層開始,然后隨著元素值范圍的縮小,慢慢降低到低層。
【加分項】特殊數據結構
HyperLogLog、Geo、Pub/Sub,Redis Module(RediSearch、redis-cell、Redis-ML、BloomFilter等)
HyperLogLog
Redis HyperLogLog 是用來做基數統計的算法,HyperLogLog 的優點是,在輸入元素的數量或者體積非常非常大時,計算基數所需的空間總是固定 的、并且是很小的(12k左右)。
【實現原理】
基數就是統計集合中不重復的元素的個數。最簡單的算法是,建立一個集合將元素添加進去,新增元素之前先判斷元素是否存在,若已存在就不添加。這樣的問題是:
1、這個集合占用的空間非常大。
2、集合大了之后判斷一個元素是否存在變得困難。
基數計數方法
1、B樹:插入和查找效率很高,但是不節省存儲空間,hashset數據結構。
2、數據庫也可以做,準確但性能較差。
3、bitmap:維護一個bit數組進行邏輯運算,這樣確實大大減少內存占用
如果一個數據id長度是32bit,那么統計1億的數據大概需要空間300M左右,空間占用不容小覷,而且加載到內存中運算時間也很長。
4、概率算法
概率算法不操作數據,而是根據概率算法估算出大約多少個基數,由于是基于概率的,所以基數值可能有偏差。算法主要有Linear Counting(LC),LogLog Counting(LLC)和HyperLogLog Counting(HLL)。其中HLL在空間復雜度和錯誤率方面最優。一億的數據HLL需要內存 不到1k就能做到,效率驚人。
【應用場景】
使用的場景都是一個大集合中,找出不重復的基數數量。比如
獲取每天獨立IP的訪問量
獲取每天某個頁面user的獨立訪問量
這樣的的場景不能考慮使用set去做,因為涉及大量的存儲,占用很大的空間,可以考慮采用HyerLogLog去做。
【命令】
pfadd key element... //向hyperloglog中添加元素
pfcount key... //計算hyperloglog的獨立總數
pfmerge destkey sourcekey... //合并多個hyperloglog
Geo
Redis 的 GEO 是 3.2 版本的新特性。這個功能可以將用戶給定的地理位置(經緯度)信息儲存起來, 并對這些信息進行操作(計算兩地距離、范圍等)。
【命令】
geoadd key longitude(經度) latitude(維度) member(地理位置標識) //可以同時添加多個
geoadd location 116.28 39.55 beijing geopos key member .. //獲取地理位置的信息
geodist key member1 member2 unit //獲取兩個地理位置的距離
unit:m 米 km 千米 mi英里 ft尺
geodist cities tianjin beijin km
Pub/Sub
“發布/訂閱”在redis中,被設計的非常輕量級和簡潔,它做到了消息的“發布”和“訂閱”的基本能力;但是尚未提供關于消息的持久化等各種企業級的特性。
一個Redis client發布消息,其他多個redis client訂閱消息,發布的消息“即發即失”,
redis不會持久保存發布的消息;
消息訂閱者也將只能得到訂閱之后的消息,通道中此前的消息將無從獲得。
pub發布的消息不會持久化,sub是阻塞等待消息,只能獲取訂閱之后產生的消息,一段時間內sub沒有收到消息或pub沒有生產消息,sub連接會被回收(因為sub是阻塞的).
4、Redis 有哪幾種數據淘汰策略(內存淘汰機制)?
- noeviction:禁止淘汰數據,返回錯誤當內存限制達到并且客戶端嘗試執行會讓更多內存被使用的命令(大部分的寫入指令,但DEL和幾個例外)
- allkeys-lru: 從數據集中回收最少使用的鍵(LRU),使得新添加的數據有空間存放。
- volatile-lru: 從已設置過期的數據集中回收最少使用的鍵(LRU),但僅限于在過期集合的鍵,使得新添加的數據有空間存放。
- allkeys-random: 從數據集中回收隨機的鍵使得新添加的數據有空間存放。
- volatile-random: 從已設置過期的數據集中回收隨機的鍵使得新添加的數據有空間存放,但僅限于在過期集合的鍵。
- volatile-ttl: 從已設置過期的數據集中回收馬上要過期的鍵,并且優先回收存活時間(TTL)較短的鍵,使得新添加的數據有空間存放。
記憶方式:
單詞組成:3個volatile開頭的,2個all_keys開頭。都是lru,random,只有volatile有ttl方式。最后加一個noeviction
volatile:指的都是快過期的數據集。
all_keys:是所有的數據集。
lrc:是選擇最近長時間不使用的,一般用作緩存機制。
random:就是隨機選一個。
ttl:就是過期時間的設置
noeviction:不做任何設置
默認的內存策略是noeviction,在Redis中LRU算法是一個近似算法,默認情況下,Redis隨機挑選5個鍵,并且從中選取一個最近最久未使用的key進行淘汰,在配置文件中可以通過maxmemory-samples的值來設置redis需要檢查key的個數,但是檢查的越多,耗費的時間也就越久,但是結構越精確(也就是Redis從內存中淘汰的對象未使用的時間也就越久~),設置多少,綜合權衡。
一般來說,推薦使用的策略是volatile-lru,并辨識Redis中保存的數據的重要性。對于那些重要的,絕對不能丟棄的數據(如配置類數據等),應不設置有效期,這樣Redis就永遠不會淘汰這些數據。對于那些相對不是那么重要的,并且能夠熱加載的數據(比如緩存最近登錄的用戶信息,當在Redis中找不到時,程序會去DB中讀取),可以設置上有效期,這樣在內存不夠時Redis就會淘汰這部分數據。
配置文件
# maxmemory <bytes>
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key according to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
# The default is:
# maxmemory-policy noeviction
5、Redis 的過期策略怎么設計比較合理?
redis 過期策略是:定期刪除+惰性刪除。
定期刪除:指的是 redis 默認是每隔 100ms 就隨機抽取一些設置了過期時間的 key,檢查其是否過期,如果過期就刪除。
惰性刪除:在我們獲取key的時候,先檢查key的過期時間,如果過期,便進行刪除。
通過上面這兩種方式,依舊會存在一些key,過期之后還會存在內存中,怎么辦?使用內存淘汰機制!
6、為什么 Redis 需要把所有數據放到內存中?
Redis為了達到最快的讀寫速度將數據都讀到內存中,并通過異步的方式將數據寫入磁盤。所以redis具有快速和數據持久化的特征。如果不將數據放在內存中,磁盤I/O速度會嚴重影響redis的性能。
如果設置了最大使用的內存,則數據已有記錄數達到內存限值后不能繼續插入新值,會執行內存淘汰機制。
7、Redis 適用場景有哪些?(Redis常用的業務場景有哪些?)
會話緩存(Session Cache),最常用的一種使用Redis的情景是會話緩存(session cache)。用Redis緩存會話比其他存儲(如Memcached)的優勢在于:Redis提供持久化。當維護一個不是嚴格要求一致性的緩存時,如果用戶的購物車信息全部丟失,大部分人都會不高興的,現在,他們還會這樣嗎?幸運的是,隨著 Redis 這些年的改進,很容易找到怎么恰當的使用Redis來緩存會話的文檔。甚至廣為人知的商業平臺Magento也提供Redis的插件。
全頁緩存(FPC)除基本的會話token之外,Redis還提供很簡便的FPC平臺。回到一致性問題,即使重啟了Redis實例,因為有磁盤的持久化,用戶也不會看到頁面加載速度的下降,這是一個極大改進,類似PHP本地FPC。再次以Magento為例,Magento提供一個插件來使用Redis作為全頁緩存后端。此外,對WordPress的用戶來說,Pantheon有一個非常好的插件 wp-redis,這個插件能幫助你以最快速度加載你曾瀏覽過的頁面。
隊列Reids在內存存儲引擎領域的一大優點是提供 list 和 set 操作,這使得Redis能作為一個很好的消息隊列平臺來使用。Redis作為隊列使用的操作,就類似于本地程序語言(如Python)對 list 的 push/pop 操作。如果你快速的在Google中搜索“Redis queues”,你馬上就能找到大量的開源項目,這些項目的目的就是利用Redis創建非常好的后端工具,以滿足各種隊列需求。例如,Celery有一個后臺就是使用Redis作為broker,你可以從這里去查看。
排行榜/計數器Redis在內存中對數字進行遞增或遞減的操作實現的非常好。集合(Set)和有序集合(Sorted Set)也使得我們在執行這些操作的時候變的非常簡單,Redis只是正好提供了這兩種數據結構。所以,我們要從排序集合中獲取到排名最靠前的10個用戶–我們稱之為“user_scores”,我們只需要像下面一樣執行即可:當然,這是假定你是根據你用戶的分數做遞增的排序。如果你想返回用戶及用戶的分數,你需要這樣執行:ZRANGE user_scores 0 10 WITHSCORESAgora Games就是一個很好的例子,用Ruby實現的,它的排行榜就是使用Redis來存儲數據的,你可以在這里看到。
位操作(大數據處理)用于數據量上億的場景下,例如幾億用戶系統的簽到,去重登錄次數統計,某用戶是否在線狀態等等。 騰訊10億用戶,要幾毫秒內查詢到某個用戶是否在線,你能怎么做?千萬別說給每個用戶建立一個key,然后挨個記(你可以算一下需要的內存會很恐怖,而且這種類似的需求很多,騰訊光這個得多花多少錢。。)這里要用到位操作——使用setbit、getbit、bitcount命令。原理是: Redis內構建一個足夠長的數組,每個數組元素只能是0和1兩個值,然后這個數組的下標index用來表示我們上面例子里面的用戶id(必須是數字哈),那么很顯然,這個幾億長的大數組就能通過下標和元素值(0和1)來構建一個記憶系統,上面我說的幾個場景也就能夠實現。用到的命令是:setbit、getbit、bitcount。
發布/訂閱 最后(但肯定不是最不重要的)是Redis的發布/訂閱功能。發布/訂閱的使用場景確實非常多。我已看見人們在社交網絡連接中使用,還可作為基于發布/訂閱的腳本觸發器,甚至用Redis的發布/訂閱功能來建立聊天系統!
8、Memcache 與 Redis 的區別都有哪些?(Redis 相比 memcached 有哪些優勢?)
緩存類型:Redis和Memcache都是將數據存放在內存中,都是內存數據庫。不過Memcache還可用于緩存其他東西,例如圖片、視頻等等。
存儲數據結構:Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,hash,sorted set等數據結構的存儲。
虛擬內存:Redis當物理內存用完時,可以將一些很久沒用到的value 交換到磁盤
過期策略:Memcache在set時就指定,例如set key1 0 0 8,即永不過期。Redis可以通過例如expire 設定,例如expire name 10
分布式:設定Memcache集群,利用magent做一主多從;Redis可以做一主多從。都可以一主一從
存儲數據安全:Memcache掛掉后,數據沒了;Redis可以定期保存到磁盤(持久化)
災難恢復:Memcache掛掉后,數據不可恢復; redis數據丟失后可以通過aof恢復
數據備份:Redis支持數據的備份,即master-slave模式的數據備份。
有持久化需求或者對數據結構和處理有高級要求的應用,選擇Redis;其他簡單的key/value存儲,選擇memcache。
綜合對比
1.性能上:
性能上都很出色,具體到細節,由于Redis只使用單核,而Memcached可以使用多核,所以平均每一個核上Redis在存儲小數據時比
Memcached性能更高。而在100k以上的數據中,Memcached性能要高于Redis,雖然Redis最近也在存儲大數據的性能上進行優化,但是比起 Memcached,還是稍有遜色。
2.內存空間和數據量大小上:
MemCached可以修改最大內存,采用LRU算法。Redis增加了VM的特性,突破了物理內存的限制。
3.操作便利上:
MemCached數據結構單一,僅用來緩存數據,而Redis支持更加豐富的數據類型,也可以在服務器端直接對數據進行豐富的操作,這樣可以減少網絡IO次數和數據體積。
4.可靠性上:
MemCached不支持數據持久化,斷電或重啟后數據消失,但其穩定性是有保證的。Redis支持數據持久化和數據恢復,允許單點故障,但是同時也會付出性能的代價。
5.應用場景上:
Memcached:動態系統中減輕數據庫負載,提升性能;做緩存,適合多讀少寫,大數據量的情況(如人人網大量查詢用戶信息、好友信息、文章信息等)。
Redis:適用于對讀寫效率要求都很高,數據處理業務復雜和對安全性要求較高的系統(如新浪微博的計數和微博發布部分系統,對數據安全性、讀寫要求都很高)。
Redis 相比 memcached 的優勢
- memcached所有的值均是簡單的字符串,Redis作為其替代者,支持更為豐富的數據類型
- Redis的速度比memcached快很多
- Redis可以持久化其數據
- Redis支持數據的備份,即master-slave模式的數據備份。
- 使用底層模型不同,它們之間底層實現方式 以及與客戶端之間通信的應用協議不一樣。Redis直接自己構建了VM 機制 ,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
- value大小:Redis最大可以達到1GB,而memcache只有1MB
9、Redis常用的命令有哪些?
常用管理命令
1、啟動Redis
> redis-server [--port 6379]
如果命令參數過多,建議通過配置文件來啟動Redis。
> redis-server [xx/xx/redis.conf]
6379是Redis默認端口號。
2、連接Redis
> ./redis-cli [-h 127.0.0.1 -p 6379]
3、停止Redis
> redis-cli shutdown
//直接殺進程
> kill redis-pid
以上兩條停止Redis命令效果一樣。
4、發送命令
給Redis發送命令有兩種方式:
1.redis-cli帶參數運行,如:
> redis-cli shutdown not connected>
這樣默認是發送到本地的6379端口。
2.redis-cli不帶參數運行,如:
> ./redis-cli 127.0.0.1:6379> shutdown not connected>
5、測試連通性
127.0.0.1:6379> ping PONG
key操作命令
獲取所有鍵
語法:keys pattern
127.0.0.1:6379> keys *
1) "phpkey"
*表示通配符,表示任意字符,會遍歷所有鍵顯示所有的鍵列表,時間復雜度O(n),在生產環境不建議使用。
獲取鍵總數
語法:dbsize
127.0.0.1:6379> dbsize
(integer) 6
獲取鍵總數時不會遍歷所有的鍵,直接獲取內部變量,時間復雜度O(1)。
查詢鍵是否存在
語法:exists key [key ...]
127.0.0.1:6379> exists phpkey php
(integer) 2
查詢查詢多個,返回存在的個數。
刪除鍵
語法:del key [key ...]
127.0.0.1:6379> del php phpkey
(integer) 1
可以刪除多個,返回刪除成功的個數。
查詢鍵類型
語法: type key
127.0.0.1:6379> type phpkey
string
移動鍵
語法:move key db
如把phpkey移到2號數據庫。
127.0.0.1:6379> move phpkey 2
(integer) 1
127.0.0.1:6379> select 2
OK
127.0.0.1:6379[2]> keys *
1) "phpkey"
查詢key的生命周期(秒)
秒語法:ttl key
毫秒語法:pttl key
127.0.0.1:6379[2]> ttl phpkey
(integer) -1
-1:永遠不過期。
設置過期時間
秒語法:expire key seconds
毫秒語法:pexpire key milliseconds
127.0.0.1:6379[2]> expire phpkey 60
(integer) 1
127.0.0.1:6379[2]> ttl phpkey
(integer) 55
設置永不過期
語法:persist key
127.0.0.1:6379[2]> persist phpkey
(integer) 1
更改鍵名稱
語法:rename key newkey
OK
字符串操作命令
字符串是Redis中最基本的數據類型,單個數據能存儲的最大空間是512M。
存放鍵值
語法:set key value [EX seconds] [PX milliseconds] [NX|XX]
nx:如果key不存在則建立,xx:如果key存在則修改其值,也可以直接使用setnx/setex命令。
127.0.0.1:6379> set phpkey 666
OK
獲取鍵值
語法:get key
127.0.0.1:6379[2]> get phpkey
"666"
值遞增/遞減
如果字符串中的值是數字類型的,可以使用incr命令每次遞增,不是數字類型則報錯。
語法:incr key
127.0.0.1:6379[2]> incr phpkey
(integer) 667
一次想遞增N用incrby命令,如果是浮點型數據可以用incrbyfloat命令遞增。
同樣,遞減使用decr、decrby命令。
批量存放鍵值
語法:mset key value [key value ...]
127.0.0.1:6379[2]> mset php1 1 php2 2 php3 3
OK
獲取獲取鍵值
語法:mget key [key ...]
127.0.0.1:6379[2]> mget php1 php2
1) "1"
2) "2"
Redis接收的是UTF-8的編碼,如果是中文一個漢字將占3位返回。
獲取值長度
語法:strlen key
127.0.0.1:6379[2]> strlen phpkey
(integer) 3
追加內容
語法:append key value
127.0.0.1:6379[2]> append phpkey hi
(integer) 5
向鍵值尾部添加,如上命令執行后由666變成666hi
獲取部分字符
語法:getrange key start end
> 127.0.0.1:6379[2]> getrange phpkey 0 4
"phps"
集合操作命令
集合類型和列表類型相似,只不過是集合是無序且不可重復的。
集合
存儲值
語法:sadd key member [member ...]
// 這里有8個值(2個php),只存了7個
127.0.0.1:6379> sadd langs php kotlin c++ go ruby python lua (integer) 7
獲取元素
獲取所有元素語法:smembers key
127.0.0.1:6379> smembers langs
1) "php"
2) "kotlin"
3) "c++"
4) "go"
5) "ruby"
6) "python"
7) "lua"
隨機獲取語法:srandmember langs count
127.0.0.1:6379> srandmember langs 3
1) "php"
2) "python"
3) "go"
判斷集合是否存在元素
語法:sismember key member
127.0.0.1:6379> sismember langs go
(integer) 1
獲取集合元素個數
語法:scard key
127.0.0.1:6379> scard langs
(integer) 7
刪除集合元素
語法:srem key member [member ...]
127.0.0.1:6379> srem langs ruby kotlin
(integer) 2
彈出元素
語法:spop key [count]
127.0.0.1:6379> spop langs 2
1) "go"
2) "php"
有序集合
和列表的區別:
列表使用鏈表實現,兩頭快,中間慢。有序集合是散列表和跳躍表實現的,即使讀取中間的元素也比較快。
列表不能調整元素位置,有序集合能。
有序集合比列表更占內存。
存儲值
語法:zadd key [NX|XX] [CH] [INCR] score member [score member ...]
127.0.0.1:6379> zadd footCounts 16011 tid 20082 huny 2893 nosy (integer) 3
獲取元素分數
語法:zscore key member
127.0.0.1:6379> zscore footCounts tid
"16011"
獲取排名范圍排名語法:zrange key start stop [WITHSCORES]
// 獲取所有,沒有分數
127.0.0.1:6379> zrange footCounts 0 -1
1) "nosy"
2) "tid"
3) "huny"
// 獲取所有及分數
127.0.0.1:6379> zrange footCounts 0 -1 Withscores
1) "nosy"
2) "2893"
3) "tid"
4) "16011"
5) "huny"
6) "20082"
獲取指定分數范圍排名語法:zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
127.0.0.1:6379> zrangebyscore footCounts 3000 30000 withscores limit 0 1
1) "tid"
2) "16011"
增加指定元素分數
語法:zincrby key increment member
127.0.0.1:6379> zincrby footCounts 2000 tid
"18011"
獲取集合元素個數
語法:zcard key
127.0.0.1:6379> zcard footCounts
(integer) 3
獲取指定范圍分數個數
語法:zcount key min max
127.0.0.1:6379> zcount footCounts 2000 20000
(integer) 2
刪除指定元素
語法:zrem key member [member ...]
127.0.0.1:6379> zrem footCounts huny
(integer) 1
獲取元素排名
語法:zrank key member
127.0.0.1:6379> zrank footCounts tid
(integer) 1
列表操作命令
列表類型是一個有序的字段串列表,內部是使用雙向鏈表實現,所有可以向兩端操作元素,獲取兩端的數據速度快,通過索引到具體的行數比較慢。
列表類型的元素是有序且可以重復的。
存儲值
左端存值語法:lpush key value [value ...]
127.0.0.1:6379> lpush list lily sandy
(integer) 2
右端存值語法:rpush key value [value ...]
(integer) 4
索引存值語法:lset key index value
127.0.0.1:6379> lset list 3 uto
OK
彈出元素
左端彈出語法:lpop key
127.0.0.1:6379> lpop list
"sandy"
右端彈出語法:rpop key
127.0.0.1:6379> rpop list
"kitty"
獲取元素個數
語法:llen key
127.0.0.1:6379> llen list
(integer) 2
獲取列表元素
兩邊獲取語法:lrange key start stop
127.0.0.1:6379> lpush users tom kitty land pony jack maddy
(integer) 6
127.0.0.1:6379> lrange users 0 3
1) "maddy"
2) "jack"
3) "pony"
4) "land"
// 獲取所有
127.0.0.1:6379> lrange users 0 -1
1) "maddy"
2) "jack"
3) "pony"
4) "land"
5) "kitty"
6) "tom"
// 從右端索引
127.0.0.1:6379> lrange users -3 -1
1) "land"
2) "kitty"
3) "tom"
索引獲取語法:lindex key index
127.0.0.1:6379> lindex list 2
"ketty"
// 從右端獲取
127.0.0.1:6379> lindex list -5
"sady"
刪除元素
根據值刪除語法:lrem key count value
127.0.0.1:6379> lpush userids 111 222 111 222 222 333 222 222
(integer) 8
// count=0 刪除所有
127.0.0.1:6379> lrem userids 0 111
(integer) 2
// count > 0 從左端刪除前count個
127.0.0.1:6379> lrem userids 3 222
(integer) 3
// count < 0 從右端刪除前count個
127.0.0.1:6379> lrem userids -3 222
(integer) 2
范圍刪除語法:ltrim key start stop
// 只保留2-4之間的元素
127.0.0.1:6379> ltrim list 2 4
OK
散列操作命令
redis字符串類型鍵和值是字典結構形式,這里的散列類型其值也可以是字典結構。
存放鍵值
單個語法:hset key field value
127.0.0.1:6379> hset user name phpkey
(integer) 1
多個語法:hmset key field value [field value ...]
127.0.0.1:6379> hmset user name phpkey age 20 address china
OK
不存在時語法:hsetnx key field value
127.0.0.1:6379> hsetnx user tall 180
(integer) 0
獲取字段值
單個語法:hget key field
127.0.0.1:6379> hget user age
"20"
多個語法:hmget key field [field ...]
127.0.0.1:6379> hmget user name age address
1) "phpkey"
2) "20"
3) "china"
獲取所有鍵與值語法:hgetall key
127.0.0.1:6379> hgetall user
1) "name"
2) "phpkey"
3) "age"
4) "20"
5) "address"
6) "china"
獲取所有字段語法:hkeys key
127.0.0.1:6379> hkeys user
1) "name"
2) "address"
3) "tall"
4) "age"
獲取所有值語法:hvals key
127.0.0.1:6379> hvals user
1) "phpkey"
2) "china"
3) "170"
4) "20"
判斷字段是否存在
語法:hexists key field
127.0.0.1:6379> hexists user address
(integer) 1
獲取字段數量
語法:hlen key
127.0.0.1:6379> hlen user
(integer) 4
遞增/減
語法:hincrby key field increment
127.0.0.1:6379> hincrby user tall -10
(integer) 170
刪除字段
語法:hdel key field [field ...]
127.0.0.1:6379> hdel user age
(integer) 1