Redis数据一致性分析

提要

Redis是一款优秀的分布式缓存中间件。当然它能胜任的工作还有很多,比如说队列、分布式锁、Key-Value数据库。Redis的优秀毋庸置疑,但是它也有明显的短板,那就是无法保证数据的强一致性。如果你对数据一致性要求不高,完全可以考虑使用Redis存放业务数据。接下来我将列举Redis的优势,然后再聊聊Redis数据一致性。

优势

定制化的数据结构

字符串(SDS)

  • 字符串保存自身长度,查询长度只需O(1)复杂度;
  • 字符串拼接操作不会带来数组越界异常;
  • 修改字符串不需要重新分配内存空间;
  • 可以保存二进制数据;

跳跃表(skip list):顺序链表。实现简单,查找快速,平均操作复杂度O(logN)。
字典(dict):等同于Map。渐进式Rehash。优雅地实现扩容,减少扩容带来的阻塞。
压缩列表(ziplist):使用二进制方式保存字符串和整数,节省内存。

高并发

Redis根据操作系统类型的选择合适的IO模型,其中最让人称道的是Epoll支撑下的事件驱动模型(Reactor模型)。Epoll可以支持大量的链接(理论上线是INT类型的最大值),并以O(1)复杂度通知用户进程IO事件。这两点为Redis高并发打下了坚实的基础。

线程安全

Redis的操作都是线程安全的,大部分用户指令都是原子的。原因很简单,Redis是单线程模型。不适合在主进程执行的操作(比如说RDB、AOF重写),它选择使用子进程进行处理(子进程拷贝父进程数据)。

集群

Redis3.0之后提供Redis Cluster功能,配合redis-trib工具,使用者可以轻松搭建一个Redis集群。Redis集群支持动态扩容缩容,支持主从互备,支持自动地故障转移。

数据一致性分析

数据一致性,Redis要么明确告知客户端请求失败,要么正确响应客户端请求并且持久化结果。

单机持久化

Redis提供两种持久化方式分别是:RDB和AOF。需要说明的一点是写入文件并不代表持久化成功,还需要将文件同步到磁盘。

RDB

RDB指的是Redis将内存中的用户数据持久化到磁盘。这就注定RDB只能在一定时间间隔的情况执行。Redis支持时间间隔和数据修改次数两种维度出发RDB。当然我们也可以通过执行SAVE或者BGSAVE命令显示地持久化数据。显而易见,以上方式总是无法避免部分最新的数据无法持久化到磁盘。

AOF

AOF指的是Redis记录所有的写操作命令,并且持久化。AOF持久化有三个级别

  • no:AOF文件同步交给操作系统决定;
  • everysec:每隔一秒执行一次文件同步;
  • always:写入文件立即同步。

虽然always级别最消耗性能,但是它似乎能够保证数据的一致性。不幸的是,它也不能保证数据绝对的一致性。原因如下:
1.无法以事务的形式写AOF文件和执行写操作。一旦机器在写AOF文件和执行写操作中间的某一时刻崩溃,都会导致数据的不一致性。Mysql使用二阶段提交解决这个问题。
2.文件同步到磁盘过程并非原子操作。mysql同步磁盘使用”double write”解决这个问题。

主从数据一致性

Redis支持主从互备,自动地故障转移。如果主从之间能够保证数据一致性,那我们也不需要担心持久化造成的数据不一致。不幸的是主从互备并不能保证数据一致性。

  1. 宕机。虽然多台机器同时宕机的概率极低。但我们不能忽略这种可能(墨菲定律)。
  2. 网络故障。主服务器主动将所有写操作发给从服务器。当网络通信不畅时,就会出现主从不同步。即使网络恢复正常,主服务器也不会将从服务器未接收到的命令发给从服务器。Mysql主从解决方案,从服务器以发送确认信号的方式确保主从一致。
  3. 过期Key。从服务器不会主动删除过期Key。即使我们访问从服务期的过期Key,从服务器将过期key返回给客户端。

总结

Redis一款优秀的缓存中间件。Redis的短板在于它无法保证数据的强一致性。如果您的业务场景对数据一致性要求很高,请不要把Redis当做DB使用。