redis核心问题
redis核心问题
redis线程,高并发下的缓存穿透、击穿、血崩、缓存淘汰策略、持久化机制,redis的分布式锁
01.说一下在你项目中的redis的应用场景
1,5大value类型 :根据我的redis课有场景的介绍
2,基本上就是缓存~!
3,为的是服务无状态,延申思考,看你的项目有哪些数据结构或对象,再单机里需要单机锁,在多机需要分布式锁,抽出来放入redis中;
4,无锁化
02.redis是单线程还是多线程
1, 无论什么版本,工作线程就是一个
2, 6.x高版本出现了IO多线程
3,使用上来说,没有变化
4, [去学一下系统IO课],你要真正的理解面向IO模型编程的时候,有内核的事,从内核把数据搬运到程序里这是第一步,然后,搬运回来的数据做的计算是第二步,netty
5,单线程,满足redis的串行原子,只不过IO多线程后,把输入/输出放到更多的线程里去并行,好处如下: 1,执行时间短,更快; 2,更好的压榨系统及硬件的资源(网卡能够高效的使用);
*,客户端被读取的顺序不能被保障
哪个顺序是可以被保障的: 在一个连接里,socket里
6.x以前
缓存不严谨,尽量去分片
6.x以后
03.redis存在线程安全的问题么
重复2中的单线程串行
redis可以保障内部串行
外界使用的时候要保障,业务上要自行保障顺序~!
04.遇到过缓存穿透么
05.遇到过缓存击穿么
06.如何避免缓存雪崩
以上问题,核心就是避免DB无效/重复请求,结合图去理解
涉及一些架构思想上的提升
07.缓存课后解答
如果查询的key缓存也没有DB也没有,访问的量又比较大会怎么样?
6.x多线程IO模式下,是怎么保证事务的?
事务有queue的
08.redis是怎么删除过期key的(缓存时如何回收的)
1,后台在轮询,分段分批的删除那些过期的key
2,请求的时候判断是否已经过期了
尽量的把内存无用空间回收回来
09.缓存是如何淘汰的
0,内存空间不足的情况下:
1,淘汰机制里有不允许淘汰
2,lru/lfu/random/TTL
3,全空间
4,设置过期的key的
10.如何进行缓存预热
1,提前把数据塞入redis,(你知道那些是热数据么?肯定不知道,会造成上线很多数据没有缓存命中)
2,开发逻辑上也要规避差集(你没缓存的),会造成击穿,穿透,雪崩,实施4,5,6中的锁方案
3,一劳永逸,未来也不怕了
*结合4,5,
10.如何进行缓存预热
1,提前把数据塞入redis,(你知道那些是热数据么?肯定不知道,会造成上线很多数据没有缓存命中)
2,开发逻辑上也要规避差集(你没缓存的),会造成击穿,穿透,雪崩,实施4,5,6中的锁方案
3,一劳永逸,未来也不怕了
*结合4,5,
12.简述一下主从不一致的问题?
1,redis的确默认时弱一致性,异步的同步
2,锁不能用主从(单实例/分片集群/redlock)==>redisson
3,在配置中提供了必须有多少个client连接能同步,你可以配置同步因子,趋向于强一致性
4,wait 2 0 小心
5,34点就有点违背
13.描述一下持久化原理
当前线程阻塞服务
异步后台进程完成持久
fork + cow
14.描述一下redis持久化方式?
1,RDB,AOF;主从同步也算持久化
2,高版本;开启AOF,AOF时可以通过执行日志得到全部内存数据的方式,但是追求性能
2.1,体积变大,重复无效指令 重写,后台用线程把内存的kv生成指令写个新的aof
2.2,4.x 新
15.Redis也打不住了,万级流量回答到DB上,该怎么处理?
见456
16.redis中的事务三条指令是什么,第三条指令到达后执行失败了,怎么处理
17.为什么使用setnx(redis实现分布式锁的指令)
1,好东西,原子 (不存在的情况下完成创建)
1,如果要做分布式锁,就要用set k v nx ex (不存在,过期时间,避免死锁)
redis时间复杂度
String类型
命令 | 时间复杂度 |
---|---|
set | 0(1) |
get | 0(1) |
del | 0(k),k是键的个数 |
mset | 0(k),k是键的个数 |
mget | 0(k),k是键的个数 |
incr | 0(1) |
decr | 0(1) |
incryby | 0(1) |
decryby | 0(1) |
incrybyfloat | 0(1) |
append | 0(1) |
strlen | 0(1) |
setrange | 0(n),n为更改字符串长度 |
getrange | 0(n),n为获取字符串长度 |
Hash类型
命令 | 时间复杂度 |
---|---|
hset | 0(1) |
hget | 0(1) |
hdel | 0(k),k是键的个数 |
hlen | O(1) |
hgetall | 0(k),k是field的个数 |
hmget | 0(k),k是field的个数 |
hmset | 0(k),k是field的个数 |
hexists | O(1) |
hkeys | 0(k),k是field的个数 |
hvals | 0(k),k是field的个数 |
hsetnx | O(1) |
hincrby | O(1) |
hincrbyfloat | O(1) |
hstrlen | O(1) |
List列表
命令 | 时间复杂度 |
---|---|
rpush | 0(k),k是field的个数 |
lpush | 0(k),k是field的个数 |
linsert | 0(n),n是插入位置距离表头或表尾的距离 |
lrange | O(s+n),s是start的偏移量,n是start到end的范围 |
lindex | O(n),n是索引的偏移量 |
llen | O(1) |
lpop | O(1) |
rpop | O(1) |
lrem | O(n),n是列表的长度 |
ltrim | O(n),n是要裁剪的元素总数 |
lset | O(n),n是索引的偏移量 |
blpop | O(1) |
Set集合
命令 | 时间复杂度 |
---|---|
sadd | O(k),k为元素个数 |
srem | O(k),k为元素个数 |
scard | O(1) |
sismember | O(1) |
srandmember | O(count) |
spop | O(1) |
smembers | O(n),n为元素总数 |
sinter | O(m*k),k为多个集合中元素较少的个数,m是键个数 |
suinon | O(k),k为多个集合元素个数和 |
sdiff | O(k),k为多个集合元素个数和 |
Zset有序集合
命令 | 时间复杂度 |
---|---|
zadd | O(k*log(n)),k为添加 成员个数,n为当前成员个数 |
zcard | O(1) |
zscore | O(1) |
zrankzrevrank | O(log(n)),n为当前成员个数 |
zrem | O(k*log(n)),k为删除成员个数,n为当前成员个数 |
zincrby | O(log(n)),n为当前成员个数 |
zrangezrevrange | O(log(n)+k),k为要获取成员个数,n为当前成员个数 |
zrangebyscorezrevrangebyscore | O(log(n)+k),k为要获取成员个数,n为当前成员个数 |
zcount | O(log(n)+k),k为要获取成员个数,n为当前成员个数 |
zremrangebyrank | O(log(n)+k),k为要删除成员个数,n为当前成员个数 |
zremrangebyscore | O(log(n)+k),k为要删除成员个数,n为当前成员个数 |
zinterstore | O(nk) + O(mlog(m)),n是成员数最小的有序集合的成员个数,k是有序集合的个数,m是结果集中成员个数 |
zunionstore | O(n) + O(m*log(m)),n是所有有序集合成员个数和,m是结果集中成员个数 |