redis单线程有什么优势与缺点?
- 优点:
1. 代码更清晰,处理逻辑更简单
2. 不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
3. 不存在多进程或者多线程导致的切换而消耗CPU
- 缺点:因为是单线程的,无法发挥多核cpu的优势,容易阻塞。
1.Redis有哪些常用的数据类型
2、Redis备份方式区别
- snapshotting(快照)默认方式,将内存中以快照的方式写入到二进制文件中,默认为dump.rdb.可以通过配置设置自动做快照持久化的方式。我们可以配置redis在n秒内如果超过m个key则修改就自动做快照。
snapshotting设置:
save 900 1 #900秒内如果超过1个key被修改则发起快照保存(15分钟变更一次)
save 300 10 #300秒内如果超过10个key被修改,则发起快照保存(5分钟变更10次)
save 60 10000 (1分钟变更1万次)
- append-only file(缩写aof)的方式(有点类似于oracle日志)
由于快照方式是在一定时间间隔做一次,所以可能发生redis意外down的情况就会丢失最后一次快照后的所有修改的数据、aof比快照方式有更好的持久化性,是由于在使用aof时,redis会将每一个收到的写命令都通过write函数追加到命令中,当redis重新启动时会重新执行文件中保存的写命令来在内存中重建这个数据库的内容,这个文件在bin目录下:
appendonly.aof。aof不是立即写到硬盘上,可以通过配置文件修改强制写到硬盘中。
aof设置:
appendonly yes //启动aof持久化方式有三种修改方式:
#appendfsync always //收到写命令就立即写入到磁盘,效率最慢,但是保证完全的持久化
#appendfsync everysec //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中
#appendfsync no //完全依赖os性能最好,持久化没保证
AOF开通写日志操作。
AOF定义:以日志的形式记录每个操作,将Redis执行过的所有指令全部记录下来(读操作不记录),只许追加文件但不可以修改文件,Redis启动时会读取AOF配置文件重构数据
换句话说,就是Redis重启就会根据日志内容从头到尾执行一次来完成数据的恢复工作。
3、Redis AOF 备份文件过大怎么处理
AOF的Rewrite(重写) :
定义:AOF采用文件追加的方式持久化数据,所以文件会越来越大,为了避免这种情况发生,增加了重写机制;当AOF文件的大小超过了配置所设置的阙值时,Redis就会启动AOF文件压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof
原理:当AOF增长过大时,会fork出一条新的进程将文件重写(也是先写临时文件最后rename),遍历新进程的内存数据,每条记录有一条set语句。
重写AOF文件并没有操作旧的AOF文件,而是将整个内存中的数据内容用命令的方式重写了一个新的aof文件(有点类似快照)
触发机制:Redis会记录上次重写时的AOF文件大小,默认配置时当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
auto-aof-rewrite-percentage 100 (一倍)
auto-aof-rewrite-min-size 64mb
4、redis做集群?
- redis cluster 的hash slot 算法
redis cluster有固定的16384个hash slot,对每个key计算CRC16值,然后对16384取模,可以获取key对应的hash slot;
redis cluster中每个master都会持有部分slot,比如有3个master,那么可能每个master持有5000多个hash slot;
hash slot让node的增加和移除很简单,增加一个master,就将其他master的hash slot移动部分过去,减少一个master,就将它的hash slot移动到其他master上去,移动hash slot的成本非常低;
- redis cluster 简单配置
cluster-enabled <yes/no>
cluster-config-file :这是指定一个文件,供cluster模式下的redis实例将集群状态保存在那里,包括集群中其他机器的信息,比如节点的上线和下限,故障转移,不是我们去维护的,给它指定一个文件,让redis自己去维护.
cluster-node-timeout :节点存活超时时长,超过一定时长,认为节点宕机,master宕机的话就会触发主备切换,slave宕机就不会提供服务.
5、Redis限制频率问题比如:
(1)限制ip每分钟访问接口100次
ip为key访问次数为value,过期时间为一分钟(但是这种会有临界值问题,限制频率不准确)
(2)如果考虑临界值问题准确限制ip每分钟限制100次
可以选择列表类型来实现,记录每个ip每次访问的时间,一旦列表元素超过100,就判断时间最早的元素距离现在的时间是否小于1分钟,如果是则表明最近一分钟超频,否则就将现在的时间加入列表同时删除最早的时间元素。
例子:短信发送的并发请求问题,是需要限制一个号码一分钟内只能获取一次随机码,一般的接口开发刷新一次接口链接就会发送一次短信,当有大用户量并发时会造成服务器高负载,短信资源的极大浪费,因此有必要做接口的防刷和限流。实现方式可以在前端设定时间,也可以在接口处用缓存做接口限流进行实现。
1.使用Redis incr解决问题
Redis incr 可以实现原子性的递增,可应用于高并发的秒杀活动、分布式序列号生成等场景。这里我使用它来计数实现一分钟内只接受一次请求。
2.设计思路
实现逻辑也很简单:我们在接到短信发送请求后,使用Redis的incr设置一个递增KEY(KEY由固定字符串+手机号码组成),并判断该KEY的数值,如果等于1,说明是第一个请求,我们将该KEY值有效期设置为一分钟;如果该KEY的数值大于1,说明是1分钟内的多次请求,这时我们直接返回短信获取频繁异常。
6、缓存穿透、缓存雪崩和缓存击穿
- 缓存穿透:查询一个数据库一定不存在的数据。key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据源。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
方案:采用缓存空值的方式,如果从数据库查询的对象为空,也放入缓存,只是设定的缓存过期时间较短,比如设置为60秒 - 缓存击穿:key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
方案:
使用互斥锁(mutex key),就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。 - 缓存雪崩:当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。
方案:一般是采取不同分类商品,缓存不同周期。在同一分类中的商品,加上一个随机因子。这样能尽可能分散缓存过期时间,而且,热门类目的商品缓存时间长一些,冷门类目的商品缓存时间短一些,也能节省缓存服务的资源