redis高级特性

一、数据失效方式:

因为Redis是基于内存的,而由于内存的昂贵,注定它的大小是有限的,所以当数据量较大、内存被占满的时候,再插入新数据,就要涉及到如何进行调度了。

调度方式主要分为四类:

  1. 不删除
  2. LRU(最近最久未使用)
  3. 随机删除
  4. 删除剩余过期时间最短

再考虑到部分key存在过期的特性,所以分为一下具体6类:

  1. noeviction:达到内存限额后返回错误,不删除已有内容。
  2. allkeys-lru:使用LRU算法(针对所有数据)
  3. volatile-lru:使用LRU算法(针对设置有过期时间的数据)
  4. allkeys-random:随机删除(针对所有数据)
  5. volatile-random:随机删除(针对设置有过期时间的数据)
  6. volatile-ttl:对设置有过期时间的数据中,删除即将失效的。


二、事务:

1、redis是支持事务的,但是很重要的一点是: 不支持回滚机制。 什么意思呢?如果在事务中执行了10条命令,在第三条失败后,后面的4-10不会执行,但是前面的1-2却是能够生效的(在mysql等数据库中,如果事务中出现错误,会整个回滚到事务执行前的状态)

2、watch命令:为了照顾事务中数据一致性,redis也提供了watch乐观锁机制来保证数据一致。具体的方式就是在事务中,对某些key执行watch命令,之后再填写对应操作命令,如果在执行事务时发现被watch的key已经修改,那么在watch之后的所有命令就失败。通过这样的方式在不支持回滚的情况下,也保证了数据的一致性。


三、数据持久化:redis中,持久化是作为备份的手段使用的,一般来说常用的方式有两种:

1、snap shot(快照机制,也就是常说的rdb):

首先执行save或bgsave命令,它们俩的区别是save会直接在主进程中执行备份(此时主进程阻塞,就相当于此时redis不能提供服务了),bgsave会启动一个子进程执行备份操作,而父进程继续提供服务。
bgsave命令的执行过程:

  1. redis调用fork,现在有了子进程和父进程。

  2. 父进程继续处理client请求,子进程负责将内存内容写入到临时文件。由于os的写时复制机制(copyon write)父子进程会共享相同的物理页面,当父进程处理写请求时os会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程的地址空间内的数据是fork时刻整个数据库的一个快照。

  3. 当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出。

2、aof(append-only file):本质上就是一个记录日志文件的机制

redis会将每一个收到的 写命令 都通过write函数追加到文件中(默认是 appendonly.aof)。当redis重启时会通过重新执行文件中保存的 写命令 来在内存中重建整个数据库的内容。

这样做的好处是实时保存的内存占用比快照小很多(使用快照保存一次会占用当前内存双倍的空间)

但aof文件的追加写方式 会导致磁盘增量占用 ,解决方式是重写aof文件,什么意思呢?就是在特定的时间(可以自己规定和调用,一般是在aof文件过大的时候)启动子进程收集当前库中数据并转化为写命令,把这些命令写入临时文件中,完成之后再用临时文件替换老的aof文件,这样就达到了aof文件的“瘦身”。(其实就有点类似于rdb中的bgsave,只不过区别是aof存的是命令,而rdb存的是具体数据)
aof的触发方式有以下三种:

  1. appendfsyncalways (每次收到一条命令就执行一次AOF,不推荐,太耗资源)
  2. appendfsyncno (完全依赖OS调度,不推荐,不稳定)
  3. appendfsync everysec (每秒钟强制写入磁盘一次,资源和稳定性平衡,推荐使用)


四、主从复制:

主从复制方式主要用于容灾、备份。(注意它不是分布式解决方案,它只是远程备份)。

配置方式如下:

  • 配置slave服务器只需要在slave的配置文件中加入如下配置即可,剩下的redis会自动帮你处理:

    slaveof 192.168.1.1 6379 #指定master的ip和端口

具体过程如下:

主从辅助过程


五、消息订阅:

redis可以作为一个pub/sub server,在订阅者和发布者之间起到了消息路由的功能。

订阅者可以通过subscribe和psubscribe命令向redis server订阅自己感兴趣的消息类型,redis将消息类型称为通道(channel)。

当发布者通过publish命令向redis server发送特定类型的消息时。订阅该消息类型的全部client都会收到此消息。

这里消息的传递是多对多的。一个client可以订阅多个 channel,也可以向多个channel发送消息。

实际上就可以通过redis实现一个轻量级的消息队列,可用于小型的服务(例如简单的任务下发)