文章目录
1. redis初识
1.1 Redis是什么
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区
- 是一个 cs 架构的开源软件
- 非关系型(没有外键关联关系)数据库
- 数据都放在内存中(读写速度超级快,每秒的 qps 10w)
- 以 key-value 形式存储
- 有5大数据类型(字符串,list,hash,集合,有序集合)
好处
Redis典型使用场景
缓存系统:使用最广泛的就是缓存
计数器:网站访问量,转发量,评论数(文章转发,商品销量,单线程模型,不会出现并发问题)
消息队列:发布订阅,阻塞队列实现(简单的分布式,blpop:阻塞队列,生产者消费者)
排行榜:有序集合(阅读排行,点赞排行,推荐(销量高的,推荐))
社交网络:很多特效跟社交网络匹配,粉丝数,关注数
实时系统:垃圾邮件处理系统,布隆过滤器
1.2 Redis特性
速度快:10w ops(每秒10w读写),数据存在内存中,c语言实现,单线程模型
持久化:rdb 和 aof
5大数据结构
-
BitMaps位图:布隆过滤器 本质是 字符串
-
HyperLogLog:超小内存唯一值计数,12kb HyperLogLog 本质是 字符串
-
GEO:地理信息定位 本质是有序集合
支持多种编程语言:基于tcp通信协议,各大编程语言都支持
功能丰富:发布订阅(消息) Lua脚本,事务(pipeline)
简单:源代码几万行,不依赖外部库
主从复制:主服务器和从服务器,主服务器可以同步到从服务器中
高可用和分布式:
-
2.8版本以后使用redis-sentinel支持高可用
-
3.0版本以后支持分布式
1.3 Redis单机安装
yum install wget
wget http://download.redis.io/releases/redis-5.0.7.tar.gz
- 解压:
tar -xzf redis-5.0.7.tar.gz
- 建立软连接
ln -s redis-5.0.7 redis
- 编译
cd redis
make&&make install
编译完成后在 src 里有以下内容
内容 | 说明 |
---|---|
redis-server | redis 服务器 |
redis-cli | redis 命令行客户端 |
redis-benchmark | redis 性能测试工具 |
redis-check-aof | aof 文件修复工具 |
redis-check-dump | rdb 文件检查工具 |
redis-sentinel | sentinel 服务器,哨兵 |
1.4 卸载流程
1、查看redis进程;
ps aux|grep redis
2、kill掉进程;
kill 进程id
3、进入到redis目录
cd /usr/local/
4、删除redis对应的文件
rm -f /usr/local/redis/bin/redis*
rm -f /usr/local/bin/redis*
5、删除对应的文件
rm -rf redis
1.5 服务端三种启动方式
- 最简启动
redis-server # 最简启动
ps -ef|grep redis # 查看进程
yum install net-tools
netstat -antpl|grep redis # 查看端口
redis-cli -h ip -p port ping # 命令查看
- 动态参数启动
# 动态参数启动
redis-serve --port 6380 # 启动,监听6380端口
- 配置文件启动
1. 通过redis-cli连接,输入 config get * 可以获得默认配置
2. 在redis目录下创建 config 目录,copy 一个redis.conf文件
cp redis.conf redis-back.conf
rm -rf redis.conf
3. 重写配置文件
daemonize yes
pidfile /var/run/redis.pid
port 6379
dir "/root/redis/data"
logfile "6379.log"
# 参数说明
# daemonize 是否是守护进程启动(no|yes)
# port 端口号
# logfile redis系统日志
# dir redis工作目录
4. 启动服务端
./src/redis-server redis.conf
5. 查看进程
ps -ef |grep redis-server |grep 6379
1.6 客户端连接
redis-cli -h 127.0.0.1 -p 6379
ping # 返回PONG
# 有密码的情况可以两种登陆方式
# 方式一
redis-cli -h 127.0.0.1 -p 6370 -a 123456
# 方式二
先登陆,再通过 auth 输入密码
# redis-cli 进入
CONFIG GET * # 一百多对建值
CONFIG SET maxmemory 128M # 设置最大使用的内存
CONFIG set requirepass 123456 # 设置密码
CONFIG REWRITE # 保存到配置文件
2. 通用命令
命令 | 说明 |
---|---|
keys * | 打印出所有key |
keys he* | 打印出所有以he开头的key |
keys he[h-l] | 打印出所有以he开头,第三个字母是h到l的范围 |
keys he? | 三位长度,以he开头,?表示任意一位 |
keys 注意点 | keys命令一般不在生产环境中使用,生产环境key很多,时间复杂度为o(n),用scan命令 |
dbsize | redis内置了计数器,插入删除值该计数器会更改,所以可以在生产环境使用,时间复杂度是o(1) |
set a b | 设置a |
exists a | 查看a是否存在,存在返回1,不存在返回0 |
del key | 时间复杂度o(1),删除成功返回1,key不存在返回0 |
expire key seconds | 设置过期时间,时间复杂度o(1) |
ttl name | 查看name还有多长时间过期 |
persist name | 去掉name的过期时间 |
type key | 查看key类型,返回string,时间复杂度o(1) |
info | 内存,cpu,主从相关 |
client list | 正在连接的会话 |
client kill ip:端口 | 结束 |
flushall | 清空所有 |
flushdb | 只清空当前库 |
select 数字 | 选择某个库 总共16个库 |
monitor | 记录操作日志,夯住 |
3. 数据类型命令
3.1 字符串命令
Redis 字符串数据类型的相关命令用于管理 redis 字符串值
命令 | 说明 |
---|---|
SET key value | 设置指定 key 的值 |
GET key | 获取指定 key 的值。 |
GETRANGE key start end | 返回 key 中字符串值的子字符 |
GETSET key value | 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。 |
GETBIT key offset | 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。 |
MGET key1 [key2…] | 获取所有(一个或多个)给定 key 的值。 |
SETBIT key offset value | 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。 |
SETEX key seconds value | 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。 |
SETNX key value | 只有在 key 不存在时设置 key 的值。 |
SETRANGE key offset value | 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始。 |
STRLEN key | 返回 key 所储存的字符串值的长度。 |
MSET key value [key value …] | 同时设置一个或多个 key-value 对。 |
MSETNX key value [key value …] | 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。 |
PSETEX key milliseconds value | 这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。 |
INCR key | 将 key 中储存的数字值增一。 |
INCRBY key increment | 将 key 所储存的值加上给定的增量值(increment) 。 |
INCRBYFLOAT key increment | 将 key 所储存的值加上给定的浮点增量值(increment) 。 |
DECR key | 将 key 中储存的数字值减一。 |
DECRBY key decrement key | 所储存的值减去给定的减量值(decrement) 。 |
APPEND key value | 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。 |
3.2 列表命令
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)
有序队列,可以从左侧添加,右侧添加,可以重复,可以从左右两边弹出
命令 | 描述 |
---|---|
blpop key1 [key2 ] timeout | 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
BRPOP key1 [key2 ] timeout | 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
BRPOPLPUSH source destination timeout | 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
lindex key index | 通过索引获取列表中的元素 |
linsert key BEFORE|AFTER pivot value | 在列表的元素前或者后插入元素 |
llen key | 获取列表长度 |
lpop key | 移出并获取列表的第一个元素 |
lpush key value1 [value2] | 将一个或多个值插入到列表头部 |
lpushx key value | 将一个或多个值插入到已存在的列表头部 |
LRANGE key start stop | 获取列表指定范围内的元素 |
LREM key count value | 移除列表元素 |
LSET key index value | 通过索引设置列表元素的值 |
LTRIM key start stop | 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 |
RPOP key | 移除并获取列表最后一个元素 |
RPOPLPUSH source destination | 移除列表的最后一个元素,并将该元素添加到另一个列表并返回 |
RPUSH key value1 [value2] | 在列表中添加一个或多个值 |
RPUSHX key value | 为已存在的列表添加值 |
3.3 哈希命令
命令 | 说明 |
---|---|
HDEL key field2 [field2] | 删除一个或多个哈希表字段 |
HEXISTS key field | 查看哈希表 key 中,指定的字段是否存在。 |
HGET key field | 获取存储在哈希表中指定字段的值/td> |
HGETALL key | 获取在哈希表中指定 key 的所有字段和值 |
HINCRBY key field increment | 为哈希表 key 中的指定字段的整数值加上增量 increment |
HINCRBYFLOAT key field increment | 为哈希表 key 中的指定字段的浮点数值加上增量 increment |
HKEYS key | 获取所有哈希表中的字段 |
HLEN key | 获取哈希表中字段的数量 |
HMGET key field1 [field2] | 获取所有给定字段的值 |
HMSET key field1 value1 [field2 value2 ] | 同时将多个 field-value (域-值)对设置到哈希表 key 中。 |
HSET key field value | 将哈希表 key 中的字段 field 的值设为 value 。 |
HSETNX key field value | 只有在字段 field 不存在时,设置哈希表字段的值。 |
HVALS key | 获取哈希表中所有值 |
HSCAN key cursor [MATCH pattern] [COUNT count] | 迭代哈希表中的键值对。 |
3.4 集合命令
命令 | 说明 |
---|---|
SADD key member1 [member2] | 向集合添加一个或多个成员 |
SCARD key | 获取集合的成员数 |
SDIFF key1 [key2] | 返回给定所有集合的差集 |
SDIFFSTORE destination key1 [key2] | 返回给定所有集合的差集并存储在 destination 中 |
SINTER key1 [key2] | 返回给定所有集合的交集 |
SINTERSTORE destination key1 [key2] | 返回给定所有集合的交集并存储在 destination 中 |
SISMEMBER key member | 判断 member 元素是否是集合 key 的成员 |
SMEMBERS key | 返回集合中的所有成员 |
SMOVE source destination member | 将 member 元素从 source 集合移动到 destination 集合 |
SPOP key | 移除并返回集合中的一个随机元素 |
SRANDMEMBER key [count] | 返回集合中一个或多个随机数 |
SREM key member1 [member2] | 移除集合中一个或多个成员 |
SUNION key1 [key2] | 返回所有给定集合的并集 |
SUNIONSTORE destination key1 [key2] | 所有给定集合的并集存储在 destination 集合中 |
SSCAN key cursor [MATCH pattern] [COUNT count] | 迭代集合中的元素 |
3.5 有序集合命令
命令 | 说明 |
---|---|
ZADD key score1 member1 [score2 member2] | 向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
ZCARD key | 获取有序集合的成员数 |
ZCOUNT key min max | 计算在有序集合中指定区间分数的成员数 |
ZINCRBY key increment member | 有序集合中对指定成员的分数加上增量 increment |
ZINTERSTORE destination numkeys key [key …] | 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中 |
ZLEXCOUNT key min max | 在有序集合中计算指定字典区间内成员数量 |
ZRANGE key start stop [WITHSCORES] | 通过索引区间返回有序集合成指定区间内的成员 |
ZRANGEBYLEX key min max [LIMIT offset count] | 通过字典区间返回有序集合的成员 |
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] | 通过分数返回有序集合指定区间内的成员 |
ZRANK key member | 返回有序集合中指定成员的索引 |
ZREM key member [member …] | 移除有序集合中的一个或多个成员 |
ZREMRANGEBYLEX key min max | 移除有序集合中给定的字典区间的所有成员 |
ZREMRANGEBYRANK key start stop | 移除有序集合中给定的排名区间的所有成员 |
ZREMRANGEBYSCORE key min max | 移除有序集合中给定的分数区间的所有成员 |
ZREVRANGE key start stop [WITHSCORES] | 返回有序集中指定区间内的成员,通过索引,分数从高到底 |
ZREVRANGEBYSCORE key max min [WITHSCORES] | 返回有序集中指定分数区间内的成员,分数从高到低排序 |
ZREVRANK key member | 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序 |
ZSCORE key member | 返回有序集中,成员的分数值 |
ZUNIONSTORE destination numkeys key [key …] | 计算给定的一个或多个有序集的并集,并存储在新的 key 中 |
ZSCAN key cursor [MATCH pattern] [COUNT count] | 迭代有序集合中的元素(包括元素成员和元素分值) |
4. 慢查询
我们配置一个时间,如果查询时间超过了我们设置的时间,我们就认为这是一个慢查询
慢查询是一个先进先出的队列,固定长度,保存在内存中
4.1 默认配置
# 默认慢查询队列的长度
config get slowlog-max-len=128
# 时间慢于默认的10000微秒,就记录命令
Config get slowly-log-slower-than=10000
4.2 修改配置
# 设置记录所有命令
config set slowlog-log-slower-than 0
# 设置不记录命令
config set slowlog-log-slower-than <0
# 最多记录100条
config set slowlog-max-len 100
# 持久化到本地配置文件
config rewrite
4.3 慢查询队列相关命令
# 获取慢查询队列长度
slowlog len
# 清空慢查询队列日志
slowlog reset
# 获取慢查询队列日志
slowlog get
# 获取慢查询队列日志个数
slowlog get 10
"""
日志由4个属性组成:
1)日志的标识id
2)发生的时间戳
3)命令耗时
4)执行的命令和参数
"""
127.0.0.1:6379> slowlog get
# 唯一的日志标识符,只有在Redis服务器重启的时候才会重置,可以避免对日志的重复处理(比如邮件通知)
1) 1) (integer) 4
2) (integer) 1660984040 # 被记录命令的执行时间点,以Unix时间戳格式表示
3) (integer) 17 # 被查询的时间,以微秒为单位
4) 1) "SLOWLOG" # 执行的命令,以数组的形式排列
2) "get"
5) "127.0.0.1:55394"
6) ""
5. 发布订阅
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
发布者发布了消息,所有的订阅者都可以收到,就是生产者消费者模型(后订阅了,无法获取历史消息)
5.1 订阅相关命令
命令 | 表格 |
---|---|
publish channel message | 发布命令 |
publish souhu:tv “hello world” | 在souhu:tv频道发布一条hello world 返回订阅者个数 |
subscribe [channel] | 订阅命令,可以订阅一个或多个 |
subscribe souhu:tv | 订阅sohu:tv频道 |
unsubscribe [channel] | 取消订阅一个或多个频道 |
unsubscribe sohu:tv | 取消订阅sohu:tv频道 |
psubscribe [pattern…] | 订阅模式匹配 |
psubscribe c* | 订阅以c开头的频道 |
unpsubscribe [pattern…] | 按模式退订指定频道 |
pubsub channels | 列出至少有一个订阅者的频道,列出活跃的频道 |
pubsub numsub [channel…] | 列出给定频道的订阅者数量 |
pubsub numpat | 列出被订阅模式的数量 |
5.2 实例
以下实例演示了发布订阅是如何工作的。在我们实例中我们创建了订阅频道名为 redisChat:
redis 127.0.0.1:6379> SUBSCRIBE redisChat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1
现在,我们先重新开启个 redis 客户端,然后在同一个频道 redisChat 发布两次消息,订阅者就能接收到消息。
redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"
(integer) 1
redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by w3cschool.cc"
(integer) 1
# 订阅者的客户端会显示如下消息
1) "message"
2) "redisChat"
3) "Redis is a great caching technique"
1) "message"
2) "redisChat"
3) "Learn redis by w3cschool.cc"
6. Bitmap 位图
在平时开发过程中,经常会有一些 bool 类型数据需要存取。比如记录用户一年内签到的次数,签了是 1,没签是 0。如果使用 key-value 来存储,那么每个用户都要记录 365 次,当用户成百上亿时,需要的存储空间将非常巨大。为了解决这个问题,Redis 提供了位图结构。
位图(bitmap)同样属于 string 数据类型。Redis 中一个字符串类型的值最多能存储 512 MB 的内容,每个字符串由多个字节组成,每个字节又由 8 个 Bit 位组成。位图结构正是使用“位”来实现存储的,它通过将比特位设置为 0 或 1来达到数据存取的目的,这大大增加了 value 存储数量,它存储上限为2^32
位图本质上就是一个普通的字节串,也就是 bytes 数组。您可以使用getbit/setbit命令来处理这个位数组,位图的结构如下所示:
位图适用于一些特定的应用场景,比如用户签到次数、或者登录次数等。上图是表示一位用户 10 天内来网站的签到次数,1 代表签到,0 代表未签到,这样可以很轻松地统计出用户的活跃程度。相比于直接使用字符串而言,位图中的每一条记录仅占用一个 bit 位,从而大大降低了内存空间使用率。
Redis 官方也做了一个实验,他们模拟了一个拥有 1 亿 2 千 8 百万用户的系统,然后使用 Redis 的位图来统计“日均用户数量”,最终所用时间的约为 50ms,且仅仅占用 16 MB内存。
6.1 位图应用原理
某网站要统计一个用户一年的签到记录,若用 sring 类型存储,则需要 365 个键值对。若使用位图存储,用户签到就存 1,否则存 0。最后会生成 11010101… 这样的存储结果,其中每天的记录只占一位,一年就是 365 位,约为 46 个字节。如果只想统计用户签到的天数,那么统计 1 的个数即可。
位图操作的优势,相比于字符串而言,它不仅效率高,而且还非常的节省空间。
Redis 的位数组是自动扩展的,如果设置了某个偏移位置超出了现有的内容范围,位数组就会自动扩充。
下面设置一个名为 a 的 key,我们对这个 key 进行位图操作,使得 a 的对应的 value 变为“he”。
首先我们分别获取字符“h”和字符“e”的八位二进制码,如下所示:
>>> bin(ord("h"))
'0b1101000'
>>> bin(ord("e"))
'0b1100101'
接下来,只要对需值为 1 的位进行操作即可。如下图所示:
把 h 和 e 的二进制码连接在一起,第一位的下标是 0,依次递增至 15,然后将数字为 1 的位置标记出来,得到 1/2/4/9/10/13/15,我们把这组数字称为位的“偏置数”,最后按照上述偏置数对字符 a 进行如下位图操作。注意,key 的初始二进制位全部为 0。
C:\Users\Administrator>redis-cli
127.0.0.1:6379> SETBIT a 1 1
(integer) 0
127.0.0.1:6379> SETBIT a 2 1
(integer) 0
127.0.0.1:6379> SETBIT a 4 1
(integer) 0
127.0.0.1:6379> get hello
"h"
127.0.0.1:6379> SETBIT a 9 1
(integer) 0
127.0.0.1:6379> SETBIT a 10 1
(integer) 0
127.0.0.1:6379> SETBIT a 13 1
(integer) 0
127.0.0.1:6379> SETBIT a 15 1
(integer) 0
127.0.0.1:6379> get hello
"he"
6.2 位图常用命令
- SETBIT命令
用来设置或者清除某一位上的值,其返回值是原来位上存储的值。key 在初始状态下所有的位都为 0 ,语法格式如下:
SETBIT key offset value
其中 offset 表示偏移量,从 0 开始。示例如下:
set hello big #放入key位hello 值为big的字符串
getbit hello 0 #取位图的第0个位置,返回0
getbit hello 1 #取位图的第1个位置,返回1 如上图
##我们可以直接操纵位
setbit key offset value #给位图指定索引设置值
setbit hello 7 1 #把hello的第7个位置设为1 这样,big就变成了cig
setbit test 50 1 #test不存在,在key为test的value的第50位设为1,那其他位都以0补
bitcount key [start end] #获取位图指定范围(start到end,单位为字节,注意按字节一个字节8个bit为,如果不指定就是获取全部)位值为1的个数
bitop op destkey key [key...] #做多个Bitmap的and(交集)/or(并集)/not(非)/xor(异或),操作并将结果保存在destkey中
bitop and after_lqz lqz lqz2 #把lqz和lqz2按位与操作,放到after_lqz中
bitpos key targetBit start end #计算位图指定范围(start到end,单位为字节,如果不指定是获取全部)第一个偏移量对应的值等于targetBit的位置
bitpos lqz 1 #big 对应位图中第一个1的位置,在第二个位置上,由于从0开始返回1
bitpos lqz 0 #big 对应位图中第一个0的位置,在第一个位置上,由于从0开始返回0
bitpos lqz 1 1 2 #返回9:返回从第一个字节到第二个字节之间 第一个1的位置,看上图,为9