從零入門Redis到實際實踐

  • mutil/exec

  • operate big value(collection)

  • string

    結構

    keyvalue
    helloworld
    counter1
    bits101111101110

    可以是字符串(json);數字,以及二進制

    使用場景

    • 緩存

    • 計數器

    • 分佈式鎖

    API

    命令說明時間複雜度
    get key獲取key對應的valueO(1)
    set key value設置key valueO(1)
    del key刪除key-valueO(1)
    incrkey自增1, 如果key不存在,自增後get(key) = 1O(1)
    decrkey自減1, 如果key不存在,自增後get(key) = -1O(1)
    incrby key kkey自增k, 如果key不存在,自增後get(key) = kO(1)
    decr key kkey自減k, 如果key不存在,自增後get(key) = -kO(1)
    set key value不管可以是否存在O(1)
    setnx key valuekey不存在,才設置
    O(1)
    set key value xxkey存在,才設置O(1)
    mget key1 key2 key3批量獲取key,原子操作O(N)
    mset key1 value1 key2 value2批量設置key-valueO(1)
    getset key newvalueset key newvalue並返回舊的valueO(1)
    append key value將value追加到舊的valueO(1)
    strlen key 返回字符串的長度(注意中文,utf8下一個中文佔用3個字符)O(1)
    incrbyfloat key 3.5增加key對應的值3.5O(1)
    getrange key start end獲取字符串指定下標所有的值O(1)
    setrange key index value設置指定下標所有對應的值O(1)

    練習

    127.0.0.1:6382> set hello "world" OK 127.0.0.1:6382> get hell (nil) 127.0.0.1:6382> get hello "world" 127.0.0.1:6382> del hello (integer) 1 127.0.0.1:6382> get hello (nil) 127.0.0.1:6382> get counter (nil) 127.0.0.1:6382> incr counter (integer) 1 127.0.0.1:6382> get counter "1" 127.0.0.1:6382> incrby counter 99 (integer) 100 127.0.0.1:6382> get counter "100" 127.0.0.1:6382> decr counter (integer) 99 127.0.0.1:6382> get counter "99" 127.0.0.1:6382> decrby counter 100 (integer) -1 127.0.0.1:6382> get counter "-1" 127.0.0.1:6382> exists php (integer) 0 127.0.0.1:6382> set php good OK 127.0.0.1:6382> setnx php bad (integer) 0 127.0.0.1:6382> set php best xx OK 127.0.0.1:6382> get php "best" 127.0.0.1:6382> exists java (integer) 0 127.0.0.1:6382> setnx java best (integer) 1 127.0.0.1:6382> set java easy xx OK 127.0.0.1:6382> get java "easy" 127.0.0.1:6382> set hello world OK 127.0.0.1:6382> getset hello php "world" 127.0.0.1:6382> get hello "php" 127.0.0.1:6382> append hell ",php" (integer) 4 127.0.0.1:6382> get hello "php" 127.0.0.1:6382> append hello ",php" (integer) 7 127.0.0.1:6382> get hello "php,php" 127.0.0.1:6382> strlen hello (integer) 7 127.0.0.1:6382> set hello "吳軍旗" OK 127.0.0.1:6382> strlen hello (integer) 9

    n次get操作

    從零入門Redis到實際實踐

    ** 1次mget操作**

    從零入門Redis到實際實踐

    實戰

    • 記錄網站每個用戶個人主頁的訪問量

    incr userid: pageview (**主要的是:單線程,所以無競爭)**)
    • 緩存視頻的基本信息(數據源在mysql中)偽代碼

    從零入門Redis到實際實踐

    • 分佈式id生成器(單線程的好處)

    從零入門Redis到實際實踐

    incr id

    hash

    哈希鍵值結構

    從零入門Redis到實際實踐

    特點

    • mapmap

    • small redis

    • field不能相同,value可以相同

    API

    命令說明時間複雜度
    hget key field獲取hash key對應field的valueO(1)
    hset key field value設置has key 對應的field的valueO(1)
    hexists key field判斷hash key 是否有fieldO(1)
    hlen key獲取hash key field的數量O(1)
    hmget key field1 field2...fieldN批量獲取hash key的一批field對應的值O(N)
    hset key field1 value1 field2 value2...fieldN valueN批量設置hash key的一批field valueO(1)
    hgetall key返回hash key對應所有的field和valueO(N)
    hvals key返回hash key對應所有的field的valueO(N)
    hkeys key返回hash key對應所有的fieldO(N)
    hsetnx key field value設置has key 對應的field的value(如果field已經存在,則失敗)O(1)
    hincrby key field intCounterhash key對應的field的value自增intCounterO(1)
    hincrbyfloat key field floatCounter浮點數版本O(1)

    注意 小心使用hgetall(牢記單線程)

    練習

    127.0.0.1:6382> hset user1 age 26 (integer) 1 127.0.0.1:6382> hset user1 name wujunqi (integer) 1 127.0.0.1:6382> hget all user1 (nil) 127.0.0.1:6382> hgetall user1 1) "age" 2) "26" 3) "name" 4) "wujunqi" 127.0.0.1:6382> hdel user1 age (integer) 1 127.0.0.1:6382> hgetall user1 1) "name" 2) "wujunqi" 127.0.0.1:6382> hget user1 name "wujunqi" 127.0.0.1:6382> hexists user1 name (integer) 1 127.0.0.1:6382> hlen user1 (integer) 1 127.0.0.1:6382> hmset user2 name xiaofang age 26 OK 127.0.0.1:6382> hmget user2 name age 1) "xiaofang" 2) "26" 127.0.0.1:6382> hgetall user2 1) "name" 2) "xiaofang" 3) "age" 4) "26" 127.0.0.1:6382> hvals user2 1) "xiaofang" 2) "26" 127.0.0.1:6382> hkeys user2 1) "name" 2) "age" 127.0.0.1:6382> hincrby user age 2 (integer) 2 127.0.0.1:6382> hgetall user2 1) "name" 2) "xiaofang" 3) "age" 4) "26" 127.0.0.1:6382> hincrby user2 age 2 (integer) 28 127.0.0.1:6382> hgetall user2 1) "name" 2) "xiaofang" 3) "age" 4) "28" 127.0.0.1:6382> hincrbyfloat user2 age 2.0 "30" 127.0.0.1:6382> hincrbyfloat user2 age 2.5 "32.5" 127.0.0.1:6382> hgetall user2 1) "name" 2) "xiaofang" 3) "age" 4) "32.5" 

    list

    列表結構

    從零入門Redis到實際實踐

    特點

    • 有序

    • 可以重複

    • 左右兩邊插入彈出

    API

    從零入門Redis到實際實踐

    練習

    127.0.0.1:6382> rpush list1 a b c d (integer) 4 127.0.0.1:6382> lpush list1 e f g h i (integer) 9 127.0.0.1:6382> lrange list1 0 -1 1) "i" 2) "h" 3) "g" 4) "f" 5) "e" 6) "a" 7) "b" 8) "c" 9) "d" 127.0.0.1:6382> linsert list1 before i wu (integer) 10 127.0.0.1:6382> lrange list1 0 -1 1) "wu" 2) "i" 3) "h" 4) "g" 5) "f" 6) "e" 7) "a" 8) "b" 9) "c" 10) "d" 127.0.0.1:6382> linsert list1 after i jun (integer) 11 127.0.0.1:6382> lrange list1 0 -1 1) "wu" 2) "i" 3) "jun" 4) "h" 5) "g" 6) "f" 7) "e" 8) "a" 9) "b" 10) "c" 11) "d" 127.0.0.1:6382> lpop list1 "wu" 127.0.0.1:6382> rpop list1 "d" 127.0.0.1:6382> lrange list1 0 -1 1) "i" 2) "jun" 3) "h" 4) "g" 5) "f" 6) "e" 7) "a" 8) "b" 9) "c" 127.0.0.1:6382> lrem list1 1 i (integer) 1 127.0.0.1:6382> lrange list1 0 -1 1) "jun" 2) "h" 3) "g" 4) "f" 5) "e" 6) "a" 7) "b" 8) "c" 127.0.0.1:6382> rpush list1 c c c c c (integer) 13 127.0.0.1:6382> ltrem list1 -3 c (error) ERR unknown command 'ltrem' 127.0.0.1:6382> lrem list1 -3 c (integer) 3 127.0.0.1:6382> lrange list1 0 -1 1) "jun" 2) "h" 3) "g" 4) "f" 5) "e" 6) "a" 7) "b" 8) "c" 9) "c" 10) "c" 127.0.0.1:6382> lindex list 0 (nil) 127.0.0.1:6382> lindex list1 0 "jun" 127.0.0.1:6382> llen list1 (integer) 10 127.0.0.1:6382> lset list 0 wu (error) ERR no such key 127.0.0.1:6382> lset list1 0 wu OK 127.0.0.1:6382> lrange list1 0 -1 1) "wu" 2) "h" 3) "g" 4) "f" 5) "e" 6) "a" 7) "b" 8) "c" 9) "c" 10) "c"

    應用

    從零入門Redis到實際實踐

    從零入門Redis到實際實踐

    set

    定義

    Redis 的 Set 是 String 類型的無序集合。集合成員是唯一的,這就意味著集合中不能出現重複的數據。 Redis 中集合是通過哈希表實現的,所以添加,刪除,查找的複雜度都是 O(1)。

    特點

    • 無序

    • 無重複

    • 集合間操作

    API

    • 集合內的操作

    命令說明時間複雜度
    sadd key element向集合key添加element(如果element已經存在,添加失敗)O(1)
    srem key element將集合key中的element移除掉O(1)
    scard key計算集合大小O(1)
    sismember key element判斷element 是否在集合中O(1)
    srandmember key count從集合中隨機挑count個元素O(1)
    spop key從集合中隨機彈出一個元素O(1)
    smembers key獲取集合所有元素O(1)
    srem key element將集合key中的element移除掉
    O(1)
    • 集合間的操作

    命令說明時間複雜度
    sdiff key1 key2差集O(1)
    sinter key1 key2交集O(1)
    sunion key1 key2並集O(1)
    sidff/sinter/suion + store destkey將差集、交集、並集保存在destkey中O(1)

    注意

    • srandmember不會破壞集合

    • spop會破會

    • smembers 返回的是無序集合,並且要注意量很大的時候回阻塞

    練習

    127.0.0.1:6382> sadd set1 a b c d (integer) 4 127.0.0.1:6382> srem set1 a (integer) 1 127.0.0.1:6382> smembers set1 1) "d" 2) "c" 3) "b" 127.0.0.1:6382> scard set1 (integer) 3 127.0.0.1:6382> sismember set1 d (integer) 1 127.0.0.1:6382> srandmember set1 2 1) "d" 2) "b" 127.0.0.1:6382> srandmember set1 2 1) "b" 2) "c" 127.0.0.1:6382> spop set1 "c" 127.0.0.1:6382> smembers set1 1) "d" 2) "b" 127.0.0.1:6382> srem set1 d (integer) 1 127.0.0.1:6382> smembers set1 1) "b" 127.0.0.1:6382> sadd set1 1 2 3 4 5 (integer) 5 127.0.0.1:6382> sadd set2 a b c 12 8 9 1 2 (integer) 8 127.0.0.1:6382> sdiff set1 set2 1) "3" 2) "4" 3) "5" 127.0.0.1:6382> sinter set1 set2 1) "2" 2) "b" 3) "1" 127.0.0.1:6382> sunion set1 set2 1) "5" 2) "2" 3) "4" 4) "1" 5) "a" 6) "8" 7) "3" 8) "b" 9) "9" 10) "12" 11) "c" 127.0.0.1:6382>

    實戰

    從零入門Redis到實際實踐

    • 抽獎系統, 用spop

    從零入門Redis到實際實踐

    • 贊過的文章,收藏過的文章等

    從零入門Redis到實際實踐

    • 標籤

    從零入門Redis到實際實踐

    • 共同關注

    總結

    從零入門Redis到實際實踐

    zset

    定義

    Redis 有序集合和集合一樣也是string類型元素的集合,且不允許重複的成員。不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。有序集合的成員是唯一的,但分數(score)卻可以重複。

    API

    命令說明時間複雜度
    zadd key score element添加score和elementO(logN)
    zrem key element(可以是多個)將集合key中的element移除掉O(1)
    zscore key element返回元素的分數O(1)
    zincrby key increScore element增加或減少元素的分數O(1)
    zcard key返回元素的總個數O(1)
    zrank(zrevrank) key member返回元素的排名O(1)
    zrange(zrevrank) key start end [WITHSCORES]返回指定索引範圍內的升序元素[分值]O(logN + m)
    zrangebyscore(zrevrangebyscore) key minScore maxScore返回指定分數範圍內的升序元素
    O(logN + m)
    zcount key minScore maxScore返回有序集合內在指定分數範圍內的個數O(logN + m)
    zremrangebyrank key start end刪除指定排名內的升序元素O(logN + m)
    zremrangebyscore key minScore maxScore刪除指定分數內的升序元素O(logN + m)
    ZINTERSTORE destination numkeys(表示key的個數) key [key ...]計算給定的一個或多個有序集的交集並將結果集存儲在新的有序集合 key 中
    ZUNIONSTORE destination numkeys key [key ...]計算給定的一個或多個有序集的並集,並存儲在新的 key 中

    實戰

    • 各種榜單(score:timestamp, saleCount, followCount)

    從零入門Redis到實際實踐

    redis客戶端的使用

    下載

    找相應語言的下載(一般選擇有笑臉和星星的)

    https://redis.io/clients#php

    redis的其他功能

    慢查詢

    生命週期

    從零入門Redis到實際實踐

    兩點說明

    • 慢查詢發生在第3階段

    • 客戶端超時不一定慢查詢,但慢查詢是客戶端超時的一個可能因素

    兩個配置

    • slowlog-max-len

    從零入門Redis到實際實踐

    • slowlog-log-slower-than

    從零入門Redis到實際實踐

    如何配置

    從零入門Redis到實際實踐

    慢查詢命令

    • slowlog get [n] : 獲取慢查詢隊列

    • slowlog len: 獲取慢查詢隊列長度

    • slowlog reset: 清空慢查詢隊列

    運維經驗

    從零入門Redis到實際實踐

    pipeline:流水線

    什麼是流水線

    • 1次網絡命令通信模型

    從零入門Redis到實際實踐

    • 批量網絡命令通信模型

    從零入門Redis到實際實踐

    什麼是流水線

    從零入門Redis到實際實踐

    流水線的作用

    從零入門Redis到實際實踐

    兩點注意

    • redis的命令時間是微秒級別

    • pipeline每次條數要控制(網絡)

    與原生操作對比

    • M操作

    從零入門Redis到實際實踐

    • pipeline

    從零入門Redis到實際實踐

    使用建議

    • 注意每次pipeline攜帶數據量

    • pipeline每次只能作用在一個redis節點上

    • M操作與pipeline區別

    發佈訂閱

    角色

    • 發佈者

    • 訂閱者

    • 頻道

    模型

    從零入門Redis到實際實踐

    從零入門Redis到實際實踐

    API

    • publish channel message

    • subscribe [channel] 一個或者多個

    • unsubscribe [channel] 一個或者多個

    練習

    127.0.0.1:6382> publish weibomovie "hello world" (integer) 1 127.0.0.1:6382> publish weibomovie "hello world2" (integer) 1

    另外一個cli

    127.0.0.1:6382> SUBSCRIBE weibomovie Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "weibomovie" 3) (integer) 1 1) "message" 2) "weibomovie" 3) "hello world" 1) "message" 2) "weibomovie" 3) "hello world2"

    發佈訂閱與消息隊列

    從零入門Redis到實際實踐

    Bitmap

    位圖

    從零入門Redis到實際實踐

    從零入門Redis到實際實踐

    API

    命令說明時間複雜度
    setbit key offset value給位圖指定索引設置值 O(1)
    getbit key offset獲取位圖指定索引的值O(1)
    bitcount key start end獲取位圖指定範圍(start 到end,單位為字節,如果不指定就獲取全部)位值為1的個數O(1)
    bitop op destkey key [key...]做多個bitmap的and,or,not,xor操作並將結果保存在destkey中O(1)
    bitpos key targetBit [start][end計算位圖指定範圍(start到end,單位為字節,如果不指定就是獲取全部)第一個偏移量對應的值等於targetBit的位置O(1)

    練習

    127.0.0.1:6382> set hello big OK 127.0.0.1:6382> getbit hello (error) ERR wrong number of arguments for 'getbit' command 127.0.0.1:6382> getbit hello 0 (integer) 0 127.0.0.1:6382> setbit hello 0 1 (integer) 0 127.0.0.1:6382> get hello "\\xe2ig" 127.0.0.1:6382> set hell a OK 127.0.0.1:6382> bitcount hell (integer) 3 127.0.0.1:6382> bitop and hell hello (integer) 3 127.0.0.1:6382> set a a OK 127.0.0.1:6382> set b b OK 127.0.0.1:6382> bitop and c a b (integer) 1 127.0.0.1:6382> get c "`" 127.0.0.1:6382> bitpos a 1 (integer) 1 127.0.0.1:6382> bitpos a 0 (integer) 0 127.0.0.1:6382> set user2 100 OK

    獨立用戶統計

    重要理解 使用位圖去記錄用戶uid,其實就是記錄索引值,比如userid=100代表位圖下標100的值為1

    從零入門Redis到實際實踐

    從零入門Redis到實際實踐

    使用經驗

    • type=string,最大512MB

    • 注意setbit時的偏移量,可能有較大耗時

    • 位圖不是絕對好

    HyperLogLog

    新的數據結構

    從零入門Redis到實際實踐

    API

    命令說明
    pfaddd key element [element...]向hyperloglog添加元素
    pfcount key [key...]計算hyperloglog的獨立總數
    pfmerge destkey sourceKey [sourcekey...]合併多個hyperloglog

    練習

    127.0.0.1:6382> pfadd puser1 "u1" "u2" "u3" (integer) 1 127.0.0.1:6382> pfcount puser1 (integer) 3 127.0.0.1:6382> pfadd puser2 "u3" "u4" "u5" (integer) 1 127.0.0.1:6382> pfmerge puser puser1 puser2 OK 127.0.0.1:6382> pfcount puser (integer) 5

    內存消耗

    從零入門Redis到實際實踐

    使用經驗

    • 是否能容忍錯誤(錯誤率:0.81%)

    • 是否需要單條數據(沒有辦法取出)

    GEO

    GEO是什麼

    從零入門Redis到實際實踐

    5個城市經緯度

    從零入門Redis到實際實踐

    API

    命令說明
    geoadd key longitude latitude member [longitude latitude member ...]增加地理位置信息
    geopos key member[member...獲取地理位置信息
    geodist key member1 member2[unit]獲取兩個地理位置的距離,unit:m,km,mi,ft
    georadius獲取指定位置範圍內的地理位置信息集合

    練習

    127.0.0.1:6382> geoadd beijing 116.28 39.55 (error) ERR wrong number of arguments for 'geoadd' command 127.0.0.1:6382> geoadd geo 116.28 39.55 beijing 117.12 39.08 tianjin (integer) 2 127.0.0.1:6382> geopos geo beijing 1) 1) "116.28000229597091675" 2) "39.5500007245470826" 127.0.0.1:6382> geodist geo beijing tianjin "89206.0576" 127.0.0.1:6382>

    相關說明

    • since 3.2+

    • type geoKey = zset

    • 沒有刪除API:zrem key member

    redis持久化的取捨和選擇

    持久化的作用

    什麼是持久化

    redis所有數據保存在內存中, 對數據的更新將異步地保存到磁盤上

    從零入門Redis到實際實踐

    持久化的實現方式

    • 快照

    • mysql dump

    • redis RDB

    • 寫日誌

    • mysql binlog

    • hbase hLog

    • redis AOF

    RDB

    什麼是RDB

    從零入門Redis到實際實踐

    觸發機制-主要三種方式

    • save(同步)

    從零入門Redis到實際實踐

    * 文件策略:如存在老的RDB文件,新替換老 * 複雜度:O(N)
    • bgsave(異步)

    從零入門Redis到實際實踐

    • 自動配置

    從零入門Redis到實際實踐

    **相關配置

    配置參數
    save900 1
    save300 10
    save60 10000
    dbfilenamedump-${port}.rdb
    dir/bigdishpath
    stop-writes-on-bgsav-erroryes
    rdbcompressionyes

    save與bgsave

    從零入門Redis到實際實踐

    觸發機制-不容忽略的方式

    其他的方式也會觸發生成RDB文件

    • 全量複製

    • debug reload

    • shutdown

    總結

    • RDB是Redis內存到硬盤的快照,用於持久化

    • save通常會阻塞Redis

    • bgsave不會阻塞redis,但是會fork新進程

    • save自動配置滿足任一就會被執行

    • 有些觸發機制不容忽視

    AOF

    RDB現存問題

    • 耗時,好性能

    從零入門Redis到實際實踐

    • 不可控,丟失數據

    從零入門Redis到實際實踐

    什麼是AOF

    • 創建

    從零入門Redis到實際實踐

    • 恢復

    從零入門Redis到實際實踐

    AOF三種策略

    • always

    從零入門Redis到實際實踐

    • everysec

    從零入門Redis到實際實踐

    • no

    從零入門Redis到實際實踐

    三種策略比較

    從零入門Redis到實際實踐

    AOF重寫

    從零入門Redis到實際實踐

    AOF重寫的作用

    • 減少硬盤佔用量

    • 加速恢復速度

    AOF重寫實現的兩種方式

    • bgrewriteaof

    從零入門Redis到實際實踐

    • aof重寫配置

    從零入門Redis到實際實踐

    從零入門Redis到實際實踐

    AOF重寫流程

    從零入門Redis到實際實踐

    配置

    從零入門Redis到實際實踐

    RDB與AOF的選擇

    從零入門Redis到實際實踐

    RDB最佳策略

    • 集中管理

    • 主從,從開

    AOF最佳策略

    • 開,緩存和存儲

    • AOF重寫集中管理

    • everysec


    分享到:


    相關文章: