# Redis_基本使用
# 命令
# 使用要点
- 命令中涉及到range操作的都支持正向索引(1,2,3)和负向索引(-1,-2,-3)
- Redis虽然提供了很多的命令,但是需要评估每个命令的性能消耗(运行效率、网卡吞吐量)
- smembers
- keys
# Help命令
# @server
- config
# @General
- type
- object
- del
- dump
- exists
- expire
- expireat
- persist
- pexpire
- pexpireat
- pttl
- keys
- migrate
- move
- randomkey
- rename
- renamenx
# @string
set
setnx
setex
setrange
msetnx
原子操作
msetex
get
getset
设置新值,返回旧值
getrange
getrange k1 0 -1
1append
strlen
incr
incrby
incrbyfloat
decr
decrby
setbit
setbit k1 1 1 setbit k1 7 1 setbit k1 9 1 // 字符集 ascii其他一般叫做扩展字符集扩展: 其他字符集不在对ascii重编码0xxxxxxx你自己写一个程序,字节流读取,每字节判断
1
2
3
4bitpos
start/end是指字节索引位置
bitcount
bitop
setbit k1 1 1 setbit k1 7 1 setbit k2 1 1 setbit k2 6 1 bitop and andkey k1 k2 bitop or orkey k1 k2
1
2
3
4
5
6
# @list
lpush
lpop
rpush
rpop
lrange
lpush
lindex
lset
lrem
lpush k1 a b c d a e f a g lrem k1 2 a // 移除前两个a lrem k1 -2 a // 移除后两个a
1
2
3linsert
lpush k1 a b c d b e linsert k1 after b 6 // 如果有两个是在第一个符合条件的数据进行操作
1
2llen
blpop
ltrim
ltrim k4 0 -1
删除范围外两端的数据
# @hash
hdel
hset
hmset
hget
hmget
hkeys
hvals
hgetall
hincrbyfloat
# @set
- sadd
# @sorted set
# 管道Pipelining
一次发送多条操作指令,节省往返时间RTT(Round Trip Time)
echo -e "set k2 99\n incr k2\n get k2" | nc localhost 6379
使用管道发送命令时,服务器将被迫回复一个队列答复,占用很多内存。所以,如果你需要发送大量的命令,最好是把他们按照合理数量分批次的处理,例如10K的命令,读回复,然后再发送另一个10k的命令,等等。这样速度几乎是相同的,但是在回复这10k命令队列需要非常大量的内存用来组织返回数据内容
# 大量插入数据
使用正常模式的Redis 客户端执行大量数据插入不是一个好主意,因为一个个的插入会有大量的时间浪费在每一个命令往返时间上。使用管道(pipelining)是一种可行的办法,但是在大量插入数据的同时又需要执行其他新命令时,这时读取数据的同时需要确保尽可能快的写入数据。
只有一小部分的客户端支持非阻塞输入/输出(non-blocking I/O),并且并不是所有客户端能以最大限度的提高吞吐量的高效的方式来分析答复。
例如,如果我们需要生成一个10亿的keyN -> ValueN
的大数据集,我们会创建一个如下的redis命令集的文件data.txt:
SET Key0 Value0
SET Key1 Value1
...
SET KeyN ValueN
2
3
4
以前可以使用netcat的方式,使用方式如下:
(cat data.txt; sleep 10) | nc localhost 6379 > /dev/null
然而这并不是一个非常可靠的方式,因为用netcat进行大规模插入时不能检查错误。
从Redis 2.6开始redis-cli
支持一种新的被称之为pipe mode的新模式用于执行大量数据插入工作。
使用pipe mode模式的执行命令如下:
cat data.txt | redis-cli --pipe
这将产生类似如下的输出:
All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 1000000
2
3
使用redis-cli将有效的确保错误输出到Redis实例的标准输出里面。
# Pub/Sub
只能收到订阅之后发布的消息
使用案例
- 聊天系统
# transactions
特点
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
帮助
help @transactions
用法
MULTI
、EXEC
、DISCARD
和WATCH
是Redis事务相关的命令。MULTI
开启事务- 开启事务之后发送的命令会被放到一个队列中
EXCEC
负责触发并执行事务中所有的命令- 如果客户端在使用
MULTI
开启了一个事务之后,却因为断线而没有成功执行EXEC
,那么事务中的所有命令都不会被执行。 - 另一方面,如果客户端成功在开启事务之后执行
EXEC
,那么事务中的所有命令都会被执行。
- 如果客户端在使用
DISCARD
放弃执行事务- 清空事务队列,并且客户端会从事务状态中退出
WATCH
WATCH
某个key,如果被其他事务修改会结束执行返回nil-reply使用check-and-set操作实现乐观锁
WATCH mykey val = GET mykey val = val + 1 MULTI SET mykey $val EXEC
1
2
3
4
5
6
事务中的错误
执行事务之前,入队可能因为语法错误(参数数量错误,参数名错误,等等)或其他更严重的错误(内存不足)出错
判断返回值是否是
QUEUED
调用
EXEC
之后出错(类型操作错误等)
多个事务执行逻辑
开启事务之后对应的操作会被缓冲到队列中,哪个事务的
EXCEC
先到达就先执行哪个事务的任务为什么不支持回滚
- Redis只会因为错误的语法失败(并且这些问题不能在入队时发现)或者命令用在错误的数据类型上。也就是说失败的命令是由错误编程造成的,这些问题应该在开发的过程中被发现,而不是生产环境
- 因为不需要回滚,所以Redis内部可以保持简单快捷
check-and-set操作实现乐观锁
WATCH mykey val = GET mykey val = val + 1 MULTI SET mykey $val EXEC
1
2
3
4
5
6使用上面的代码, 如果在
WATCH
执行之后,EXEC
执行之前, 有其他客户端修改了mykey
的值, 那么当前客户端的事务就会失败。 程序需要做的, 就是不断重试这个操作, 直到没有发生碰撞为止。这种形式的锁被称作乐观锁, 它是一种非常强大的锁机制。 并且因为大多数情况下, 不同的客户端会访问不同的键, 碰撞的情况一般都很少, 所以通常并不需要进行重试。
# modules
如何加载模块
启动的时候通过参数指定加载
redis-server /etc/redis/6379.conf --loadmodule /path/xxx.so
配置文件中配置
loadmodule
# Redisbloom布隆过滤器
配置使用
访问redis.io->modules查找RedisBloom的github地址 (opens new window)
下载源码,解压安装
unzip *.zip
make
cp bloom.so /opt/mashibing/redis5/
启动
redis-server --loadmodule /opt/mashibing/redis5/redisbloom.so
使用
redis-cli
bf.add ooxx abc
bf.exits abc
bf.exits sdfsdf
cf.add
架构
- client实现bloom算法自己承载bitmap + Redis
- client实现bloom算法 + Redis&bitmap
- client + Redis&Bloom&bitmap
# cukcoo布谷鸟过滤器
# Lua脚本
# Lua脚本调试
# 内存优化
# 过期
过期时间的变化
- 过期时间不会随着访问而改变
- 如果发生写会剔除过期时间,需要业务逻辑去补全
Redis如何淘汰过期的key
过期两种方式
被动访问时检测
当客户端尝试访问它时,key会被发现并且主动的过期
主动周期轮询判定
定时随机测试设置keys的过期时间,所有的这些过期的key将会从秘钥空间删除
- 测试随机的20个keys进行相关过期监测
- 删除所有已经过期的keys
- 如果有多于25%的key过期,重复步骤1
这样的话在任何给定的时刻,最多会清楚1/4的过期keys
这样做的目的是稍微牺牲下内存,但是保住了Redis性能
在复制AOF文件时如何处理过期