Redis第一天

Redis基礎(chǔ)入門

1,redis 介紹

redis 是一種基于鍵值對(duì)(key-value)數(shù)據(jù)庫(kù),其中 value 可以為 string、hash、list、set、zset 等多種數(shù)據(jù)結(jié)構(gòu),可以滿足很多應(yīng)用場(chǎng)景。還提供了鍵過(guò)期,發(fā)布訂閱,事務(wù),流水線,等附加功能;

流水線: Redis 的流水線功能允許客戶端一次將多個(gè)命令請(qǐng)求發(fā)送給服務(wù)器, 并將被執(zhí)行的多個(gè)命令請(qǐng)求的結(jié)果在一個(gè)命令回復(fù)中全部返回給客戶端,使用這個(gè)功能可以有效地減少客戶端在執(zhí)行多個(gè)命令時(shí)需要與服務(wù)器進(jìn)行通信的次數(shù)。

2,特性:

1〉速度快,數(shù)據(jù)放在內(nèi)存中,官方給出的讀寫性能 10 萬(wàn)/S,與機(jī)器性能也有關(guān);

a, 數(shù)據(jù)放內(nèi)存中是速度快的主要原因

b, C 語(yǔ)言實(shí)現(xiàn),與操作系統(tǒng)距離近

c, 使用了單線程架構(gòu),預(yù)防多線程可能產(chǎn)生的競(jìng)爭(zhēng)問(wèn)題

2〉鍵值對(duì)的數(shù)據(jù)結(jié)構(gòu)服務(wù)器;

3〉豐富的功能:見上功能;

4〉簡(jiǎn)單穩(wěn)定:?jiǎn)尉€程;

5〉持久化:發(fā)生斷電或機(jī)器故障,數(shù)據(jù)可能會(huì)丟失,持久化到硬盤;

6〉主從復(fù)制:實(shí)現(xiàn)多個(gè)相同數(shù)據(jù)的 redis 副本;

7〉高可用和分布式:哨兵機(jī)制實(shí)現(xiàn)高可用,保證 redis 節(jié)點(diǎn)故障發(fā)現(xiàn)和自動(dòng)轉(zhuǎn)移;

8〉客戶端語(yǔ)言多:java php python c c++ nodejs 等 。

3,使用場(chǎng)景:

1,緩存:合理使用緩存加快數(shù)據(jù)訪問(wèn)速度,降低后端數(shù)據(jù)源壓力

2,排行榜:按照熱度排名,按照發(fā)布時(shí)間排行,主要用到列表和有序集合

3,計(jì)數(shù)器應(yīng)用:視頻網(wǎng)站播放數(shù),網(wǎng)站瀏覽數(shù),使用 redis 計(jì)數(shù)

4,社交網(wǎng)絡(luò):贊、踩、粉絲、下拉刷新

5,消息隊(duì)列:發(fā)布和訂閱

4,正確安裝與啟動(dòng)

1,linux 上安裝,windows 也能裝,但我們以 linux 環(huán)境為主

2,配置、啟動(dòng)、操作、關(guān)閉

3,redis-server 啟動(dòng):????

1,默認(rèn)配置:redis-server, 日志輸出版本信息,端口 6379

2,運(yùn)行啟動(dòng):redis-server --port 6380 不建議

3,配置文件啟動(dòng): redis-server /opt/redis/redis.conf,靈活,生產(chǎn)環(huán)境使用這種

4,redis-cli 啟動(dòng):

1,>交互式:redis-cli -h {host} -p {prot}連接到 redis 服務(wù),沒有 h 默認(rèn)連 127.0

redis-cli -h 127.0.0.1 -p 6379? ? ?//沒有 p 默認(rèn)連 6379

2,>命令式:redis-cli -h 127.0.0.1 -p 6379 get hello //取 key=hello 的 value

3,>停止 redis 服務(wù): redis-cli shutdown

注意:??

a,關(guān)閉時(shí):斷開連接,持久化文件生成,相對(duì)安全

b,還可以用 kill 關(guān)閉,此方式不會(huì)做持久化,還會(huì)造成緩沖區(qū)非法關(guān)閉,可能會(huì)造成 AOF 和丟失數(shù)據(jù)

c,關(guān)閉前生成持久化文件:使用 redis-cli -a 123456 登錄進(jìn)去,再 shutdown nosave|save

4,>重大版本:

1,版本號(hào)第二位為奇數(shù),為非穩(wěn)定版本(2.7、2.9、3.1)

2,第二為偶數(shù),為穩(wěn)定版本(2.6、2.8、3.0)

3,當(dāng)前奇數(shù)版本是下一個(gè)穩(wěn)定版本的開發(fā)版本,如 2.9 是 3.0 的開發(fā)版本


Redis重要的指令使用

1>全局命令

1,查看所有鍵:keys * set school enjoy set hello world

2,鍵總數(shù) dbsize //2 個(gè)鍵,如果存在大量鍵,線上禁止使用此指令

3,檢查鍵是否存在:exists key //存在返回 1,不存在返回 0

4,刪除鍵:del key //del hello school, 返回刪除鍵個(gè)數(shù),刪除不存在鍵返回 0

5,鍵過(guò)期:expire key seconds //set name test expire name 10 //10 秒過(guò)期 ;ttl 查看剩余的過(guò)期時(shí)間

6,鍵的數(shù)據(jù)結(jié)構(gòu)類型:type key //type hello //返回 string,鍵不存在返回 none

2>單線程架構(gòu)

列舉例子:三個(gè)客戶端同時(shí)執(zhí)行命令

客戶端 1:set name test

客戶端 2:incr num

客戶端 3:incr num

執(zhí)行過(guò)程:發(fā)送指令-〉執(zhí)行命令-〉返回結(jié)果;

執(zhí)行命令:?jiǎn)尉€程執(zhí)行,所有命令進(jìn)入隊(duì)列,按順序執(zhí)行,使用 I/O 多路復(fù)用解決 I/O 問(wèn)題,后面有介紹(通過(guò) select/poll/epoll/kqueue 這些 I/O 多路復(fù)用函數(shù)庫(kù),我們解決了一個(gè)線程處理多個(gè)連接的問(wèn)題);

單線程快原因:純內(nèi)存訪問(wèn), 非阻塞 I/O(使用多路復(fù)用),單線程避免線程切換和競(jìng)爭(zhēng)產(chǎn)生資源消耗 。

問(wèn)題:如果某個(gè)命令執(zhí)行,會(huì)造成其它命令的阻塞

3>字符串 <String>?

3.1,字符串類型:實(shí)際上可以是字符串(包括 XML JSON),還有數(shù)字(整形 浮點(diǎn)數(shù)),二進(jìn)制(圖片 音頻 視頻),最大不能超過(guò) 512MB ;

3.2,設(shè)值命令:set age 23 ex 10? ? ?//10 秒后過(guò)期 px 10000 毫秒過(guò)期

setnx name test? ? ? ? //不存在鍵 name 時(shí),返回 1 設(shè)置成功;存在的話失敗 0

set age 25 xx? ? ? ? ? ?//存在鍵 age 時(shí),返回 1 成功

場(chǎng)景:如果有多客戶同時(shí)執(zhí)行 setnx,只有一個(gè)能設(shè)置成功,可做分布式鎖

獲值命令:get age //存在則返回 value, 不存在返回 nil

批量設(shè)值:mset country china city beijing

批量獲取:mget country city address? ? ? ? ? ? ? ? ? ?//返回 china beigjin, address 為 nil

若沒有 mget 命令,則要執(zhí)行 n 次 get 命令

使用 mget=1 次網(wǎng)絡(luò)請(qǐng)求+redis 內(nèi)部 n 次查詢

3.3,計(jì)數(shù):incr age //必須為整數(shù)自加 1,非整數(shù)返回錯(cuò)誤,無(wú) age 鍵從 0 自增返回 1

decr age? ? ? ? ? ? ?//整數(shù) age 減 1

incrby age 2? ? ? ?//整數(shù) age+2

decrby age 2? ? ? //整數(shù) age -2

incrbyfloat score 1.1? ? ? ? ?//浮點(diǎn)型 score+1.1

3.4,append 追加指令:set name hello; append name world? ? ? ?//追加后成 helloworld

3.5,字符串長(zhǎng)度:set hello “世界”;strlen hello? ? ? ? ? ? ?//結(jié)果 6,每個(gè)中文占 3 個(gè)字節(jié)

3.6,截取字符串:set name helloworld ; getrange name 2 4? ? ? ? ? ? ? ? ? ? //返回 llo

3.7,內(nèi)部編碼:int:8 字節(jié)長(zhǎng)整理//set age 100; object encoding age? ? ? ? ?//返回 int

embstr:小于等于 39 字節(jié)串 set name bejin; object encodeing name? ? ? ? //embstr

raw:大于 39 字節(jié)的字符串 set a fsdfwerwerweffffffffffdfs? ? ? ? ? ? ? ? ? ? ? ? ?//返回 raw

3.8,應(yīng)用場(chǎng)景:

1,鍵值設(shè)計(jì):業(yè)務(wù)名:對(duì)象名:id:[屬性]

數(shù)據(jù)庫(kù)為 order, 用戶表 user,對(duì)應(yīng)的鍵可為 order:user:1 或 order:user:1:name

注意:redis 目前處于受保護(hù)模式,不允許非本地客戶端鏈接,可以通過(guò)給 redis設(shè)置密碼,然后客戶端鏈接的時(shí)候,寫上密碼就可以了。

127.0.0.1:6379> config set requirepass 123456 臨時(shí)生效

或者修改 redis.conf requirepass 123456,啟動(dòng)時(shí)./redis-server redis.conf 指定 conf

./redis-cli -p 6379 -a 12345678? ? ? ? ? ?//需要加入密碼才能訪問(wèn)

切換數(shù)據(jù)庫(kù):select 2

4>哈希 hash

是一個(gè) string 類型的 field 和 value 的映射表,hash 特適合用于存儲(chǔ)對(duì)象。

4.1 命令 hset key field value

設(shè)值:hset user:1 name james? ? ?//成功返回 1,失敗返回 0

取值:hget user:1 name? ? ? ? ?//返回 james

刪值:hdel user:1 age? ? ? ? ? //返回刪除的個(gè)數(shù)

計(jì)算個(gè)數(shù):hset user:1 name james; hset user:1 age 23; hlen user:1? ? ? ? ? ?//返回 2,user:1 有兩個(gè)屬性值

批量設(shè)值:hmset user:2 name james age 23 sex boy? ? ? ? ? ? ? ? //返回 OK

批量取值:hmget user:2 name age sex? ? ? ? ? ? ? ? ? //返回三行:james 23 boy

判斷 field 是否存在:hexists user:2 name? ? ? ? ? ? ?//若存在返回 1,不存在返回 0

獲取所有 field: hkeys user:2? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?// 返回 name age sex 三個(gè) field

獲取 user:2 所有 value:hvals user:2? ? ? ? ? ? ? ? // 返回 james 23 boy

獲取 user:2 所有 field 與 value:hgetall user:2? ? ? ? ? //name age sex james 23 boy 值

增加 1:hincrby user:2 age 1? ? ? ? //age+1

hincrbyfloat user:2 age 2? ? ? ? ? ? //浮點(diǎn)型加 2

4.2 內(nèi)部編碼:

ziplist<壓縮列表>和 hashtable<哈希表>;

當(dāng) field 個(gè)數(shù)少且沒有大的 value 時(shí),內(nèi)部編碼為 ziplist ;

如:hmset user:3 name james age 24; object encoding user:3? ? ? ? ? ?//返回 ziplist

當(dāng) value 大于 64 字節(jié),內(nèi)部編碼由 ziplist 變成 hashtable

如:hset user:4 address “fsgst64 字節(jié)”; object encoding user:3? ? ? ? ? //返回 hashtable

4.3 應(yīng)用場(chǎng)景:

比如將關(guān)系型數(shù)據(jù)表轉(zhuǎn)成 redis 存儲(chǔ):

使用 hash 后的存儲(chǔ)方式為:

如果有值為 NULL,那么如下:

HASH 類型是稀疏,每個(gè)鍵可以有不同的 filed, 若用 redis 模擬做關(guān)系復(fù)雜查詢開發(fā)困難,維護(hù)成本高 。

4.4 三種方案實(shí)現(xiàn)用戶信息存儲(chǔ)優(yōu)缺點(diǎn):

1,原生:

set user:1:name james;

set user:1:age 23;

set user:1:sex boy;

優(yōu)點(diǎn):簡(jiǎn)單直觀,每個(gè)鍵對(duì)應(yīng)一個(gè)值

缺點(diǎn):鍵數(shù)過(guò)多,占用內(nèi)存多,用戶信息過(guò)于分散,不用于生產(chǎn)環(huán)境

2,將對(duì)象序列化存入 redis:

set user:1 serialize(userInfo);

優(yōu)點(diǎn):編程簡(jiǎn)單,若使用序列化合理內(nèi)存使用率高

缺點(diǎn):序列化與反序列化有一定開銷,更新屬性時(shí)需要把 userInfo 全取出來(lái)進(jìn)行反序列化,更新后再序列化到 redis

3,使用 hash 類型:

hmset user:1 name james age 23 sex boy;

優(yōu)點(diǎn):簡(jiǎn)單直觀,使用合理可減少內(nèi)存空間消耗

缺點(diǎn):要控制 ziplist 與 hashtable 兩種編碼轉(zhuǎn)換,且 hashtable 會(huì)消耗更多內(nèi)存

總結(jié):對(duì)于更新不多的情況下,可以使用序列化,對(duì)于 VALUE 值不大于 64 字節(jié)可以使用 hash 類型 。

5>列表

5.1 用來(lái)存儲(chǔ)多個(gè)有序的字符串,一個(gè)列表最多可存 2 的 32 次方減 1 個(gè)元素;

因?yàn)橛行?,可以通過(guò)索引下標(biāo)獲取元素或某個(gè)范圍內(nèi)元素列表,列表元素可以重復(fù) 。

5.2 列表命令:

添加命令:rpush james c b a? ? ?//從右向左插入 cba, 返回值 3

lrange james 0 -1? ? ?//從左到右獲取列表所有元素 返回 c b a

lpush key c b a? ? ? ?//從左向右插入 cba

linsert james before b teacher? ? //在 b 之前插入 teacher, after 為之后,使用 lrange james 0 -1 查看:c teacher b a

查找命令: lrange key start end? ? //索引下標(biāo)特點(diǎn):從左到右為 0 到 N-1

lindex james -1? ? //返回最右末尾 a,-2 返回 b

llen james? ? ?//返回當(dāng)前列表長(zhǎng)度

lpop james? ? //把最左邊的第一個(gè)元素 c 刪除

rpop james? ? //把最右邊的元素 a 刪除


lrem key count value? ?//刪除指定元素

如:lpush test b b b b b j x z? ? ?//鍵 test 放入 z x j b b b b b

lrange test 0 -1? ? ? //查詢結(jié)果為 z x j b b b b b

lrem test 4 b? ? ? ? //從左右開始刪除 b 的元素,刪除 4 個(gè),若 lrem test 8 b, 刪除 8 個(gè) b, 但只有 5 個(gè)全部刪除

lrange test 0 -1? ? ?//刪除后的結(jié)果為 b j x z

lrem test 0 b? ? ? ?//檢索所有 b 全部刪除 j x z


lpush user b b b b b j x z //鍵 user 從左到右放入 z x j b b b b b

ltrim user 1 3 //只保留從第 2 到第 4 的元素,其它全刪

lrange user 0 -1 //查詢結(jié)果為 x j b, 其它已全被刪掉

lpush user01 z y x //鍵 user01 從左到右放入 x y z

lset user01 2 java // 把第 3 個(gè)元素 z 替換成 java

lrange user01 0 -1 //查詢結(jié)果為 x y java

應(yīng)用場(chǎng)景設(shè)計(jì): cacheListHashApplicationTest 用例

每個(gè)用戶有多個(gè)訂單 key 為 order:1 order:2 order:3, 結(jié)合 hmset

1, hmset order:1 orderId 1 money 36.6 time 2018-01-01

hmset order:2 orderId 2 money 38.6 time 2018-01-01

hmset order:3 orderId 3 money 39.6 time 2018-01-01

2,把訂單信息的 key 放到隊(duì)列

lpush user:1:order order:1 order:2 order:3

3,每新產(chǎn)生一個(gè)訂單,

hmset order:4 orderId 4 money 40.6 time 2018-01-01

4,追加一個(gè) order:4 放入隊(duì)列第一個(gè)位置

lpush user:1:order order:4

5,當(dāng)需要查詢用戶訂單記錄時(shí):

List orderKeys = lrange user:1 0 -1? ? ? ? //查詢 user:1 的所有訂單 key 值

for(Order order: orderKeys){

hmget order:1}

5.3 列表內(nèi)部編碼:

從 redis 的官網(wǎng)查閱了相關(guān)資料,在 3.2 版本以后,redis提供了 quicklist 內(nèi)部編碼,它結(jié)合了 ziplist 和 linkedlist 兩者的優(yōu)勢(shì),之前的 ziplist 是存在 BUG的,使用 quicklist 內(nèi)部編碼效率更高,所以我們現(xiàn)在 3.2 以后看不到這兩個(gè)編碼,只看到quicklist, 可以看一下https://matt.sh/redis-quicklist國(guó)外的這篇博客有重點(diǎn)提到。

感興趣的可以下一下 3.1 之前的版本。

6>集合 用戶標(biāo)簽,社交,查詢有共同興趣愛好的人,智能推薦

保存多元素,與列表不一樣的是不允許有重復(fù)元素,且集合是無(wú)序,一個(gè)集合最多可存 2 的 32 次方減 1 個(gè)元素,除了支持增刪改查,還支持集合交集、并集、差集;

6.1 命令:

exists user? ? //檢查 user 鍵值是否存在

sadd user a b c? ?//向 user 插入 3 個(gè)元素,返回 3

sadd user a b? ? //若再加入相同的元素,則重復(fù)無(wú)效,返回 0

smembers user? ? //獲取 user 的所有元素,返回結(jié)果無(wú)序

srem user a? ? //返回 1,刪除 a 元素

scard user? ? //返回 2,計(jì)算元素個(gè)數(shù)

sismember user a? ? //判斷元素是否在集合存在,存在返回 1,不存在 0

srandmember user 2? ? //隨機(jī)返回 2 個(gè)元素,2 為元素個(gè)數(shù)

spop user 2? ? //隨機(jī)返回 2 個(gè)元素 a b,并將 a b 從集合中刪除

smembers user? ? //此時(shí)已沒有 a b, 只有 c

集合的交集:

sadd user:1 zhangsan 24 girl

sadd user:2 james 24 boy? ?//初始化兩個(gè)集合

sinter user:1 user:2? ? //求兩集合交集, 此時(shí)返回 24

sadd user:3 wang 24 girl? ? //新增第三個(gè)元素

sinter user:1 user:2 user:3? ? //求三個(gè)集合的交集,此時(shí)返回 24

集合的并集(集合合并去重):

sunion user:1 user:2 user:3? ? //三集合合并(并集),去重 24

sdiff user:1 user:2? ?//1 和 2 差集,(zhangsan 24 girl)-(james 24 boy)=zhangsan girl

將交集(jj)、并集(bj)、差集(cj)的結(jié)果保存:

sinterstore user_jj user:1 user:2? ? //將 user:1 user:2 的交集保存到 user_jj

sunionstore user_bj user:1 user:2? ? //將 user:1 user:2 的(并)合集保存 user_bj

sdiffstore user_cj user:1 user:2? ? //將 user:1-user:2 的差集保存 user_cj

smemebers user_cj? ? // 返回 zhangsan girl

6.2 內(nèi)部編碼:

sadd user 1 2 3 4? ? ? ? ?//當(dāng)元素個(gè)數(shù)少(小于 512 個(gè))且都為整數(shù),redis 使用 intset減少內(nèi)存的使用

sadd user 1 2...513? ? ? //當(dāng)超過(guò) 512 個(gè)或不為整數(shù)(比如 a b)時(shí),編碼為 hashtable

object encoding user? ? //hashtables

6.3 使用場(chǎng)景:標(biāo)簽,社交,查詢有共同興趣愛好的人,智能推薦

使用方式:sadd user:1:fav basball fball pq

給用戶添加標(biāo)簽:sadd user:2:fav basball fball

或給標(biāo)簽添加用戶:

sadd basball:users user:1 user:3

sadd fball:users user:1 user:2 user:3

計(jì)算出共同感興趣的人:

sinter user:1:fav user2:fav

規(guī)則:sadd (常用于標(biāo)簽) spop/srandmember(隨機(jī),比如抽獎(jiǎng))

sadd+sinter (用于社交,查詢共同愛好的人,匹配)

7>有序集合

常用于排行榜,如視頻網(wǎng)站需要對(duì)用戶上傳視頻做排行榜,或點(diǎn)贊數(shù)與集合有聯(lián)系,不能有重復(fù)的成員。

7.1命令

zadd key score member [score member......]

zadd user:zan 200 james? ? //james 的點(diǎn)贊數(shù) 1, 返回操作成功的條數(shù) 1

zadd user:zan 200 james 120 mike 100 lee? ?// 返回 3

zadd test:1 nx 100 james? ? //鍵 test:1 必須不存在,主用于添加

zadd test:1 xx incr 200 james? ? //鍵 test:1 必須存在,主用于修改,此時(shí)為 300

zadd test:1 xx ch incr -299 james? ? //返回操作結(jié)果 1,300-299=1

zrange test:1 0 -1 withscores? ? //查看點(diǎn)贊(分?jǐn)?shù))與成員名

zcard test:1? ?//計(jì)算成員個(gè)數(shù), 返回 1

查點(diǎn)贊數(shù):

zadd test:2 nx 100 james? ? //新增一個(gè)集合

zscore test:2 james? ? //查看 james 的點(diǎn)贊數(shù)(分?jǐn)?shù)),返回 100

排名:

zadd user:3 200 james 120 mike 100 lee? ? ?//先插入數(shù)據(jù)

zrange user:3 0 -1 withscores? ? ?//查看分?jǐn)?shù)與成員

zrank user:3 james? ? ?//返回名次:第 3 名返回 2,從 0 開始到 2,共 3 名

zrevrank user:3 james? ? ?//返回 0, 反排序,點(diǎn)贊數(shù)越高,排名越前

刪除成員:

zrem user:3 jame mike? ? ?//返回成功刪除 2 個(gè)成員,還剩 lee

增加分?jǐn)?shù):

zincrby user:3 10 lee? ? //成員 lee 的分?jǐn)?shù)加 10

zadd user:3 xx incr 10 lee? ? //和上面效果一樣

返回指定排名范圍的分?jǐn)?shù)與成員:

zadd user:4 200 james 120 mike 100 lee? ? //先插入數(shù)據(jù)

zrange user:4 0 -1 withscores? ? ?//返回結(jié)果如下圖:

zrevrange user:4 0 -1 withscores? ? //倒序,結(jié)果如下圖

返回指定分?jǐn)?shù)范圍的成員:

zrangebyscore user:4 110 300 withscores? ? ? ? //返回 120 lee ,200 James, 由低到高

zrevrangebyscore user:4 300 110 withscores? ? //返回 200james 120lee,由高到低

zrangebyscore user:4 (110 +inf withscores? ? ? ? //110 到無(wú)限大,120mike 200james

zrevrangebyscore user:4 (110 -inf withscores? ? ? //無(wú)限小到 110,返回 100 lee

返回指定分?jǐn)?shù)范圍的成員個(gè)數(shù):

zcount user:4 110 300 //返回 2,由 mike120 和 james200 兩條數(shù)據(jù)

刪除指定排名內(nèi)的升序元素:

zremrangebyrank user:4 0 1 //分?jǐn)?shù)升序排列,刪除第 0 個(gè)與第 1 個(gè),只剩 james

刪除指定分?jǐn)?shù)范圍的成員:

zadd user:5 200 james 120 mike 100 lee? ? ?//先插入測(cè)試數(shù)據(jù)

zremrangebyscore user:5 100 300? ? ? ? ? ?//刪除分?jǐn)?shù)在 100 與 300 范圍的成員

zremrangebyscore user:5 (100 +inf? ? ? ? //刪除分?jǐn)?shù)大于 100(不包括 100),還剩 lee

有序集合交集:

格式:zinterstore destination numkeys key ... [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]

destination:交集產(chǎn)生新的元素存儲(chǔ)鍵名稱

numkeys: 要做交集計(jì)算的鍵個(gè)數(shù)

key :元素鍵值

weights:每個(gè)被選中的鍵對(duì)應(yīng)值乘 weight, 默認(rèn)為 1

初始化數(shù)據(jù):

zadd user:7 1 james 2 mike 4 jack 5 kate? ? //初始化 user:7 數(shù)據(jù)

zadd user:8 3 james 4 mike 4 lucy 2 lee 6 jim? ?//初始化 user:8 數(shù)據(jù)

交集例子:

zinterstore user_jj 2 user:7 user:8 aggregate sum? ?

?//2 代表鍵合并個(gè)數(shù),

?//aggregate sum 可加也不可加上,因?yàn)槟J(rèn)是 sum

//結(jié)果 user_jj:4james(1+3), 6mike(2+4)

zinterstore user_jjmax 2 user:7 user:8 aggregate max 或 min? ? ? ??

?//取交集最大的分?jǐn)?shù),返回結(jié)果 3james 4mike, min 取最小

weights:

zinterstore user_jjweight 2 user:7 user:8 weights 8 4 aggregate max

//1,取兩個(gè)成員相同的交集,user:7->1 james 2 mike; user:8->3 james 4 mike

//2,將 user:7->james 1*8=8, user:7->mike 2*8 =16, 最后 user:7 結(jié)果 8 james 16 mike;

//3,將 user:8-> james 3*4=12, user:8->mike 4*4=16,最后 user:8 結(jié)果 12 james 16 mike

//4,最終相乘后的結(jié)果,取最大值為 12 james 16mike

//5, zrange user_jjweight 0 -1 withscores 查詢結(jié)果為 12 james 16mike

總結(jié):將 user:7 成員值乘 8,將 user:8 成員值乘 4,取交集,取最大

有序集合并集(合并去重):

格式:zunionstore destination numkeys key ... [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]

destination:交集產(chǎn)生新的元素存儲(chǔ)鍵名稱

numkeys: 要做交集計(jì)算的鍵個(gè)數(shù)

key :元素鍵值

weights:每個(gè)被選中的鍵對(duì)應(yīng)值乘 weight, 默認(rèn)為 1

zunionstore user_jjweight2 2 user:7 user:8 weights 8 4 aggregate max

//與以上 zinterstore 一樣,只是取并集,指令一樣

7.2 有序集合內(nèi)部編碼

1,ziplist: zadd user:9 20 james 30 mike 40 lee

object encoding user:init

//當(dāng)元素個(gè)數(shù)少(小于 128 個(gè)),元素值小于 64 字節(jié)時(shí),使用 ziplist 編碼,可有效減少內(nèi)存的使用

2,skiplist: zadd user:10 20 james...... //大于 128 個(gè)元素或元素值大于 64 字節(jié)時(shí)為 skiplist 編碼

7.3 使用場(chǎng)景:

排行榜系統(tǒng),如視頻網(wǎng)站需要對(duì)用戶上傳的視頻做排行榜 。

點(diǎn)贊數(shù):zadd user:1:20180106 3 mike? ? ?//mike 獲得 3 個(gè)贊

再獲一贊:zincrby user:1:20180106 1 mike? ? //在 3 的基礎(chǔ)上加 1

用戶作弊,將用戶從排行榜刪掉:zrem user:1:20180106 mike

展示贊數(shù)最多的 5 個(gè)用戶:

zadd user:4:20160101 9 jack 10 jj 11 dd 3 james 4 lee 6 mark 7 kate

zrevrangebylex user:4:20160101 + - limit 0 5

查看用戶贊數(shù)與排名:

zscore user:1:20180106 mike zrank user:1:20180106 mike


Redis 緩存雪崩與穿透

1, 什么是雪崩?

前提:為節(jié)約內(nèi)存,Redis 一般會(huì)做定期清除操作 ;

1),當(dāng)查詢 key=james 的值,此時(shí) Redis 沒有數(shù)據(jù);

2),如果有 5000 個(gè)用戶并發(fā)來(lái)查詢 key=james,全到 Mysql 里去查, Mysql 會(huì)掛掉,導(dǎo)致雪崩;

解決方案如下:

A,設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過(guò)期;

B,加互斥鎖,互斥鎖參考代碼,如下代碼如下:

2, 什么是穿透?

前提:黑客模擬一個(gè)不存在的訂單號(hào) xxxx 。

1,Redis 中無(wú)此值

2,Mysql 中也無(wú)此值, 但一直被查詢

解決方案:

1,對(duì)訂單表所有數(shù)據(jù)查詢出來(lái)放到布隆過(guò)濾器, 經(jīng)過(guò)布隆過(guò)濾器處理的數(shù)據(jù)很小(只存 0 或 1);

2,每次查訂單表前,先到過(guò)濾器里查詢當(dāng)前訂單號(hào)狀態(tài)是0還是1, 0的話代表數(shù)據(jù)庫(kù)沒有數(shù)據(jù), 直接拒絕查詢。


Redis 持久化

redis 支持 RDB 和 AOF 兩種持久化機(jī)制,持久化可以避免因進(jìn)程退出而造成數(shù)據(jù)丟失;

RDB

1.RDB 持久化把當(dāng)前進(jìn)程數(shù)據(jù)生成快照(.rdb)文件保存到硬盤的過(guò)程,有手動(dòng)觸發(fā)和自動(dòng)觸發(fā);

手動(dòng)觸發(fā)有 save 和 bgsave 兩命令;

save 命令:阻塞當(dāng)前 Redis,直到 RDB 持久化過(guò)程完成為止,若內(nèi)存實(shí)例比較大會(huì)造成長(zhǎng)時(shí)間阻塞,線上環(huán)境不建議用它;

bgsave 命令:redis 進(jìn)程執(zhí)行 fork 操作創(chuàng)建子進(jìn)程,由子進(jìn)程完成持久化,阻塞時(shí)間很短(微秒級(jí)),是 save 的優(yōu)化,在執(zhí)行 redis-cli shutdown 關(guān)閉 redis 服務(wù)時(shí),如果沒有開啟 AOF 持久化,自動(dòng)執(zhí)行 bgsave;

顯然 bgsave 是對(duì) save 的優(yōu)化。

bgsave 運(yùn)行流程:

2.RDB 文件的操作

命令:config set dir /usr/local //設(shè)置 rdb 文件保存路徑

備份:bgsave //將 dump.rdb 保存到 usr/local 下

恢復(fù):將 dump.rdb 放到 redis 安裝目錄與 redis.conf 同級(jí)目錄,重啟 redis 即可

優(yōu)點(diǎn):1,壓縮后的二進(jìn)制文,適用于備份、全量復(fù)制,用于災(zāi)難恢復(fù)

? ? ? ? ? ?2,加載 RDB 恢復(fù)數(shù)據(jù)遠(yuǎn)快于 AOF 方式

缺點(diǎn):1,無(wú)法做到實(shí)時(shí)持久化,每次都要?jiǎng)?chuàng)建子進(jìn)程,頻繁操作成本過(guò)高

? ? ? ? ? ? 2,保存后的二進(jìn)制文件,存在老版本不兼容新版本 rdb 文件的問(wèn)題

AOF

1.AOF 持久化

針對(duì) RDB 不適合實(shí)時(shí)持久化,redis 提供了 AOF 持久化方式來(lái)解決 。

開啟:redis.conf 設(shè)置:appendonly yes (默認(rèn)不開啟,為 no)

默認(rèn)文件名:appendfilename "appendonly.aof" 流程說(shuō)明:

1,所有的寫入命令(set hset)會(huì) append 追加到 aof_buf 緩沖區(qū)中

2,AOF 緩沖區(qū)向硬盤做 sync 同步

3,隨著 AOF 文件越來(lái)越大,需定期對(duì) AOF 文件 rewrite 重寫,達(dá)到壓縮

4,當(dāng) redis 服務(wù)重啟,可 load 加載 AOF 文件進(jìn)行恢復(fù)

AOF持久化流程:命令寫入(append),文件同步(sync),文件重寫(rewrite),重啟加載(load)

2.redis 的 AOF 配置詳解:

appendonly yes? ? ? ? ? ? ? ?//啟用 aof 持久化方式

# appendfsync always? ? ?//每收到寫命令就立即強(qiáng)制寫入磁盤,最慢的,但是保證完全的持久化,不推薦使用

appendfsync everysec? ? ?//每秒強(qiáng)制寫入磁盤一次,性能和持久化方面做了折中,推薦

# appendfsync no? ? ? ? ? ? ?//完全依賴 os,性能最好,持久化沒保證(操作系統(tǒng)自身的同步)

no-appendfsync-on-rewrite yes? ? ? ? ?//正在導(dǎo)出 rdb 快照的過(guò)程中,要不要停止同步 aof

auto-aof-rewrite-percentage 100? ? ? //aof 文件大小比起上次重寫時(shí)的大小,增長(zhǎng)率100%時(shí),重寫

auto-aof-rewrite-min-size 64mb? ? ? ?//aof 文件,至少超過(guò) 64M 時(shí),重寫

3.如何從 AOF 恢復(fù)?

1. 設(shè)置 appendonly yes;

2. 將 appendonly.aof 放到 dir 參數(shù)指定的目錄;

3. 啟動(dòng) Redis,Redis 會(huì)自動(dòng)加載 appendonly.aof 文件。

4.redis 重啟時(shí)恢復(fù)加載 AOF 與 RDB 順序及流程:

1,當(dāng) AOF 和 RDB 文件同時(shí)存在時(shí),優(yōu)先加載

2,若關(guān)閉了 AOF,加載 RDB 文件

3,加載 AOF/RDB 成功,redis 重啟成功

4,AOF/RDB 存在錯(cuò)誤,redis 啟動(dòng)失敗并打印錯(cuò)誤信息

RDB與AOF對(duì)比


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容