1. 安装

docker-compose.yml
version: '3'
services:
    redis:
        image: redis:alpine
        container_name: redis
        volumes:
            - ~/volumes/redis/data/:/data
        command: redis-server --appendonly yes
        network_mode: host

2. 数据结构

2.1. string

2.1.1. 命令

  • set key value [EX seconds] [PX milliseconds] [NX|XX]

    • set a 1

    • set a 1 PX 10000

    • set a 1 NX NX: 只有key不存在的时候才设置值.

    • set a 1 XX XX: 只有key存在的时候才设置值.

  • get key

    • get a

  • mset key1 value1 [key2 value2 …​] 批量set.

    • mset a 1 b 2 c 3

  • mget key [key1 key2 key3 …​]

    • mget a b c 批量get.

  • msetnx key1 value1 [key2 value2 …​] 批量set, 但是只有所有key不存在时才能设置.

    • msetnx a 1 b 2

  • strlen key 返回key的长度.

    • strlen a

  • append key chars 在key后面追加字符串.

    • append a world

  • getset key value 设置并返回值.

    • getset a 1

  • getrange key start end 截取key从start到end的字符串, 闭区间.

    • getrange demo 0 -1

  • setrange key start substitute key从start位置开始替换值.

    • setrange demo 5 Redis Hello World → HelloRedisd

  • incr key 将key的值加1

    • incr a

  • incrbyfloat key increment 加上浮点数. 最多保留小数后17位.

    • incrbyfloat demo 1.23

2.1.2. 内部编码

可以使用 object encoding KEY 查看内部编码方式.
  • int : 8个字节的长整型.

  • embstr : 小于等于39个字节的字符串.

  • raw : 大于39个字节的字符串.

当字符串长度小于1MB时, 扩容都是加倍现有的空间. 如果长度大于1MB, 扩容时只会增加1MB的空间. 字符串长度最大为512MB.

2.1.3. 使用场景

  • 缓存 setex, get

  • 计数 incr

  • session共享 setex, get

  • 限速 setnx, decr

2.2. hash

2.2.1. 命令

  • hset key field value 为hash的指定field设置值.

    • hset k a 1

  • hsetnx key field value 当field不存在时为field设置值.

    • hsetnx k a 1

  • hget key field 获取hash的指定field的值.

    • hget k a

  • hincrby key field increment 给指定field增加值

    • hincrby k a 111

  • hstrlen key field 获取field值的长度

    • hstrlen k a

  • hlen key 获取hash字段数量

    • hlen k

  • hdel key field [field …​] 删除hash内字段.

    • hdel k a b c

  • hmset key value [key1 value1 …​] 批量设置hash field的值

    • hmset k a 1 b 2 c 3

  • hmget key [key1 key2 …​] 批量获取hash field的值

    • hmget k a b c

  • hexists key field field是否存在

    • hexists k a

  • hkeys key 获取所有的field

    • hkeys k

  • hvals key 获取所有的value

    • hvals k

  • hgetall key 获取hash内所有的field-value

    • hgetall k

2.2.2. 内部编码

  • ziplist : 当哈希元素个数小于 hash-max-ziplist-entries(512) 同时所有值的大小都小于 hash-max-ziplist-value(64B) 时, Redis内部使用 ziplist 作为hash的实现, 结构紧凑, 节省内存.

  • hashtable : 元素数量过多会导致 ziplist 读写效率下降, 此时使用 hashtable 作为hash的内部实现.

2.2.3. 使用场景

  • 缓存 hmset, hgetall

  • 存储稀疏图 hset, hgetall

2.3. list

2.3.1. 命令

  • lpush key value [value1 value2 …​] 从左向右push.

    • lpush k 1 2 3

  • rpush key value [value1 value2 …​] 从右向左push.

    • rpush k 3 2 1

  • lpushx key value 当key存在时才后插入值, 一次只能插入一个值

    • lpushx dummy val

  • linsert key before|after pivot value 插入值到指定元素前/后.

    • linsert k before 1 0

  • lpop key 从左边取出第一个值.

  • rpop key 从右边取出第一个值.

  • rpoplpush source target 从source右端弹出元素, 并将其推入target左端. 如果source为空则执行失败.

    • rpoplpush l1 l2

  • lrem key count value 删除值为value的元素.

    • lrem k 0 1 删除所有值为1的元素.

    • lrem k 1 1 从左向右删除1个值为1的元素.

    • lrem k -1 1 从右向左删除1个值为1的元素.

  • ltrim key start end 保留索引从start到end的元素, 索引从0到N-1.

    • ltrim k 1 3 保留索引从1到3的元素.

  • blpop|brpop key [key1 key2 …​] timeout 从多个列表中取出左/右边第一个元素

    • blop k k1 k2 0

  • lset key index value 将索引为index的元素值修改为value.

    • lset k 1 111

  • lrange key start end 取出列表中从left到end的元素(左右都是闭区间). list从左到右索引下标为0到N-1, 从右向左索引下标为-1到-N.

    • lrange k 0 -1 取出列表所有元素.

  • lindex key index 查看index处的值.

    • lindex k 3

  • llen key 获取列表长度.

2.3.2. 内部编码

  • ziplist : 当列表元素个数小于 hash-max-ziplist-entries(512) 同时每个元素大小都小于 hash-max-ziplist-value(64B) 时, Redis内部使用 ziplist 作为list的实现, 结构紧凑, 节省内存.

  • linkedlist : 元素过多或过大时使用 linkedlist 作为list的实现.

  • quicklist

2.3.3. 使用场景

  • 消息队列 lpush, brpop

  • 实体列表 lpush, lrange

  • 有限集合 lpush, ltrim

  • 优先级调度 lpush l1/l2/l3…​, brpop l1 l2 l3 0

2.4. set

2.4.1. 命令

  • sadd key value [value1 value2 …​]

  • srem key value [value1 value2 …​] 删除set中元素.

  • scard key 获取set元素个数.

  • smove source target value 将value从source移动到target.

  • sismember key value set中是否存在该元素.

    • sismember k 1

  • srandmember key [count] 随机获取set中元素.

    • srandmember k 10

  • spop key [count] 随机弹出set中元素.

  • sinter key [key1 key2 …​] 取多个set的交集.

    • sinter a b c

  • sunion key [key1 key2 …​] 取多个set的并集.

    • sunion a b c

  • sdiff key [key1 key2 …​] 取多个set的差集(key-key1).

    • sdiff a b

  • sinterstore|sunionstore|sdiffstore key [key1 key2 …​] 取key1,key2…​的交/并/差集, 存到key中.

    • sdiff dest a b

2.4.2. 内部编码

  • intset : 集合中的元素都是整数, 且元素个数小于 set-max-intset-entries(512) 时使用intset作为集合的内部实现.

  • hashtable

2.4.3. 使用场景

  • 打tag sinter

  • 抽奖 spop, srandmember

  • 社交关系 sadd, spop, srem, smembers

  • 共同关注 sinter

2.5. zset

2.5.1. 命令

  • zadd key [NX|XX|INCR|CH] score member [score1 member1 …​]

    • zadd k 1 a 2 b

    • zadd k NX 1 a 2 b NX表示member不存在才添加.

    • zadd k XX 11 a 2 c XX表示member存在才更新.

    • zadd k INCR 123 a INCR表示加分数.

    • zadd k CH 123 a 1000 b CH表示修改的成员数量.

  • zcard key : 获取member数量.

  • zrem key member : 删除某个member.

  • zscore key member : 获取member的分数.

  • zrank key member : 分数从低到高获取member名次.

  • zrevrank key member : 分数从高到低获取member名次.

  • zincrby key increment member : 给某个member加score.

    • zincrby k 10 a

  • zrange|zrevrange key start end [withscores] 从低到高/从高到低获取排行start到end的member[和它的分数].

    • zrange k 0 2 withscores

  • zrangebyscore key min max [withscores] [limit offset count] 根据分数范围列出member.

    • zrangebyscore k 10 11 withscores limit 0 1

    • zrangebyscore k (10 11

    • zrangebyscore k -inf 11

  • zcount key min max 获取分数从min到max的member数量.

    • zcount k 10 11

    • zcount k 10 (11

    • zcount k -inf +inf

  • zremrangebyrank key start end 删除排行从start到end的member.

  • zremrangebyscore key min max 删除分数从min到max的member.

  • zinterstore|zunionstore destination numKeys key [key1 …​] [weights weight] [aggregate SUM|MIN|MAX] 将numKeys个zset成员乘以按照各自的权重进行SUM/MIN/MAX操作, 存放到destination中.

    • zinterstore dest 2 k1 k2 weights 1 0.5 aggregate sum

  • zrangebylex key min max 按照字典顺序过滤成员.

  • zlexcount key min max 按照字典顺序过滤成员, 再获取数量.

  • zremrangebylex key min max 删除字典顺序内成员.

  • zpopmax 移除分最高的成员.

  • zpopmin 移除分最低的成员.

2.5.2. 内部编码

  • ziplist : 有序集合的元素个数小于 zset-max-ziplist-entries(128) , 同时每个成员的大小小于 zset-max-ziplist-value(64B) 时用 ziplist 实现zset.

  • skiplist

2.6. HyperLogLog

2.6.1. 命令

  • pfadd key element [element …​] 添加元素.

  • pfcount key [key2 key3 …​] 获取集合的近似基数.

  • pfmerge destKey sourceKey1 [sourceKey2 …​] 将其他HyperLogLog合并到destKey.

2.7. bitmap

2.7.1. 命令

  • setbit key index value 设置指定位置上的值

  • getbit key index 获取指定位置上的值.

  • bitcount key [start, end] 统计从start到end的1. (字节为单位偏移量, 1字节等于8位.)

  • bitpos key {0|1} [start, end] 获取第一个指定值的位置.

    • 在一个全为0的位图里找1, 返回-1

    • 在一个全为1的位图里找0, 返回下一个位置的索引

  • bitop [AND|OR|XOR|NOT] result_key bitmap1 [bitmap2 …​] 对多个bitmap进行算术操作.

    • 处理不同长度的bitmap时, 空的位置会视作0.

  • bitfield key [SET|GET|INCRBY|OVERFLOW] type offset value ``

3. key管理

  • rename/renamenx key newKey 重命名/newKey不存在时才重命名成功.

  • randomkey 随机返回一个key.

  • dbsize 获取key的数量.

管理key时效时间
  • expire key seconds 让key在seconds秒后过期.

  • expireat key epochSecond 让key在epochSecond时过期.

  • pexpire key millseconds 让key在millseconds毫秒后过期.

  • persist key 取消key的过期时间.

  • ttl key 获取key的过期时间.

set 命令会使key的失效时间消失.
遍历key
  • keys pattern 根据pattern正则列出key.

  • scan cursor [match pattern] [count number] 使用游标遍历键.

    • scan 0

    • scan 0 match k* count 1

key迁移
  • move key db_idx 将key移动到db_idx数据库里.

  • dump + restore dump指定key再restore

    1. select 0

    2. set hello world

    3. dump hello

    4. select 1

    5. restore hello 0 "\x00\x05hello\x09\x00\xB3\x80\x8E\xBA1\xB2C\xBB"

    6. get hello

  • migrate host ip key|"" destination_db_idx timeout [auth password] [COPY] [REPLACE] [KEYS k1 k2 …​] 批量迁移key到host:ip:destination_db_idx里, 如果key为"",则按KEYS后的key列表迁移.

    • migrate 192.168.0.227 6379 "" 1 1000 COPY REPLACE KEYS k1 k2 k3

migrate 命令不能在同一Redis实例上执行.

4. 慢查询

  • slowlog-log-slower-than(微秒) : 慢查询执行阈值, 默认10000微秒, 负数时不记录慢查询. 建议设置为1000.

  • slowlog-max-len : 慢查询日志最多存储多少条. 建议设置为1000以上.

  • slowlog get [n] : 获取前n条慢查询.

  • slowlog len : 获取慢查询数量.

  • slowlog reset : 重置慢查询.

5. Redis Shell

5.1. redis-cli

  • -r n : 将命令重复执行n次.

  • -i n : 每隔几秒执行一次.

  • -a password : 密码认证.

  • --scan --pattern : scan key名.

  • --rdb filename : dump数据到rdb文件中.

  • --bigkeys : 找到内存占比比较大的key.

  • --latency : 测试延迟.

  • --stat : 获取Redis统计信息.

5.2. redis-benchmark

  • -c : 客户端的并发数量, 默认50.

  • -n : 客户端的请求总数, 默认100K.

  • -q : 每秒请求数.

  • -r : 插入随机键, 10000表示对后四位处理.

  • -t : 对指定命令进行基准测试.

  • --csv : 结果按csv格式输出.

6. 事务

6.1. 原子性

  1. multi

  2. commands …​

  3. discard/exec

  • 事务期间命令拼错会导致整个事务回滚.

  • 事务期间命令没有拼写错误, 但是命令使用错误(如对set执行zadd), 则会执行没有错误的部分命令.

6.2. 隔离性

  1. watch

  2. multi

  3. commands …​

  4. discard/exec

watch某一个key期间, 如果 exec 后返回null, 则表示这期间key其他client修改过, 直接回滚.

6.3. 原子性

  • script load <lua content> : load lua脚本到redis server中, 返回一个SHA1值, 以后可以直接用SHA1值调用lua脚本.

  • script flush : 删除所有被加载过的lua脚本.

  • script kill : 取消正在执行读操作的lua脚本.

  • script exists <SHA1> : 返回相关lua脚本的SHA1是否被加载过.

lua脚本执行
  • eval <script> numberKeys key args

  • evalsha <SHA1> numberKeys key args

7. bitmap

  • setbit <bitmap_key> <offset> 1|0 : 设置offset为1/0.

  • getbit <bitmap_key> <offset> : 获取offset处是1还是0.

  • bitcount [<bitmap_key> start end] : 获取start到end的1的个数.

  • bitop and|or|not|nor <destination_key> key [key1 key2 …​] : 对多个bitmap key执行逻辑操作.

  • bitpos <bitmap_key> 1|0 [start end] : 获取第一个值为1/0的偏移量.

8. HyperLogLog

  • pfadd key element [element …​] : 添加元素.

  • pfcount key : 计数.

  • pfmerge <destination_key> key [key1 key2 …​] : 求多个key的并集, 插入到destination_key中.

9. Publish/Subscribe

  • publish <channel> <message> : 向channel的每个订阅者发送message.

  • subscribe <channel> : 订阅channel.

  • pubsub channels : 查看当前活跃的channel.

  • psubscribe/punsubscribe <pattern> : 批量订阅channel.

  • pubsub numsub <channel> : 查看channel的订阅数.

  • pubsub numpat : 查看按模式订阅数.

10. Redis Serialization Protocol

10.1. Request

*<参数数量> CRLF
$<参数1的字节数> CRLF
<参数1> CRLF
$<参数2的字节数> CRLF
<参数2> CRLF
...

10.2. Response

Response的第一个字节
  • 状态回复: +

  • 错误回复: -

  • 整数回复: :

  • 字符串回复: $

  • 多条字符串回复: *

11. 持久化

11.1. RDB

RDB持久化是把当前进程的数据生成快照保存到硬盘里.

11.1.1. 手动触发

  • save : 阻塞redis server直到RDB过程完成为止.

  • bgsave : fork出子进程, 让子进程持久化.

11.1.2. 自动触发

  • save <m> <n> : 表示m秒内数据存在n次修改时, 自动触发bgsave.

  • 如果从节点执行全量复制操作, 主节点自动执行bgsave生成RDB文件发送给从节点.

  • debug reload

  • shutdown : 如果没有开启AOF持久化功能则自动执行 bgsave .

11.1.3. 问题

  • bgsave 属于全量复制, 每次执行都要创建子进程, 频繁操作执行成本太高.

  • RDB使用特定二进制格式保存, 可能会出现不兼容的问题.

11.2. AOF

所有的写入命令追加到aof_buf中, aof_buf会根据相应的策略向磁盘做同步操作.

AOF重写
  • bgrewriteaof

  • 根据 auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage 参数确定自动触发时机. aof_current_size > auto-aof-rewrite-min-size && (aof_current_size - aof_base_size) / aof_base_size >= auto-aof-rewrite-percentage

    • auto-aof-rewrite-min-size : AOF文件重写时文件最小体积.

    • auto-aof-rewrite-percentage : 当前aof文件体积和上一次重写后aof文件体积比值.

11.3. 持久化文件加载流程

  1. appendonly开启时优先加载aof文件, aof不存在时加载rdb文件

  2. appendonly未开启时加载rdb文件

  3. 加载aof/rdb文件成功后, redis启动成功.

  4. aof/rdb文件存在错误时, redis启动失败并打印错误信息. (可以使用redis-check-aof --fix命令修复)

12. 主从复制

12.1. 从节点开启方式

  • redis-server replicaof <host> <port> .

  • 配置文件添加 replicaof <host> <port> .

  • 直接运行命令 replicaof <host> <port> .

12.2. 从节点断开

replicaof no one .

12.3. 数据同步方式

  • 全量复制: 用于初次复制场景. 把主节点全部数据一次性地发送给从节点.

  • 部分复制: 补发丢失数据给从节点.

13. Sentinel

Redis Sentinel 负责监控redis主从节点, 主节点故障时自动切换从节点为主节点.

13.1. 安装

docker-compose.yml
version: '3.7'
services:
    redis-master:
        image: redis:alpine
        container_name: redis-master
        volumes:
            - ./master.conf:/usr/local/etc/redis/redis.conf
        command: redis-server /usr/local/etc/redis/redis.conf
        networks:
            - redis
        ports:
            - 6379:6379
    redis-replica1:
        image: redis:alpine
        container_name: redis-replica1
        volumes:
            - ./replica1.conf:/usr/local/etc/redis/redis.conf
        command: redis-server /usr/local/etc/redis/redis.conf
        networks:
            - redis
        ports:
            - 6380:6379
        depends_on:
            - redis-master
    redis-replica2:
        image: redis:alpine
        container_name: redis-replica2
        volumes:
            - ./replica2.conf:/usr/local/etc/redis/redis.conf
        command: redis-server /usr/local/etc/redis/redis.conf
        networks:
            - redis
        ports:
            - 6381:6379
        depends_on:
            - redis-master
    redis-sentinel1:
        image: redis:alpine
        container_name: redis-sentinel1
        volumes:
            - ./sentinel1.conf:/usr/local/etc/redis/redis.conf
        command: redis-sentinel /usr/local/etc/redis/redis.conf
        networks:
            - redis
        ports:
            - 16379:6379
        depends_on:
            - redis-master
    redis-sentinel2:
        image: redis:alpine
        container_name: redis-sentinel2
        volumes:
            - ./sentinel2.conf:/usr/local/etc/redis/redis.conf
        command: redis-sentinel /usr/local/etc/redis/redis.conf
        networks:
            - redis
        ports:
            - 16380:6379
        depends_on:
            - redis-master
    redis-sentinel3:
        image: redis:alpine
        container_name: redis-sentinel3
        volumes:
            - ./sentinel3.conf:/usr/local/etc/redis/redis.conf
        command: redis-sentinel /usr/local/etc/redis/redis.conf
        networks:
            - redis
        ports:
            - 16381:6379
        depends_on:
            - redis-master

networks:
    redis:
master.conf
appendonly yes
logfile "master.log"
dbfilename "dump-master.rdb"
replica1.conf
appendonly yes
logfile "replica1.log"
dbfilename "dump-replica1.rdb"
replicaof redis-master 6379
replica2.conf
appendonly yes
logfile "replica2.log"
dbfilename "dump-replica2.rdb"
replicaof redis-master 6379
sentinel1.conf, sentinel2.conf, sentinel3.conf
logfile "sentinel.log"
sentinel monitor master redis-master 6379 2
sentinel down-after-milliseconds master 15000
sentinel parallel-syncs master 1

14. 集群模式