Redis相关问题总结

Redis的数据结构
  • String 简单的key-value.
    设值命令:
    set name james ex 10 //设值,10s后过期
    setnx name james //不存在键name时,设置成功返回1,键已存在返回0
    场景:如果有多个用户同时使用setnx,只有一个人能成功,可做分布式锁
    取值命令:
    get name ,如果存在值返回james,不存在返回nil
    批量设值:mset conutry china city nanjing
    批量取值:mget conutry city address //返回china nanjing address为nil
    计数:
    incr age//整数自增1,必须为整数,非整数返回错误.
    decr age//整数age -1
    incrby age 2//整数自增2
    decrby age 2//整数自减2
    追加命令:
    append,set name lebron,append name james //值由lebron变成lebronjames
    字符串长度:
    set hello "世界",strlen hello//返回6,每个中文占3个字节
    截取字符串:
    getrange,set name helloword ,getrange name 2 4 //返回llo
  • list 有序列表,底层是双向链表,可以做简单队列.
    添加命令:
    rpush james c b a //从右往左插入cba,返回3
    lpush james c b a //从左往右插入cba,
    linsert james before b teacher //在b之前插入teacher ,after为之后.
    lrange james 0 -1 返回: c teacher b a
  • set 无序列表(去重).
    命令:
    sadd user a b c //插入三个元素
    exists user //检查user是否存在
    smembers user //查找user的所有元素
    srem user a //删除a元素
    scard user //查询user元素的个数
    sismember user a //检查a元素是否存在,存在返回1,不存在返回0
    srandmmember user 2 //随机返回元素,2为元素的个数
    交集:sinter,并集:sunion,差集,sdiff.
    内部编码
    sadd user 1 2 3 ... //元素不超过512且元素都为整数时,内部结构为intset,减少内存的使用;
    sadd user 1 2 3 ... 513 //元素超过513且元素不为整数时,内部结构为hashtable.
    使用场景:标签,社交等等
  • hash 哈希表,存储结构化数据.
    命令:
    hset key field value
    设值: hset user:1 name james
    取值: hget user:1 name //返回james
    删值: hdel user:1 age
    计算个数: hlen user:1 //返回1
    批量设值: hmset user:2 name james age 23
    批量取值: hmset user:2 name age //返回james 23
    获取所有的field: hkeys user:2 //返回name age
    获取所有的value: hvals user:2 //返回james 23
    获取所有的field,value: hgetall user:2 //返回name age james 23
    内部编码: ziplist<压缩列表>和hashtable<哈希表>
    当field个数少且值不大的时候,内部编码为ziplist
    hmset user:3 name james age 24 ; object encoding user:3 //返回为ziplist
    当value大于64字节时候,会有ziplist转换为hashtable
    hset user:4 address "adada64" ;object encoding user:4 //返回hashtable
  • sortSet 有序集合
项目中为什么要使用缓存?

用缓存主要有两个用途:高性能,高并发.
1.高性能
假如用户请求获取数据直接去mysql查询每次耗时600ms,但是这个结果一段时间内都不会改变了,或者变了也不用立即反馈给用户.这时我们可以采用缓存,把查询的数据扔进缓存,采用key-value存储,每次用户请求先去缓存查询,有直接返回给用户,没有再去数据库查询.假如数据库的数据发生了变化,就同时去更新缓存里的数据.
2.高并发
mysql数据库承受不了太高的并发,mysql单机一般达到2000QPS就会报警,所以如果有一个系统,高峰期有10000个请求同时进来会导致数据库宕机,这时候我们也可以采用缓存技术,单机支撑的并发量轻松超过一秒几万次,单机承载并发量是mysql的几十倍.
缓存是走内存的,天然支持高并发.

什么是Redis缓存雪崩与穿透?

1.雪崩
前提:为节约内存,一般redis会做定期删除的操作.
1).当查询key =james的时候,redis没有数据,
2).如果有5000个用户同时访问key =james时,全部到mysql里面去查,导致雪崩.
解决方案如下:
1).设置热点数据永不过期.
2).加互斥锁
互斥锁代码:

public statis String getData(String key)  throws Exception{
//从缓存去获取数据
String result = getDataFromRedis(key);
//如果result为空
if(result == null){
//去获取锁,获取成功,去数据库获取数据
if(reenLock.tryLock()){
//从数据库获取数据
result = getDataFromMysql(key)
//如果数据不为空,将数据写入缓存
if(relust ! =null){
setDataCache(result)
}
//释放锁
reenLock.unLock()
}
}else{
//获取锁失败
//暂停100ms再去获取数据
Thread.sleep(100)
result = getData(key)
}
return result;
}

2.穿透

前提:黑客模拟一个不存在的订单号:
1).redis中无此数据
2).mysql中也无此数据,但是一直被查询.
解决方案:
1).对订单表所有的订单id数据查询出来都放在布隆过滤器中,经过布隆过滤器处理过后的数据很小(只存0或者1)
2).每次查询订单表之前,都去过滤器中查询订单id的状态是0还是1,0的话代表订单id不存在,直接拒绝查询.

redis的持久化

redis支持RDB和AOF两种持久化机制,持久化可以避免因进程退出而导致数据丢失.
1.RDB持久化
RDB持久化把当前进程的数据生成快照(.rdb)文件保存到硬盘,有手动触发和自动触发
手动触发有save命令和bgsave命令
save命令:阻塞当前Redis,知道RDB持久化完成为止,若内存实例较大,会造成较长时间的阻塞,线上环境不建议使用
save命令: redis进程fork操作创建子进程,由子进程完成持久化,阻塞时间很短(微秒级),是save的优化,在执行redis-cli shutdown关闭redis服务时,如果没有开启持久化,会自动执行bgsave;
RDB文件的操作:
命令:config set dir /usr/local //设置rdb文件的保存路径
备份:bgsave //将dump.rdb保存到/usr/local目录下
恢复:将dump.rdb放到redis安装目录下与redis.conf同级目录,重启redis即可
优点:
1).压缩后的二进制文,适用于备份,全量复制,用于灾难恢复.
2).加载RDB恢复数据远快于AOF.
缺点:
1).无法做到实时持久化,每次都要创建子进程,频繁操作成本过高.
2).保存后的二进制文件,可能存在新老版本不兼容的情况.
2.AOF持久化
针对RDB不适合实时持久化,redis提供了AOF来解决.
开启:redis.conf配置 设置,appendonly yes(默认为不开启,为no)
默认文件名:appendfilename "appendonly.aof"
流程说明:
1).所有的写入命令(set hset)会append到aof_buf缓冲区中;
2).AOF缓冲区向硬盘做sync同步;
3).随着aof文件越来越大,需定期对AOF文件rewrite重写,达到压缩
4).当redis服务重启,可以load加载AOF文件进行恢复
redis的AOF配置详解:
appendonly yes //启用持久化命令
井号键 appendfsync always //每收到命令就立即强制写到磁盘,最慢的,但是保证完全持久化,不推荐使用
appendfsync everysec //每秒强制写入磁盘一次,性能和持久化方面做了折中,推荐
no-appendfsync-on-rewrite yes //正在导出RDB快照的时候,要不要同步停止AOF
auto-aof-rewrite-percentage 100 //aof文件大小比上次重写时的大小,增长率100%时,重写
auto-aof-rewrite-min-size 64mb // aof文件至少超过64MB时重写
如何从AOF恢复?
1.)设置appendonly yes
2.)将appendonly.aof文件放到dir参数指定目录
3.)启动redis,redis会自动加载appendonly.aof文件
redis重启时恢复加载AOF和RDB的流程:
1.)当AOF和RDB同时加载时,优先加载AOF
2.)当AOF关闭时,加载RDB
3.)加载AOF/RDB成功,redis重启成功
4.)AOF/RDB存在错误,redis重启失败并打印错误信息

Redis有哪几种内存淘汰策略?

1).noeviction,当内存不足以容纳新数据时,新写入操作会报错;
2).allkeys-lru,当内存不足以容纳新数据时,在键空间中移除最近最少使用的key;
3).allkeys-random,当内存不足以容纳新数据时,在键空间中随机移除key;
4).volatile-lru,当内存不足以容纳新数据时,在设置了过期时间的键空间中移除最近最少使用的key;
5).volatile-random,当内存不足以容纳新数据时,在设置了过期时间的键空间中随机移除key;
6).volatile-ttl,当内存不足以容纳新数据时,在设置了过期时间的键空间中有更早过期时间的优先移除.

Redis的过期时间和永久有效怎么设置?

EXPIRE和PERSIST命令

Redis如何做内存优化?

尽可能的使用散列表(hashes),散列表占用的内存非常小,所以应该尽可能的将数据放到散列表当中.
比如系统中有有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码单独的设置key,而是把这个用户的所有信息存储在散列表当中.

Redis进程是如何进行回收工作的?

一个客户端执行一条命令,添加入一条新的数据,Redis检查内存的使用情况,如果超过了maxmemory的限制,使用设置好的过期策略淘汰数据.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。