[笔记] [redis] redis命令总结
安装
# 修改docker源
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com",
"https://mirror.ccs.tencentyun.com"
]
# 安装redis
docker pull redis:latest
# 检查镜像
docker images
# 运行容器
docker run -itd --name redis-test -p 6379:6379 redis
docker exec -it 容器id /bin/bash
# 在Windows系统上顺带安装redis, 为了使用redis-cli
redis key
对于key来说,我们应该拥有哪些属性和接口呢?首先是过期属性,在计算时间时,因为使用的是system_clock,在测量时间间隔时可能会修改时钟,比如通过网络与另一个时钟同步、转换到夏令时等。因此如果两个redis实例时钟不同步,则在过期时间的精度上会不准确。
对于expire属性来说,我们需要这些接口:
- 设置过期时间:对于时间可分为两种抽象:时间间隔和时间点
expire key integer # 设置key在integer秒后过期
pexpire key integer # 以毫秒为单位
expireat key unix_timepoint #设置key在unix_timepoint时过期
pexpireat key unix_timepoint #以毫秒为单位
persist key #不过期
ttl key # 判断还有多久过期
pttl # 毫秒为单位
- redis支持多种数据类型,可以通过key来判断我们存储的类型是什么
type key
- 删除key
del key
- 判断是否存在
exists key
- 序列化和反序列化
dump key #序列化
restore key ttl serialized-value [replace]
- 重命名key
rename key new_key
# assert key != new_key
# if (exists new_name then overlap)
- 查询匹配的键
keys pattern
redis的过期删除策略(ToDo)
redis数据类型
- string
-
- List
- hash
- Set
- Sorted Set
string
- 二进制安全(jpg/序列化后的对象等)
- value不能大于512MB
string支持二进制、整数、浮点数操作:
对于二进制,有以下接口:
- 以二进制形式读取字符串,计算位为1的个数:
bitcount key start end
,[start, end]内bit=1的个数 - 位运算
setbit
,getbit
,bitfield
,getrange
# SETBIT key offset value # 配合bitcount可以快速计算1的个数
# GETBIT key offset
# BITOP operation destkey key [key ...] #可能需要and/or/not/xor等操作
# BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
# type: u8/u16/u32/u64/i8/i16/i32/i64
# offset: #0 => first
# value: 使用与type相对应的值即可, 不确实是否支持二进制输入.
# getrange key start end
对于整数,有以下接口:
decr key
decrby key value
incr key
incrby key value
对于浮点数,有以下接口:
incrbyfloat key value
位图的使用(引用自[2])
- 统计每日活跃用户
redis.setbit(login:yyyy-mm-dd, user_id, 1)
,为了统计月活,即对一个月所有天数求并集。bitop or dest login:yyyy-mm-01 login:yyyy-mm-02 ....
,同时我们可以为对每日、每周、每月的数据进行缓存以优化计算。
reference
list
list为链表型数据结构,随机读取&插入的复杂度为O(n),
lpush key value # 左端插入元素,返回list长度
rpush key value # 同lpush
lpop key
rpop key
lpushx/rpushx key value # 逻辑和lpush/rpush相似,不同点在于lpushx/rpush仅在key存在时才执行
# 谨慎使用,复杂度为O(n),特殊情况见注释
LINDEX key index # 下标访问
LSET key index value # 下标访问, 如果访问的是头/尾元素则复杂度为O(1)
LINSERT key BEFORE|AFTER pivot value
LREM key count value # 从存于 key 的列表里移除前 count 次出现的值为 value 的元素,count的正负值决定从头开始还是从末尾开始
redis的list
可以用于模拟双端队列,为此也提供了一系列阻塞式操作,如blpop/brpop
,见引用[1],提供该接口的一个目的是解决这类问题:在生产者消费者模型中,如果链表为空,那么消费者执行rpop
时返回null,此时消费者不得不等待一段时间并且重试rpop
。
BLPOP key [key ...] timeout
BRPOP key [key ...] timeout
reference
Hash
可以理解为将hashmap搬入redis。Hash非常适用于表现对象类型的数据。用Hash中的field对应对象的field即可。如果存在嵌套类型,其中的一个解决方案是:使用redis json(注:或许存在其他解决方案)。
优点:
- 存储经过序列化后的数据
- 随机访问性能强于list
HSET key field value
HMSET key field value [field value ...]
HGET key field
HMGET key field [field ...]
HDEL key field [field ...]
HEXISTS key field
hincrby key field value # 与field对应的值能转为整型
hincrbyfloat field value # 能转float
hlen key # 计算有多少个field
# 以下3个命令谨慎使用,因为复杂度为O(n),可转换为HSCAN进行游标式遍历
HGETALL key
HKEYS key # 获取所有的field
HVALS key # 获取所有的值
使用scan命令(ToDo)
Set
Set是无序的,不可重复的String集合。
SADD key member [member ...] # 向set中添加member
SISMEMBER key member # 查询member是否是set中的member
SREM key member [member ...] # 删除set中的member,返回值=删除的个数
SCARD key # 返回member个数
SRANDMEMBER key [count] # 随机地返回count个member
SPOP key [count] # 随机移除并返回count个member
SMOVE source destination member # 将指定的member从source移动到destination
以下为复杂度较高的指令:
SMEMBERS key # 返回指定set中的所有member,复杂度O(n)
SUNION key [key ...] # 计算多个Set的并集并返回
SUNIONSTORE destination key [key ...] # 计算多个Set的并集并将结果存储至destination
SDIFF key [key ...] # 计算多个Set的差集并返回
SDIFFSTORE destination key [key ...] # 计算多个Set的差集并将结果存储至destination
可以考虑使用sscan指令获取所有的member,对于union和diff运算,可以在客户端上进行计算。
Sorted Set
有序的不可重复的Set。
ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
# 这里的附加选项其实要解决的问题是:当我们添加key时,如果key存在如何处理,如果key不存在如何处理,以及是否根据上述条件对全局做一个约束
# XX => 仅更新存在的成员,不添加新成员
# NX => 不更新存在的成员,仅添加新成员
# ...
ZREM key member [member ...] # 可删除多个成员
ZCOUNT key min max # 返回score∈[min, max]的成员个数 O(log(n))
ZCARD key # 返回Set中成员的个数
ZSCORE key member # 返回成员的score
ZRANGE key start stop [WITHSCORES] # 升序,返回key [+scores]
ZREVRANGE key start stop [WITHSCORES] # 降序,返回key
ZINCRBY key increment member # 对指定member的score增加increment,increment可以为负数
复杂度较高的指令:
ZRANGE key start stop [WITHSCORES] # 升序排序,返回指定范围的member
ZREVRANGE key start stop [WITHSCORES] # 降序排序,返回指定范围的member
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] # 升序,返回score∈[min, max]的member
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count] # 降序,返回score∈[min, max]的member
应尽量避免[0, -1]
和[-inf, inf]
这样的范围指定,尽量使用zscan
指令进行游标式遍历。
redis的数据持久化
redis的持久化包括RDB和AOF两个方案。其中:
- RDB: 能够在指定的时间间隔能对你的数据进行快照存储
- 记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
如果只把redis当作缓存使用,可以不进行持久化。
也可以同时开启RDB和AOF,redis在重启时优先加载AOF,因为通常情况下AOF的数据集比RDB更加完整。
RDB优点
- RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集.
- RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密),非常适用于灾难恢复.
- RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能.
- 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些.
RDB缺点
- 如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你.虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据.
- RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度.
AOF 优点
- 使用AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync.使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据.
- AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题.
- Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。
- AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。
AOF 缺点
- 对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。
- 根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。 不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。
定时生成RDB快照易于备份,且恢复速度比AOF快。
如何生成RDB快照:
save 60 1000 # 60s内有1000个键被改动
如何开启AOF功能:
配置文件添加:appendonly yes
redis如何实现RDB和AOF?
- 父进程调用
fork
- 子进程将内存数据写入临时RDB文件,此时并不会影响父进程的写入(利用写时复制原理)
- 子进程完成对临时文件的写入,使用系统调用rename原子地替换原来的RDB文件,并删除原有的RDB文件。
- 父进程调用
fork
- 子进程开始在临时文件中写入基础的AOF(这里完成了AOF重建,其实就是根据当前的内存状态生成AOF文件)
- 父进程将新的更新写入新的AOF文件,如果子进程重写AOF失败,此时旧的AOF和父进程此时新的AOF就是完整的数据集,并将其持久化
- 当子进程完成基础AOF的重写后,向父进程发信号,父进程收到信号后则使用子进程新建的基础AOF文件+新AOF生成临时的AOF文件
- 使用rename替换原有AOF文件,持久化生效,并清理基础文件和未使用的增量文件。
reference
redis的一些常见应用
string
- session cache
- 购物车数据
- 队列处理流量,消息,数据收集
list
Set
- 数据分析,如集合操作等
- IP访问量统计
- 文本过滤=>关键词过滤
Sorted Set
- QA平台权重排序
- 游戏积分排行榜
- 任务调度服务
Hash
- 用户档案信息=>字段保存
- 用户发帖信息保存
- Introduction to Redis Hashes
redis主从配置
master其实可以什么都不做,slave则需要指定master的ip和port,如果master设置了密码,则需要添加masterauth masterpassword。
slaveof ip port
cluster-enable no
masterauth masterpassword