Redis深入浅出

常识

  1. 一个value最大是512m
  2. 一个hash可以存储2的三十二次方-1个键值
  3. 一个list可以存储2的三十二次方-1个元素
  4. 一个set可以存储2的三十二次方-1个元素
  5. 如果存储为字符串,可以用tableName!id!field设计key
  6. 如果设计为hash,并映射关系型数据库的表,可以用tableName:id设计整个hash表key,然后表的字段用hash的子key表示
  7. 一条评论信息,因为需要所有的评论信息(人、时间、内容),所以适合用字符串存储,如果是评论列表,就做成list类型
  8. 利用set的集合关系运算,可以模拟sql的and、or、xor、not等逻辑
  9. object encoding key,可以查看key的存储结构
  10. redis-server /path/redis.conf #启动redis

数据类型

keys *
scan 0 [match *a*] [count 10] #实现key的遍历
del key
exists key
ttl key #返回key的剩余时间

字符串

set key value
setnx key value
get key
mset key1 value1 key2 value2 ...
mget key1 key2 key3
incr key //自增id可以用这个
incrby key 10 //给key的value加10
decr key
decrby key 10
append key appendValue //给key后面追加字符串

散列表

hset table key value
hsetnx table key value
hmset table key1 value1 key2 value2...
hget table key
hmget table key1 key2...
hgetall table //获取table表的所有字段和值
hkeys table //只获取table表的所有字段
hvals table //只获取table表的所有值
hlen table //获取table表的字段个数
hexists table key //判断hash的字段是否存在
hincrby table key value //给某个字段加value,注意没有hincr命令
hincrbyfloat table key value //hincrby的小数版本
hdel table key //删除table的key字段

列表类型

//列表特别适用用于分页查询,内部适用双向链表实现
lpush list value1 [value2 ...]
rpush list value1 [value2 ...]
lpop list //从左端取出一个元素
rpop list
llen list //获取列表长度
lrange list start end //分页查询,并且是右包含的,-1表示倒数第一个,-2表示倒数第二个
lrange list start -1 //获取列表所有数据
lrem list count value //count>0时,从表示开始删除等于value的conut个元素,
                    //count<0表示从右端开始删除,
                    //count=0表示删除所有value
lindex list index //获取index位置上的值,-1表示倒数第一个
lset list index value
ltrim list start end //也是右包含的
linsert list [before|after] pivot value #找到指定的元素,并插到前面或者后面
rpoplpush source dest #在source上执行rpop,并将得到的值在dest上执行lpush

集合

sadd set value [value ...]
srem set value [value ...]
smembers set //返回set的所有元素
sismember set value //判断value是否为set的成员
sdiff set1 set2 //返回差集
sdiffstore dest set1 set1 //返回差集,并存储在一个新的dest里面
sinter set1 set2 //返回交集
sinterstore dest set1 set2 //返回交集,并存储在一个新的dest里面
sunion set1 set2 //返回并集
sunionstore dest set1 set2 //返回并集,并存储在一个新的dest里面
scard set //统计集合元素个数
srandmember set [count] //从set中随机获取一个元素,
                        //count>0返回count个不相同的,
                        //count<0返回count可能相同的
spop set //从set中获取一个元素并删除,和srandmember区别是,这个要删除元素
smove source dest value //从source取出一个value元素,放入dest中

有序集合

按分数排序,如果分数相同,按value的字典序排序。增加、查找、删除时间复杂度log(n)

zadd zset score value [score value ...]  //如果存在则用新的分数替换旧的分数
zscore zset value //获取value的分数
zrange zset start stop [withscores] //按分数升序排序,同lrange使用方法一样,withscores表示是否返回分数
zrevrange zset start stop [withscores]  //按分数降序排序

//min/max前面加(表示不包含,-inf/+inf表示正负无穷大
zrangebyscore zset min max [withscores] [limit offset count]
zincrby zset increment member //增加指定元素的分数
zscard zset //返回集合的元素个数
zcount zset min max //统计分数区间内的元素个数
zrem zset member [member ...] //删除元素
zremrangebyrank zset start stop //按排序删除元素
zremrangebyscore zset min max //按分数删除元素
zrank zset value //返回升序名次
zrevrank zset value //返回降序名次
//另外也支持集合的交、并、差,但是都是store类型,即结果存在到一个zset,而不是直接返回

进阶点

事务

watch结合multi和exec可以起到CAS的效果
watch key [key ...] //监控一个或者多个键,一旦有一个键被修改(或删除),之后的事务就不会执行
multi //开启一个批处理
exec //执行批处理
discard //取消批处理
unwatch key [key ...] //取消监控,防止影响下一个事务,如果执行了exec或者discard,会自动执行unwatch

过期设置

expire key seconds //设置key的过期时间,单位秒,返回1表示设置成功,0标志key不存在或者其他失败
ttl key //返回key还有多久过期,单位秒,-1表示永不过期,默认情况即没有设置过期时间,-2表示已过期
persist key //设置为永久不过期,返回1表示设置成功,否则返回0(key不存在或者本来就是永久的
            //处理persist,set、getset也会清楚key的过期时间
//pexpire/pttl是expire和ttl的毫秒版,用法都相同

//下面不太常用
expireat key 时间戳 //指定具体的过期时间点,秒为单位
pexpireat //毫秒版

实现访问频率限制

  • 思路1:用gateLimit:userId做key,并expire设置过期时间为1分钟,当有访问时就incr gateLimit:userId
  • 思路2:用list保存最近访问的10次记录,lpush list now(),如果list的最早时间距离现在小于1分钟,则表示需要限制

实现缓存

修改配置文件maxmemory,当所用内存超出了这个设置,会依据maxmemory-policy策略淘汰不需要的键值对

规则说明
volatile-lru只对有过期时间的减执行lru算法
allkeys-lru对所有键执行lru算法
volatile-random只对有过期时间的键执行随机删除算法
allkeys-random对所有键执行随机删除算法
volatile-ttl删除过期时间最近的键
noevication不删除键,只返回错误

排序

sort命令的时间复杂度为n+mlog(m),n为待排序列表长度,m为返回长度,尽量使n和m变小,或者store保存结果,否则可能是性能瓶颈

sort [list|set|zset] [desc] [limit offset count]
sort map by name*->time [desc] //用map的time字段做降序排序
sort list by pre:* [desc] //list做排序
sort map by name*->time desc get name*->title [get name*->otherField] //通过get返回map其他字段,可以多个get
sort ... store list //把排序结果保存在一个list里面

队列

  • 普通队列:使用lpush和rpop/brpop实现队列,brpop当没有队列元素会阻塞直到有元素加入
  • 优先队列:使用rpop/brpop list1 list2 …同时处理多个list,这样list有元素时,就会优先返回list1的,当list1没有了才返回list2的

发布与订阅

特点:发布的消息所有的订阅者都能接收到,并且订阅者只能接收到订阅时间点之后发布的数据

publish channel message //发布消息
subscribe channel [channel ...] //订阅消息
unsubscribe channel [channel ...] //取消订阅

psubscribe channel [channel ...] //订阅消息,channel名称可以使用*?匹配符
punsubscribe channel [channel ...] //取消订阅

管道技术

一次性发送多条指令批量执行,用于多条指令对返回结果没有依赖的情况,可以大大减少网络往返的时间开销
存储类型

Lua脚本

优点:

  1. 减少网络开销
  2. 原子操作
  3. 复用
//执行脚本,逗号两边必须有空格,否则报错,逗号前面用keys[index]访问,后面用argv[index]访问
redis-cli --eval /path/.../xxx.lua key [key ...] , value [value ...] 

redis.call('command', 'key', 'value', ...) //当执行错误时会直接返回,不会继续执行
redis.pcall('command', 'key', 'value', ...) //和call不同的是,当命令执行错误时会记录错误并继续执行

return //脚本中返回值使用return关键字

script load //加载lua脚本到缓存,返回一个sha1值
script exists sha1 //判断缓存是否存在
script flush //清楚所有缓存
script kill //强制终止正在执行的脚本

redis中不允许定义全局变量
不允许使用lua系统调用与文件的函数

持久化

可以同时配置RDB和AOF,但是启动时还原的是AOF数据

RDB(redis database)

通过快照方式持久化,生成的文件是dump.rdb,可以配置dir、dbfilename设置存储路径和文件名,默认开启,配置save 900 1表示900秒内有一个键被修改就执行备份,删除全部save配置,则表示不启动RDB

原理:

  • 使用fork函数复制当前进程(父进程)的一个副本(子进程),copy-on-write,如果有写操作就复制一个内存数据
  • 父进程继续处理命令,子进程开始将内存中的数据写入临时文件
  • 写入完成后,把临时文件替换旧的备份文件

优点:

是完整的一次备份,可以直接复制备份文件,加载快速

缺点:

可能丢失最近一个备份后的新数据

触发持久化的方式:

  • 根据配置规则进行自动快照
  • 执行save和bgsave命令
  • 执行flushall命令
  • 执行复制时

AOF(appendonly file)

优点:

每一次执行命令,都会把命令追加到硬盘文件,所以只会丢失最后一条命令

缺点:

降低redis性能,使用固态硬盘可以提高AOF性能,加载比rdb速度慢

配置

//默认AOF未开启
appendonly yes //开启AOF
dir //配置设置保存路径
appendfilename a.aof  //配置文件名

//重写配置
auto-aof-rewrite-percentage 100 //表示目前aof文件大小超过上一次aof文件大小百分比时执行重写
auto-aof-rewrite-min-size 64mb //允许重写的最小aof文件大小,因为太小的话没比较重写
appendsync always //每次命令都直接同步到硬盘,强制不经过操作系统缓存
appendsync everysec //默认
appendsync no //不主动同步数据

bgrewriteaof //主动出发aof命令

集群

复制

  • 分为master和slave节点,master可读可写,slave只能读。
  • 也可以配置slave-read-only no让slave可写,但是不推荐,因为写会被master覆盖。
  • 只要有复制就是执行快照,即使关闭了RDB
  • slave也可以成为其他slave的master,形成树型的关系
  • 复制非常实用于读多写少,实现读写分离
  • 当master关闭持久化功能后,避免使用supervisor工具让redis重启或者操作系统重启,这会导致slave的数据也被清空

原理

复制初始化:

在slave连接上master,会首先执行复制初始化,即master生成一个RDB快照,复制给slave,slave收到后保存到临时文件,然后改名为rdb的文件,执行缓存加载过程;redis2.8以前当主从断开后也会执行复制初始化,即使变化的命令很少甚至没有

增量复制:

复制初始化完成之后,就执行增量复制,即每执行一条命令都会把命令异步的传给slave执行,redis的增量复制采用了乐观复制,即不会阻塞master,所以slave和master不是强一致的,slave是最终一致的

配置

slaveof ip port //配置master节点的ip和端口号,既可在配置文件也可在命令行中动态配置
                //如果已经是其他master的slave了,会成为新master的slave
slaveof no one //不再担任slave,从而可以不但提供读服务,还能提供写服务

redis-cli -p 6379 连接到指定的端口
info replication //进入redis-cli后,查看复制信息

min-slaves-to-write 3 //保证最少有3个slave才可以提供写服务
min-slaves-max-lag 10 //设置slave最大心跳时间间隔,大于这个间隔表示slave已经断开

repl-diskless-sync yes //开启无硬盘复制,2.8.18以前复制复用了rdb持久化的逻辑,导致复制会把rdb文件持久化到
            //硬盘,即降低了性能,同时还可能导致redis重启后数据加载问题,无硬盘则直接传给slave而不持久化

增量复制

redis2.8后实现了增量复制,master维护一个积压队列,slave从先前的发送sync同步并未发送psync 主数据运行id 命令偏移量,主数据运行id是确保slave断开期间master没有重启过,命令偏移量判断是否可以增量复制,不能则还是会执行初始化复制

repl-backlog-size 1mb //设置积压队列大小
repl-backlog-ttl 1h //当全部slave和master断开后,积压队列多久可以释放,默认是1小时

哨兵

  • 2.8才提供了稳定的哨兵功能。用于监控主从数据是否运行正常,如果主数据库出现故障自动将从数据库升级为主数据库。同时哨兵也是一个集群,避免单点故障
    master出现故障后,会选取一个slave作为master,并且down掉的master成为slave,让其在重启后可以和slave同步起来
  • 一个哨兵可以同时监控多个redis主从
  • 为保证同一时间只有一个哨兵来执行故障恢复,需要选择一个领头哨兵,使用的是Raft算法
  • 当master宕机后,哨兵默认是30秒开始切换主备

配置

//建立一个sentinel.conf文件,masterName随便取个名字,最后的1表示投票通过数
sentinel monitor masterName 127.0.0.1 6379 1
//每隔6000毫秒发送一次ping命令
sentinel down-after-milliseconds masterName 6000 
redis-sentinel /path/sentine.conf //启动一个哨兵,哨兵只需通过监控master就能知道其所有slave

集群

  • redis3.0引入
  • mget如果在全在同一节点则正常支持,否则提示错误
  • 数据只能放在0号数据库,使用select会报错
  • keys和scan只会列出本机的key
  • 5.0创建集群的方法:Redis-5.0.0集群配置.note
  • 集群直接支持了主备的切换自动切换,所以不需要sentinel了
cluster-enabled yes //开启集群
cluster-config-file /path/nodes.conf //配置集群节点文件存放目录

管理

配置

bind ip //绑定到指定的ip
requirepass password //设置一个密码,设置密码后需要先使用auth password命令输入密码,否则其他命令会报错误
slowlog-log-slower-than 99 //设置慢查询时间,0表示记录所有,负数表示关闭,单位为微妙,默认10000,即10毫秒

命令

rename-command flushall df23423423423423 //重命名命令,其他的名字就不能用了,可以防止被其他人使用
rename-command flushall "" //设置为空字符串,直接禁用命令
slowlog get //获取当前的耗时命令日志
monitor //监控其他客户端执行命令情况,损耗redis近一半的性能,所以只能用来调试
  • PhpRedisAdmin是redis的一个网页管理工具
  • Rdbtools是redis的一个快照文件解析器
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值