本文已参与「新人创作礼」活动,一起开启掘金创作之路
11、Redis如何做内存优化?
可以好好利用Hash,list,sorted set,set等集合类型数据,因为通常情况下很多小的Key-Value可以用更紧凑的方式存放到一起。尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面。
12、keys命令存在的问题?
redis的单线程的。keys指令会导致线程阻塞一段时间,直到执行完毕,服务才能恢复。scan采用渐进式遍历的方式来解决keys命令可能带来的阻塞问题,每次scan命令的时间复杂度是O(1),但是要真正实现keys的功能,需要执行多次scan。
scan的缺点:在scan的过程中如果有键的变化(增加、删除、修改),遍历过程可能会有以下问题:新增的键可能没有遍历到,遍历出了重复的键等情况,也就是说scan并不能保证完整的遍历出来所有的键。
13、Redis事务
事务的原理是将一个事务范围内的若干命令发送给Redis,然后再让Redis依次执行这些命令。
事务的生命周期:
①使用MULTI开启一个事务
②在开启事务的时候,每次操作的命令将会被插入到一个队列中,同时这个命令并不会被真的执行
③EXEC命令进行提交事务
一个事务范围内某个命令出错不会影响其他命令的执行,不保证原子性:
14、WATCH命令
WATCH命令可以监控一个或多个键,一旦其中有一个键被修改,之后的事务就不会执行(类似于乐观锁)。执行EXEC命令之后,就会自动取消监控。
比如上面的代码中:
①watch name开启了对name这个key的监控
②修改name的值
③开启事务a
④在事务a中设置了name和gender的值
⑤使用EXEC命令进提交事务
⑥使用命令get gender发现不存在,即事务a没有执行
使用UNWATCH可以取消WATCH命令对key的监控,所有监控锁将会被取消。
15、Redis事务支持隔离性吗?
Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的。
16、Redis事务保证原子性吗,支持回滚吗?
Redis单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。
17、持久化机制
持久化就是把内存的数据写到磁盘中,防止服务宕机导致内存数据丢失。
Redis支持两种方式的持久化,一种是RDB
的方式,一种是AOF
的方式。前者会根据指定的规则定时将内存中的数据存储在硬盘上,而后者在每次执行完命令后将命令记录下来。一般将两者结合使用。
18、RDB方式
RDB是 Redis 默认的持久化方案。RDB持久化时会将内存中的数据写入到磁盘中,在指定目录下生成一个dump.rdb文件。Redis 重启会加载dump.rdb文件恢复数据。
bgsave是主流的触发 RDB 持久化的方式,执行过程如下:
①执行BGSAVE命令
②Redis 父进程判断当前是否存在正在执行的子进程,如果存在,BGSAVE命令直接返回。
③父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞。
④父进程fork完成后,父进程继续接收并处理客户端的请求,而子进程开始将内存中的数据写进硬盘的临时文件;
⑤当子进程写完所有数据后会用该临时文件替换旧的 RDB 文件。
Redis启动时会读取RDB快照文件,将数据从硬盘载入内存。通过 RDB 方式的持久化,一旦Redis异常退出,就会丢失最近一次持久化以后更改的数据。
触发 RDB 持久化的方式:
手动触发:
①用户执行SAVE或BGSAVE命令。
②SAVE命令执行快照的过程会阻塞所有客户端的请求,应避免在生产环境使用此命令。
③BGSAVE命令可以在后台异步进行快照操作,快照的同时服务器还可以继续响应客户端的请求,因此需要手动执行快照时推荐使用BGSAVE命令。
被动触发:
①根据配置规则进行自动快照,如SAVE 100 10,100秒内至少有10个键被修改则进行快照。
②如果从节点执行全量复制操作,主节点会自动执行BGSAVE生成 RDB 文件并发送给从节点。
③默认情况下执行shutdown命令时,如果没有开启 AOF 持久化功能则自动执行BGSAVE。
优点:
①Redis 加载 RDB 恢复数据远远快于 AOF 的方式。
②使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 Redis 的高性能。
缺点:
①RDB方式数据无法做到实时持久化。因为BGSAVE
每次运行都要执行fork
操作创建子进程,属于重量级操作,频繁执行成本比较高。
②RDB 文件使用特定二进制格式保存,Redis 版本升级过程中有多个格式的 RDB 版本,存在老版本 Redis 无法兼容新版 RDB 格式的问题。
19、AOF方式
AOF(append only file)持久化:以独立日志的方式记录每次写命令,Redis重启时会重新执行AOF文件中的命令达到恢复数据的目的。AOF的主要作用是解决了数据持久化的实时性,AOF 是Redis持久化的主流方式。
默认情况下Redis没有开启AOF方式的持久化,可以通过appendonly参数启用:appendonly yes。开启AOF方式持久化后每执行一条写命令,Redis就会将该命令写进aof_buf缓冲区,AOF缓冲区根据对应的策略向硬盘做同步操作。
默认情况下系统每30秒会执行一次同步操作。为了防止缓冲区数据丢失,可以在Redis写入AOF文件后主动要求系统将缓冲区数据同步到硬盘上。可以通过appendfsync参数设置同步的时机。
appendfsync always //每次写入aof文件都会执行同步,最安全最慢,不建议配置
appendfsync everysec //既保证性能也保证安全,建议配置
appendfsync no //由操作系统决定何时进行同步操作
接下来看一下 AOF 持久化执行流程:
①所有的写入命令会追加到 AOP 缓冲区中。
②AOF 缓冲区根据对应的策略向硬盘同步。
③随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩文件体积的目的。AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。
④当 Redis 服务器重启时,可以加载 AOF 文件进行数据恢复。
优点:
①AOF可以更好的保护数据不丢失,可以配置 AOF 每秒执行一次fsync操作,如果Redis进程挂掉,最多丢失1秒的数据。
②AOF以append-only的模式写入,所以没有磁盘寻址的开销,写入性能非常高。
缺点:
①对于同一份文件AOF文件比RDB数据快照要大。
②数据恢复比较慢。
20、RDB和AOF如何选择?
通常来说,应该同时使用两种持久化方案,以保证数据安全。
①如果数据不敏感,且可以从其他地方重新生成,可以关闭持久化。
②如果数据比较重要,且能够承受几分钟的数据丢失,比如缓存等,只需要使用RDB即可。
③如果是用做内存数据,要使用Redis的持久化,建议是RDB和AOF都开启。
④如果只用AOF,优先使用everysec的配置选择,因为它在可靠性和性能之间取了一个平衡。
当RDB与AOF两种方式都开启时,Redis会优先使用AOF恢复数据,因为AOF保存的文件比RDB文件更完整。