Redis学习笔记(1)——基本概念

Redis是什么

Redis是一个开源的、基于内存、提供多种数据结构、支持持久化的非关系型数据库。

Redis为什么快

  • Redis绝大多数操作是纯内存操作,内存的读写速度远远大于硬盘的读写速度。
  • Redis采用多路复用的非阻塞IO机制,对数据的操作是单进程、单线程的,避免多线程中上下文切换造成的时间浪费。
  • 数据结构简单、高效。

为什么选择Redis作为缓存

  • 相比Memcached,Redis的优势为:
    • 支持多种数据类型;
    • 支持持久化数据;
    • 支持更大的value(512MB);
    • 原生支持集群。

旧版Redis单线程的原因

  • 使用多线程带来的好处是提高CPU利用率,但Redis的瓶颈不在CPU,而在于网络带宽和内存大小。
  • 避免线程切换带来的性能开销。
  • 单线程无需考虑线程安全问题,简化数据结构和算法的实现。
  • 采用多路复用IO技术,单线程就能处理多个IO事件。
  • 注意:旧版Redis不是完全单线程的,只是网络IO和数据操作是单线程的。持久化机制、集群支撑模块等是多线程的。

新版Redis为何采用多线程

  • Redis 6.0版本使用多线程处理网络请求,但对数据的操作仍然是单线程的。
  • Redis的瓶颈在于网络IO的处理,尽管单线程的多路复用IO性能已经很好,但在并发量极高的场景下,仍然不够。采用多个IO线程来处理网络请求,可以提高网络请求的处理速度,并充分利用多核心CPU。
  • Redis 6.0默认是禁用多线程的,需要开启io-threads-do-reads yes并配置线程数。

Redis线程模型

  • Redis基于Reactor模式开发了自己的网络事件处理器:
    • 文件事件处理器以单线程方式运行,通过I/O多路复用程序监听多个套接字,并根据套接字目前执行的任务为套接字关联不同的事件处理器。
    • 文件事件分派器接收I/O多路复用程序传来的套接字,根据套接字产生的事件类型调用相应的事件处理器。
    • 事件处理器包括命令请求处理器、命令回复处理器、连接应答处理器等。
  • Redis的I/O多路复用程序有selectepollevportkqueue等多个I/O多路复用库实现可选,会在编译时自动选择系统中性能最高的I/O多路复用库作为底层实现。

Redis使用场景

  • 缓存:Redis读写性能优异,且支持的数据类型丰富,适合做缓存。
  • 分布式Session:用Redis集中处理Session,解决不同服务器间Session的通信问题。
  • 分布式ID:Redis是单线程的,可以用自增命令来生成全局唯一ID。
  • 分布式锁:利用SETNX或者Redlock做分布式锁。
  • 排行榜:利用zset天生有序的特性,可以实现排行榜功能。
  • 计数器:利用Redis原子自增或者自减,可以实现计数器功能。
  • 消息队列:list数据结构基于双向链表,利用其先进先出的特性可以作为消息队列使用。但是与专业的MQ相比,存在很多缺陷:
    • 没有ACK机制,需要自己处理消息丢失的问题;
    • 不支持一个消息被多个消费者消费。

分布式锁

  • SETNX key value:只有当键不存在时才写入键值,如果键已经存在,则不做任何操作。通常需要EXPIRE key seconds命令来设置锁的过期时间,但如果SETNX操作成功,但EXPIRE设置失败,会导致死锁。
  • SET key value NX EX seconds:Redis 2.6.12版本使用SET命令涵盖了SETNX的功能,避免了上述死锁的情况。
  • Redlock是在分布式环境下更高级的分布式锁的实现,其流程为:
    • 客户端记录当前UNIX时间。
    • 客户端依次尝试从N个Redis实例获取锁,获取锁时设置一个超时时间,避免Redis节点失效时客户端仍在等待锁。
    • 计算获取锁花费的时间(用当前时间减去开始尝试获取锁时的时间),只有这个时间小于锁失效的时间才算获取这个节点的锁成功,只有当获取了至少N/2+1个实例上的锁才算获取分布式锁成功。
    • 如果获取锁失败,客户端给每个实例解锁。