|

資源列表:
Redis 命令參考
Commands
Redis是什么
Redis是一個(gè)開源(BSD許可)的內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ),用作數(shù)據(jù)庫(kù)、緩存和消息中間件。它支持多種數(shù)據(jù)結(jié)構(gòu),如字符串、哈希表、列表、無(wú)序集合、有序集合的范圍查詢,位圖、基數(shù)統(tǒng)計(jì)和地理空間索引的與查詢。Redis內(nèi)置復(fù)制、Lua腳本、LRU回收、事務(wù)和不同級(jí)別的磁盤持久化,并通過(guò)哨兵和自動(dòng)分區(qū)提供高可用性集群。
單線程結(jié)構(gòu)
- 純內(nèi)存數(shù)據(jù)庫(kù),瓶頸不在內(nèi)存,在于網(wǎng)絡(luò)IO
- 單線程,避免頻繁切換上下文
- 異步阻塞I/O(多路復(fù)用)
持久化
RDB(Redis DataBase)持久化
- 快照
- 優(yōu)點(diǎn):適合備份、還原、恢復(fù)數(shù)據(jù)快、最大化 Redis 的性能
- 缺點(diǎn):兩次快照間的數(shù)據(jù)會(huì)丟失、數(shù)據(jù)集比較龐大時(shí),
fork() 可能會(huì)非常耗時(shí)
AOF(Append Only File)持久化
- 日志
- 優(yōu)點(diǎn):數(shù)據(jù)完整性高、可讀性高、可重寫(重寫后的新 AOF 文件包含了恢復(fù)當(dāng)前數(shù)據(jù)集所需的最小命令集合)
- 缺點(diǎn):體積大、慢于RDB、有bug
事務(wù)
multi開啟事務(wù),exec執(zhí)行事務(wù)

可以看到,redis事務(wù)實(shí)現(xiàn)原理是將要執(zhí)行的命令,存儲(chǔ)到一個(gè)隊(duì)列中,依次執(zhí)行,報(bào)錯(cuò)時(shí)停止并取消事務(wù),不報(bào)錯(cuò)則提交事務(wù)。
例外:不會(huì)回滾的情況:
當(dāng)一個(gè)事務(wù)中某一條(多條)命令加入隊(duì)列不報(bào)錯(cuò),執(zhí)行時(shí)才會(huì)報(bào)錯(cuò),則redis會(huì)忽略錯(cuò)誤繼續(xù)執(zhí)行。
使用watch監(jiān)視一個(gè)(或多個(gè)) key ,如果在事務(wù)執(zhí)行之前這個(gè)(或這些) key 被其他命令所改動(dòng),那么事務(wù)將被打斷。當(dāng)exec被調(diào)用時(shí), 不管事務(wù)是否成功執(zhí)行, 對(duì)所有鍵的監(jiān)視都會(huì)被取消?;蛘哒{(diào)用unwatch手動(dòng)取消監(jiān)控。
管道
- pipeline通過(guò)減少客戶端與redis的通信次數(shù)來(lái)實(shí)現(xiàn)降低往返延時(shí)時(shí)間,而且Pipeline 實(shí)現(xiàn)的原理是隊(duì)列,而隊(duì)列的原理是時(shí)先進(jìn)先出,這樣就保證數(shù)據(jù)的順序性。
- 適用場(chǎng)景:批量操作、可靠性要求不高、
Lua腳本
Lua是一個(gè)高效的輕量級(jí)腳本語(yǔ)言,用標(biāo)準(zhǔn)C語(yǔ)言編寫并以源代碼形式開放, 其設(shè)計(jì)目的是為了嵌入應(yīng)用程序中,從而為應(yīng)用程序提供靈活的擴(kuò)展和定制功能,從定義上來(lái)說(shuō), Redis 中的腳本本身就是一種事務(wù), 所以任何在事務(wù)里可以完成的事, 在腳本里面也能完成。 并且一般來(lái)說(shuō), 使用腳本要來(lái)得更簡(jiǎn)單,并且速度更快。
- 通過(guò)lua腳本可以原子執(zhí)行多條redis命令
- 執(zhí)行l(wèi)ua腳本期間,會(huì)阻塞所有命令操作
使用腳本的好處
- 減少網(wǎng)絡(luò)開銷,在Lua腳本中可以把多個(gè)命令放在同一個(gè)腳本中運(yùn)行
- 原子操作,redis會(huì)將整個(gè)腳本作為一個(gè)整體執(zhí)行,中間不會(huì)被其他命令插入。換句話說(shuō),編寫腳本的過(guò)程中無(wú)需擔(dān)心會(huì)出現(xiàn)競(jìng)態(tài)條件
- 復(fù)用性,客戶端發(fā)送的腳本會(huì)永遠(yuǎn)存儲(chǔ)在redis中,這意味著其他客戶端可以復(fù)用這一腳本來(lái)完成同樣的邏輯
多數(shù)據(jù)庫(kù)支持
默認(rèn)支持16個(gè)數(shù)據(jù)庫(kù);可以理解為一個(gè)命名空間
跟關(guān)系型數(shù)據(jù)庫(kù)不一樣的點(diǎn)
- redis不支持自定義數(shù)據(jù)庫(kù)名詞
- 每個(gè)數(shù)據(jù)庫(kù)不能單獨(dú)設(shè)置授權(quán)
- 每個(gè)數(shù)據(jù)庫(kù)之間并不是完全隔離的。 可以通過(guò)flushall命令清空redis實(shí)例面的所有數(shù)據(jù)庫(kù)中的數(shù)據(jù)
通過(guò) select dbid 去選擇不同的數(shù)據(jù)庫(kù)命名空間 。 dbid的取值范圍默認(rèn)是0 -15
分布式集群
Redis Cluster中,Sharding采用slot(槽)的概念,一共分成16384個(gè)槽,這有點(diǎn)兒類似前面講的pre sharding思路。對(duì)于每個(gè)進(jìn)入Redis的鍵值對(duì),根據(jù)key進(jìn)行散列,分配到這16384個(gè)slot中的某一個(gè)中。使用的hash算法也比較簡(jiǎn)單,就是CRC16后16384取模。Redis集群中的每個(gè)node(節(jié)點(diǎn))負(fù)責(zé)分?jǐn)傔@16384個(gè)slot中的一部分,也就是說(shuō),每個(gè)slot都對(duì)應(yīng)一個(gè)node負(fù)責(zé)處理。當(dāng)動(dòng)態(tài)添加或減少node節(jié)點(diǎn)時(shí),需要將16384個(gè)槽做個(gè)再分配,槽中的鍵值也要遷移。當(dāng)然,這一過(guò)程,在目前實(shí)現(xiàn)中,還處于半自動(dòng)狀態(tài),需要人工介入。Redis集群,要保證16384個(gè)槽對(duì)應(yīng)的node都正常工作,如果某個(gè)node發(fā)生故障,那它負(fù)責(zé)的slots也就失效,整個(gè)集群將不能工作。為了增加集群的可訪問(wèn)性,官方推薦的方案是將node配置成主從結(jié)構(gòu),即一個(gè)master主節(jié)點(diǎn),掛n個(gè)slave從節(jié)點(diǎn)。這時(shí),如果主節(jié)點(diǎn)失效,Redis Cluster會(huì)根據(jù)選舉算法從slave節(jié)點(diǎn)中選擇一個(gè)上升為主節(jié)點(diǎn),整個(gè)集群繼續(xù)對(duì)外提供服務(wù)。這非常類似服務(wù)器節(jié)點(diǎn)通過(guò)Sentinel監(jiān)控架構(gòu)成主從結(jié)構(gòu),只是Redis Cluster本身提供了故障轉(zhuǎn)移容錯(cuò)的能力。
- redis sharding
- codis
- twemproxy
支持的數(shù)據(jù)類型、常用命令、常用場(chǎng)景
String
默認(rèn)存儲(chǔ)最大容量為512M
常用命令:set、get、incr、decr、append、strlen、mget、setnx
List
有序,可重復(fù)
常用命令:lpush、rpush、lpop、rpop、llen、lrange、lrem、lset
- lpush+lpop:Stack(棧)
- lpush+rpop:Queue(隊(duì)列)
- lpush+ltrim:Capped Collection(有限集合)
- lpush+brpop:Message Queue(消息隊(duì)列)
- blpop:事件提醒(替代輪詢)
Hash
不支持?jǐn)?shù)據(jù)類型的嵌套
適合存儲(chǔ)對(duì)象
常用命令:hset、hget、[hmset](http://doc./hash/hmset
,.html)、hmget、hgetall、hexists、hincrby、hsetnx、hdel
Set
無(wú)序、不重復(fù)
常用命令:sadd、srem、smembers、sdiff、sunion、sinter
- sadd:標(biāo)簽
- sinter:交集
- sunion:并集
SortedSet
有序、不重復(fù)
常用命令:zadd、zrange
- zcount:統(tǒng)計(jì)信息
- zrevrange:排行榜
key
常用命令:expire、ttl
Script
常用命令:eval
Redis安裝
安裝
首先,到redis官網(wǎng)找到要安裝的redis版本,Redis下載頁(yè),我們這里選用v4.0.11,依次執(zhí)行下面命令:
# wget http://download./releases/redis-4.0.11.tar.gz
# tar xzf redis-4.0.11.tar.gz
# cd redis-4.0.11
# make
到此安裝完成,然后可以通過(guò)make test測(cè)試編譯狀態(tài)
# make test
無(wú)報(bào)錯(cuò)完成編譯應(yīng)該會(huì)有這樣的輸出:

報(bào)錯(cuò):需要tcl 8.5以上來(lái)運(yùn)行redis test
You need tcl 8.5 or newer in order to run the Redis test
make: *** [test] Error 1
下面安裝tcl8.6.1:
# wget http://downloads./tcl/tcl8.6.1-src.tar.gz
# sudo tar xzvf tcl8.6.1-src.tar.gz
# cd tcl8.6.1/unix/
# sudo ./configure
# sudo make
# sudo make install
再次運(yùn)行make test,沒問(wèn)題之后,運(yùn)行最后一步,完成安裝:
# make install

直接啟動(dòng):
# ./redis-server ../redis.conf

后臺(tái)啟動(dòng)redis,只需修改redis.conf配置文件的daemonize yes,再次啟動(dòng)即可。

安裝啟動(dòng)相關(guān)命令
啟動(dòng)redis服務(wù)器:
# ./redis-server ../redis.conf
停止redis服務(wù):
# ./redis-cli shutdown
連接本地啟動(dòng)好的redis:
# redis-cli
根據(jù)ip端口連接redis:
# redis-cli -h 127.0.0.1 -p 6379
查看當(dāng)前是否設(shè)置了密碼
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) ""
設(shè)置密碼
127.0.0.1:6379> config set requirepass 123456 //密碼是123456
OK
使用總結(jié)
關(guān)于key
- 建議key不要太長(zhǎng),不要超過(guò)1024字節(jié),占用內(nèi)存且會(huì)降低查詢效率
- 建議統(tǒng)一命名規(guī)則,例如:String:001:zhangsan:age
使用 bitmap 實(shí)現(xiàn)用戶上線次數(shù)統(tǒng)計(jì)
Bitmap 對(duì)于一些特定類型的計(jì)算非常有效。
假設(shè)現(xiàn)在我們希望記錄自己網(wǎng)站上的用戶的上線頻率,比如說(shuō),計(jì)算用戶 A 上線了多少天,用戶 B 上線了多少天,諸如此類,以此作為數(shù)據(jù),從而決定讓哪些用戶參加 beta 測(cè)試等活動(dòng) —— 這個(gè)模式可以使用 SETBIT 和 BITCOUNT 來(lái)實(shí)現(xiàn)。
比如說(shuō),每當(dāng)用戶在某一天上線的時(shí)候,我們就使用 SETBIT ,以用戶名作為 key ,將那天所代表的網(wǎng)站的上線日作為 offset 參數(shù),并將這個(gè) offset 上的為設(shè)置為 1 。
舉個(gè)例子,如果今天是網(wǎng)站上線的第 100 天,而用戶 peter 在今天閱覽過(guò)網(wǎng)站,那么執(zhí)行命令 SETBIT peter 100 1 ;如果明天 peter 也繼續(xù)閱覽網(wǎng)站,那么執(zhí)行命令 SETBIT peter 101 1 ,以此類推。
當(dāng)要計(jì)算 peter 總共以來(lái)的上線次數(shù)時(shí),就使用 BITCOUNT 命令:執(zhí)行 BITCOUNT peter ,得出的結(jié)果就是 peter 上線的總天數(shù)。
更詳細(xì)的實(shí)現(xiàn)可以參考博文(墻外) Fast, easy, realtime metrics using Redis bitmaps 。
緩存
緩存一致性
- 先更新庫(kù)數(shù)據(jù),再刪除緩存
緩存擊穿和緩存雪崩
分布式鎖的實(shí)現(xiàn)
setnx+lua實(shí)現(xiàn)
public class RedisTool {
private static final String LOCK_SUCCESS = "OK";
private static final String SET_IF_NOT_EXIST = "NX";
private static final String SET_WITH_EXPIRE_TIME = "PX";
private static final Long RELEASE_SUCCESS = 1L;
// 獲取鎖
public static boolean getLock(Jedis jedis, String lockKey, String requestId, int expireTime) {
String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
return false;
}
// 釋放鎖
public static boolean releaseLock(Jedis jedis, String lockKey, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
return false;
}
}
搶紅包,秒殺的實(shí)現(xiàn)
incr+lua腳本實(shí)現(xiàn)
參考鏈接:
http://doc.>
https://blog.csdn.net/liqingtx/article/details/60330555

|