基础篇
基本数据类型
string 常见于计数a
list 有序集合 常见于实现队列
hash 对象存贮
set 排重
zset 排重且有序
持久化策略
RDB 是 采用快照的方式,用bgsave的话,“写时复制”——会fork一个子进程出来负责记录写入,不影响主进程,完事再替换。
AOF 就是直接追加所有的写入操作命令。当aof文件过大触发rewrite:fork一个子线程新开辟一个aof文件去备份。
数据的完整性要好很多,所以在恢复数据时,redis也是优先 使用aof的文件。
底层原理
基础概念:
1.IO多路复用,多个socekt用同一根网线(单线程去监听然后通知)。
2.同步|异步、阻塞|非阻塞,同步异步 --强调被调用方是否等待,阻塞非阻塞强调调用方是否等待。(参考服务员和顾客)。
3.BIO-NIO-IO多路复用,
bio,accept和read都会阻塞,改进用 多线程去read.但开销大,tomcat7以前都是用的bio加多线程。
nio,(单线程,socket的list,谁有就读谁)用户程序调用read(),没有数据就返回error,不用阻塞。缺点:循环read(),就频繁的两态切换。
IO多路复用,将寻找可读的过程放入内核态,主动通知用户程序来read();
select() 返回bitmap数组,缺点最大1024,用户程序仍需遍历。
poll()比上面好在,没有大小限制,可以复用数组。
epoll()会将有数据的放置在最前面.O(1)
过期数据的“GC”
朴素思想:
立即删除:对cpu不友好
懒删除:对内存不友好
中和版,定期删除,但就需考虑 删除的频次和时长了,而且犹豫redis是随机抽查的,有可能导致 有的key一直没被删除调优:
默认策略:non
推荐策略:allkey lru
主从 数据同步
1.建立链接
2.发送rdb文件
3.发送期间的修改数据
应用篇
分布式锁
用redis 获取锁 对 在不同服务器上都可见的命令是 setnx()
1.手动释放锁 之前 出现异常之类,无法释放锁,导致死锁,setnx()加过期时间,自动释放锁
2. 当 过期时间 很短 小于 操作共享资源的时间,就可能导致手动释放时 误删别人的锁,setnx前生成uuid,手动释放包一层if判断。
3.但 判断 + 释放,不原子,仍可能会误删锁,用lua脚本,相当于把判断的操作放到 redis命令里了。
mysql和redis的数据一致性
用于同步的中间件 canal:
伪装自己为 mysql 中的slave,向master 发送dump协议请求,master就会放松binlog日志给canal。1.先update redis ,后update mysql
排除,底单数据以mysql为准
2. 那么就 先 update mysql 后 update redis
但 update redis 的操作 不如 直接淘汰. 因为 update 常涉及其它关联数据的计算。那么 问题就变成 redis的删除与update mysql的先后了。
3. 先删redis,后update mysql
缺点:当中间异常或“ update不成功”,会导致其它线程 将mysql旧数据,重写回redis
解决:延时双删,就是等其它线程写完旧数据,再删一次redis.
进一步的常见面试问题。
3.1延时多久
压测后,在读操作的耗时上 加 几百毫秒
3.2要是mysql主从读写分离配置导致读操作回写旧值到redis?
此时,redis 删除了,master更新了,但还未 主从同步,线程B去从库读到了旧值。
延时等于 在主从同步的基础上加上几百毫秒。
3.3这种同步淘汰策略 导致,吞入量降低了怎么办?
异步去延迟和删。
4、先update mysql,后删redis
缺点:当“删redis不成功”,导致redis中始终为旧值。
解决:消息队列 重试推荐:使用4,延时双删还得评估 读操作的耗时。