# Redis
# Redis 基础
redis(Remote dictionary server)是一个开源的基于内存的数据存储系统。它可以用于数据库缓存,消息队列等各种场景,是一种 NoSQL 数据库。早期的互联网公司系统大多是通过 Mysql 这种传统的关系型数据库对外提供服务。随着互联网的快速发展,应用系统的访问量原来远大,数据库的性能瓶颈越来越明显,主要是由于磁盘 IO 所导致的,磁盘 IO 的读写速度与内存相比是非常慢的,如果能把数据存储在内存中,则可以大大数据存储的性能。于是便出现了 redis,这种基于内存的数据存储系统。
# 切换数据库
redis
默认有 16 个数据库,编号分别是 0-15
,通过 select
来进行切换
select 10 # 切换数据库 10 | |
dbsize # 产看当前数据库大小(不含数据,则数据库大小为 0) |
# 清空数据库
flushdb # 清空当前数据库 | |
flushall # 清空所有数据库 |
# 数据结构
redis
支持多种数据结构,包括五种基本数据类型和五种高级数据类型。
五种基本数据类型:
- 字符串
String
- 列表
List
- 集合
Set
- 有序集合
SortedSet
- 哈希
Hash
五种高级数据类型:
- 消息队列
- 地理空间
- HyperLogLog
- 位图 Bitmap
- 位域 Bitfiled
redis
的使用方式有三种:
- CLI,命令行界面(Command Line Interface);通过 Redis-CLI 命令行工具来使用
- API,应用程序接口(Application Programing Interface);
- GUI,图形用户界面(Graphical User Interface);通过图形化工具来使用 Redis
# String
redis
中的数据是以键值对的形式存储的
# 字符串 String | |
set key value # 设置键值对(key, value) | |
get key # 获取 key 对应的 value 值,大小写敏感 | |
# redis 内默认都是使用字符串来存储数据的,而且是二进制安全的(redis-cli --raw) | |
del key # 删除 key 对应的(key,value)键值对 | |
exists key # 判断是否存在 key 对应的键值对 | |
keys pattern # 查看与 pattern 匹配的键,* 表示所以 key | |
clear # 清空屏幕 | |
type key # 产看 key 的数据类型 | |
append key addstring # 在 key 对应的 value 后追加 addstring | |
strlen key # 获取 key 对应的 value 的长度 | |
# 设置一个带过期时间的键值对 | |
TTL key # 查看 key 的过期时间,返回 - 1 表示没有设置过期时间,返回 - 2 表示设置了过期时间同时该键值对已经过期,返回正数表示过期时间 | |
expire key seconds # 为 key 对应的键值对设置过期时间 seconds | |
setex key seconds value # 设置(key,value)键值对的过期时间 | |
setnx key value # 当键 key 不存在时,插入(key, value), 否则不插入 | |
incr key # key 对应的 value +1 | |
decr key # key 对应的 value -1 | |
incrby key add # key 对应的 value +add | |
decrby key sub # key 对应的 value -sub | |
getrange key start end # 获取 key 对应的 value 的 [start, end] 的值 | |
setrange key offset replace_string # 替换 offset 小标开始的字符串为 replace_string | |
mset key1 value1 key2 value2 key3 value3 # 批量设置 key-value | |
mget key1 key2 key3 # 批量获取 | |
msetnx | |
getset key value # 返回原始的 key 对应的值,若不存在返回 nil,同时修改 key 对应的值为 value |
# list
list
也叫列表,一般用来存储和操作一组有顺序的数据,和数组的概念比较类似
# lish 操作 | |
lpush key value # 往列表 key 的左边插入一个 value 的元素 | |
rpush key value # 往列表 key 的右边插入一个 value 的元素 | |
lpush key value1 value2 value3 ... # 一次性添加多个元素 | |
lrange key start stop # 获取列表 key 左边 [start, stop] 的所以元素索引 0 开始 | |
lpop key # 删除列表 key 最左边的元素,返回删除的元素值 | |
lpop key count # 删除列表 key 最左边的 count 个元素(版本 >=6.0.2),返回删除的元素值 | |
llen key # 获取列表 key 的长度 | |
ltrim key start stop # 保留列表 key 从左开始 [stop, stop] 内的元素,范围之外的元素均会被删除(索引均是从 0 开始) |
# set
set 是一种无序集合,它和列表的区别是列表中的元素都是可以重复的,而 set 中的元素不可以重复,而且 set 中的元素并不像列表中的元素那样都是具有顺序的。
# set 操作 | |
sadd key member # 往无序集合 key 内添加 member 元素,若无序集合 key 内已经存在该 member,则添加失败 | |
sadd key memeber1 member2 ... # 往无序集合 key 内添加多个元素 | |
smembers key # 查看无序集合 key 的元素 | |
sismember key member # 查看 member 是否是无序集合 key 内的元素 | |
srem key memeber # 删除无序集合 key 内的 member | |
srem key member1 member2 ... # 删除无序集合 key 内的多个元素 | |
# 集合运算操作 |
# sortedset
sortedset 是一种有序集合,又名 zset,其和集合的区别在于有序集合的每个元素都会关联一个浮点类型的分数,然后按照这个分数来对集合中的元素进行从小到大的顺序排序,有序集合的成员是唯一的,但是分数是可以重复的。
# sortedset 操作 | |
zadd key score1 member1 score2 member2 ... # 往有序集合 key 中插入 member1,member2,其对应的分数为 score1, scores2 | |
zrange key start stop # 查看有序集合 key 内 [start, stop] 内的元素 | |
zrange key start stop withscores # 查看有序集合 key 内 [start, stop] 内的元素和其对应的分数 | |
zscore key member # 获取有序集合 key 内 member 的分数 | |
zrank key member # 获取有序集合 key 内 member 的排名(从小到大排序,分数越小排名越高) | |
zrevrank key member # 获取有序集合 key 内 member 的排名(从大到小排序,分数越高排名越高) |
# hash
哈希 hash 是一个字符类型的字段和值的映射表,简单来说就是一个键值对的集合,特别适合用来存储对象。
# hash 操作 | |
hset key field value # 往哈希 key 内插入 (field, value) 键值对 | |
hget key field # 获取哈希 key 内 field 对应的值 | |
hgetall key # 获取哈希 key 内所以的键值对 | |
hdel key field # 删除哈希 key 内 field 对应的键值 | |
hexists key field # 查看哈希 key 内是否存在 field 对应的键值 | |
hkeys key # 获取哈希 key 内所以的键 | |
hlen key # 获取哈希 key 内所以键值对的数目 |
redis 提供了发布订阅的功能,可以通过 publish
将消息发布到指定的频道,然后通过 subscribe
命令来订阅这个频道。但是这样的简单的发布和订阅功能具有一些局限性,比如消息无法持久化,无法记录历史消息等等
subscribe channel # 订阅频道 channel | |
publish channel message # 像频道 channe 发布消息 message |
# Stream 消息队列
消息队列 Stream,是 redis5.0 引入的一个新的数据结构,他是一个轻量级的消息队列,可以实现消息的持久化、记录历史消息等。
# Stream 操作 | |
xadd key id field value # 往消息队列 key 内添加一条消息(消息的 id,消息的内容 (field, value)), id 为 *,则 redis 则会自动生成,id 为 (时间戳 - 序号) 的形式;redis 自动生成的 id 保证其为递增,如果手动指定 id 需要自己保证插入消息 id 为递增的 | |
xlen key # 获取消息队列 key 的消息数目 | |
xrange key - + # 获取消息队列 key 内的所以消息信息 | |
xrange key start end # 获取消息队列 key 内 id 在 [start, end] 范围内的消息信息 | |
xdel key id # 删除消息队列 key 内 ID 为 id 的消息 | |
xtrim key maxlen count # 删除消息队列 kye 内的消息,直到消息队列长度为 count(可能比 count 多) | |
xread [count count_num] [block milliseconds] streams key id # 读取消息队列可以内 count_num 条消息,ID>id,若没有则堵塞 milliseconds 毫秒,如果 id 为 $, 表示获取当前时刻之后的 count_num 条消息 |
# Genspatial 地理空间
地理空间 Genspatial
是 redis3.2 版本的新特性,它提供了一种存储空间位置信息的数据结构,同时支持对地理位置进行的各种计算操作。
# 地理空间 genspatial | |
geoadd key longitude latitude member # 往空间地理位置 key 内添加名称为 member 的地理位置信息(经度,纬度) | |
geopos key member # 获取空间地理位置 key 内 member 的位置信息 | |
geodist key member1 member2 [km] # 获取空间地理位置 key 内 member1 与 member2 之间的距离,默认为 m |
# HyperLogLog
HyperLogLog
是一种用来做基数统计的算法,它并不是 redis 特有的算法。基数:集合中元素数目(去重之后)。它的原理是使用随机算法来计算,通过牺牲一定的精度来换取更小的内存消耗。
# hyperloglog 操作 | |
pfadd key element1 element2 ... # 往基数容器 key 内添加 element1,element2... 元素 | |
pfcount key # 获取基数容器 key 内元素的数目 | |
pfmerge destkey sourcekey1 sourcekey2 # 合并多个基数容器,最终存放于 destkey 基数容器内 |
# 位图
位图是字符串类型的扩展,可以使用一个 string 类型来模拟一个 Bit 数组,数组的下标就是偏移量,值只有 0 和 1,也支持一些位运算,比如与、或、非和异或等等。他们的运用非常广泛,比如用来记录用户的签到情况,在线状态,点赞状态。
# bitmap 操作 | |
setbit key offset value # 设置位图 key 偏移量为 offset 的位置为 value (0/1) | |
getbit key offset # 获取位图 key 偏移量为 offset 的位置的值 | |
set key value # 位图本质是 string,可以通过设置 string 的方法来设置位图,value 转化为二进制即为对应位图的值 | |
bitcount key # 获取位图 key 内 1 的个数 | |
bitpos key bit # 获取位图 key 内第一次出现 bit 的下标 (0 开始) |
位域能够将很多小的整数存储到一个较大的位图中,这样就可以更加高效的使用内存
# 面试题
redis 支持事务,也就是可以在一次请求中执行多个命令;redis 中的事务主要通过 multi
和 exec
这两个命令来实现的; multi
命令用来开启一个事务,事务开启之后所以的命令都会被放进一个队列中,最后通过一个 exec
命令来执行所以的命令。redis 中是事务和 mysql 或者 oracle 中的数据库的事务不太一样,在关系型数据库中,事务一般是一个原子操作,要么全部执行成功,要么全部执行失败;而在 redis 中,事务并不能保证所以命令都会执行成功,它的执行结果取决于事务中的命令,但是 redis 可以保证如下三点:
- 在发送
exec
命令之前,所以的命令都会被放入到一个队列中缓存起来,不会立即执行 - 在收到
exec
命令之后事务开始执行,事务中的任何一个命令执行失败其他命令依然会被执行(不会以为其中的命令执行失败而影响后续的命令的执行) - 在事务的执行过程中,其他客户端提交的命令请求并不会被插入到执行命令序列中
持久化的 redis 一个非常重要的功能,因为 redis 是一个基于内存的数据库,如果没有持久化的话,那么一旦服务器重启或者断点,那么之前的所以数据都会丢失,这对于一个数据库来说是非常致命的。redis 中的持久化主要由两种方式:
- RDB 方式(redis databse),在指定的时间间隔内,将内存中的数据快照写入磁盘,他是某一时间点上数据的完整副本
- AOF 方式(Append-Only File),追加文件,每次在执行写命令的时候,不仅将命令写入到内存中,还会将命令写入到一个追加的文件中,这个文件就是 AOF 文件,它会以日志的形式来记录每一个写操作,当 redis 重启的时候,就会通过重新执行 AOF 文件中的命令来在内存中重建整个数据库的内容
主从复制是指将一台服务器(主节点)的数据复制到其他 redis 服务器中(从节点)。一个主节点可以有多个从节点,而每个从节点只可以有一个主节点,数据的复制是单向的,只能由主节点到从节点;一般来说主节点负责写操作,从节点负责读操作,主节点会将自己的数据变化通过异步的方式发送给从节点,从节点接收到主节点的数据之后,更新自己的数据,这样就达到的了数据一致性的目的。