Redis1️⃣NoSQL 数据库 & Redis 简介

1、NoSQL 数据库

non-relational SQL,也称 Not Only SQL

泛指非关系型数据库,作为关系型数据库的补充。

作用:应对基于海量用户和海量数据前提下的数据处理问题。

  1. 降低 CPU 及内存压力。
  2. 降低 I/O 压力。

1.1、对比 SQL

SQL NoSQL
结构化
存储方式 基于业务逻辑(表结构,约束) 基于 K-V 模式
存储位置 磁盘 内存
事务 ACID 强一致性 BASE 弱一致性
扩展性 垂直(主从集群) 垂直(主从集群),水平(分片集群)
适用场景 要求强事务支持,即席查询(按需求添加查询条件) 高并发读写,海量读写,高可扩展性要求

说明

  1. NoSQL 数据存储在内存中,查询效率远高于 SQL 数据库。
  2. SQL 本身不支持水平扩展,但可借助第三方工具进行分库分表

1.2、常见 NoSQL

Memcache Redis MongoDB
存储形式 K-V 型 K-V 型 文档型
说明 早期 NoSQL 数据库,Redis 的雏形 涵盖了 Memcache 的大部分功能 模式自由的文档型数据库
数据存储 内存 内存 内存
持久化 不支持 支持
(用于备份恢复)
支持
(内存不足时,将不常用数据保存到硬盘)
数据类型 简单 K-V 模式
(字符串)
丰富的 K-V 模式
Redis 数据类型
对 Value 提供丰富的查询功能(尤其是 JSON),支持二进制数据和大型对象

其它常见 NoSQL

HBase(列类型),Neo4j(图类型)

2、Redis

2.1、简介

Redis(Remote Dictionary Server)

远程词典服务器

基于内存的开源 K-V 型存储系统,具备高性能和高并发的特点。

  1. 基于内存
  2. 存储形式:全局链式哈希表,K-V 型。
    • Key:通常是字符串类型,且支持设置过期时间。
    • Value:支持多种数据结构。
    • 数据的操作指令具有原子性
  3. 线程模型
    • 单线程:保证线程安全,不会因线程切换而影响性能(Redis 6 引入网络多线程)
    • I/O 多路复用:epoll,解决并发需求。
  4. 存储:数据存储在内存中,支持持久化
  5. 集群:支持搭建主从集群(垂直),分片集群(水平)。
  6. 渐进式扩容:Redis 默认两张全局哈希表。
    1. 数据存储在第一张,需要扩容时使用第二张,并将第一张的元素映射到第二张。
    2. 请求分摊:每处理一次请求,就将一个哈希桶的元素映射到另一张表,每个请求分摊了哈希映射的时间。
    3. 定时器:周期性地进行数据的重新映射。
  7. 支持多语言客户端。

2.2、安装

👉 CentOS7 安装 Redis

3、线程模型

在 Redis 6 之前,单线程 + IO 多路复用

  • 多路:多个 socket 连接
  • 复用:一个线程

文件事件处理器

File Event Handler(FEH)

基于 Reactor 模式开发的、单线程的网络事件处理器

组成

  • 多个 Socket(不同客户端请求会建立不同的 Socket)

    • 连接应答(accept)
    • 读取(read)
    • 写入(write)
    • 关闭(close)
  • IO 多路复用程序

  • 文件事件分派器

  • 事件处理器

    • 连接应答处理器:客户端连接 redis

    • 命令请求处理器:客户端要写数据到 redis

    • 命令回复处理器:客户端要从 redis 读数据

      image

处理流程

  1. 监听多个 Socket,根据 Socket 需要执行的操作产生事件。

  2. 将产生事件的 Socket 依次放入队列,有序、同步地发送给文件事件分配器。

    (处理完成后才发送下一个 Socket)

  3. 根据事件类型为 Socket 绑定事件处理器。

  4. 调用绑定好的事件处理器来处理事件。

一次通信过程

  1. Redis 启动初始化时,将连接应答处理器AE_READABLE 事件关联。

  2. 若一个客户端(redis-cli)发起连接,会产生一个 AE_READABLE 事件。

    1. 连接应答处理器负责和客户端建立连接,创建客户端对应的 Socket
    2. 同时将这个 Socket 的 AE_READABLE 事件和命令请求处理器关联。
    3. 使客户端可以向主服务器发送命令请求。
  3. 当客户端向 Redis 发请求时(读/写)

    1. 客户端对于的 socket 会产生一个 AE_READABLE 事件,触发命令请求处理器
    2. 处理器从 Socket 读取客户端请求, 传给相关程序执行。
  4. 当 Redis 服务器准备好给客户端的响应数据后,将 socket 的 AE_WRITABLE 事件和命令回复处理器关联。

  5. 当客户端准备好读取响应数据时

    1. 在 socket 产生一个 AE_WRITABLE 事件

    2. 由对应命令回复处理器处理,将准备好的响应数据写入 socket,供客户端读取。

    3. 全部数据写完后,删除该 socket 的 AE_WRITABLE 事件和命令回复处理器的关联。

      img

实现技术

select

过程:同时监控多个 fd(file descriptor, 文件描述符)

  1. 调用时会阻塞,OS 将用户进程加入到所有资源的等待队列中。
  2. 当其中有 fd 就绪(可读/可写/except)、超时(timeout),函数返回。
    1. 就绪:返回可读、可写的文件描述符个数
    2. 超时:返回 null。
  3. 函数返回后
    1. 中断程序唤起用户线程。
    2. 用户可以遍历所有 fd,通过 FD_ISSET 判断具体哪个 fd 收到数据,做出相应处理。

特点:实现简单,但开销大。

  1. 遍历
    1. 每次调用 select 都需要将进程加入到所有监视 fd 的等待队列(遍历)
    2. 每当函数返回,将就绪的 fd 写入 fd_set 中,将整个 fd_set 传给内核,拷贝到用户空间。(拷贝)
    3. 每次唤醒都需要从每个队列中移除(遍历)。
    4. 为了知道哪个 fd 收到数据,需要遍历所有监视 fd(遍历)。
  2. 大小限制:fd_set 的大小有限
    • 32 位系统最多监听 1024 个
    • 64 位系统最多监听 2048 个。

poll

对比 select

  1. 相同:拷贝全部监听的 fd,即 fd_set。
  2. 不同
    1. fd_set 是链表结构,不受数量限制。
    2. 函数返回后,通过 pollfd 结构处理就绪的 fd。

缺点:同 select

  1. 函数返回后,需要遍历 pollfd 来获取就绪的 fd。
  2. 而实际上,连接的客户端在同一时刻可能只有很少处于就绪状态,随着 fd 数量增加,性能线性下降。

epoll(最新)

(Linux 特有)使用一个 fd 管理多个 fd

将用户进程监控的 fd 的事件存放到内核的一个事件表中,

这样在用户空间和内核空间只需拷贝一次。

  1. epoll_create:创建一个 epoll 的句柄。
    1. 参数 size 并非限制了 epoll 所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。
    2. epoll 句柄占用一个 fd 值,使用完必须关闭,避免 fd 耗尽。
  2. epoll_ctl:事件注册函数,将需要监听的事件和需要监听的 fd 交给 epoll 对象。
    1. 事件:添加(EPOLL_CTL_ADD),删除(EPOLL_CTL_DEL),修改(EPOLL_CTL_MOD)
    2. 结构:红黑树。避免重复添加,性能高 O(lognN)
    3. 事件说明
      1. 事件一旦添加,触发回调关系的建立。
      2. 事件一旦发生,调用回调函数 ep_poll_callback,将事件对应 fd 的 epitem 添加到 rdlist 双向链表。
  3. epoll_wait
    1. 等待 io 事件,当回调函数被调用时会唤醒该进程。
    2. 检查 rdlist 双向链表是否有注册事件,拷贝到 txlist,清空 rdlist。
    3. ep_send_events 函数
      1. 遍历 txlist,调用每个 epitem 关联的 fd 的 poll
      2. 目的是取得 fd 上较新的 events,发送到用户空间(封装在struct epoll_event)
    4. 返回 events

工作模式

  1. LT(level triggered):水平触发,默认
    1. 当 epoll_wait 检测到 fd 事件发生,将事件通知应用程序
    2. 应用程序可以不立即处理该事件。
    3. 下次调用 epoll_wait 时会再次通知。
  2. ET(edge-triggered):边缘触发(减少 epoll 事件重复触发)
    1. 应用程序必须立即处理该事件。
    2. 如果不处理,下次调用 epoll_wait 时不会再次通知。

对比

  1. select 和 poll 基本一致,
    1. select 采用数组存储,监听数量有限。
    2. poll 采用链表存储,不受限制。
  2. select、poll、epoll 都会返回就绪 fd 数量。
    1. select 和 poll 不会明确指出就绪 fd,需要遍历所有监听 fd。
    2. epoll 会,可直接处理即可。
  3. 检查 fd 就绪
    1. select、poll:轮询,随着 fd 增加 性能降低,
    2. epoll:通知 + 回调,不会 fd 数量影响,除非活跃 socket 很多。
  4. 工作模式:epoll 支持 ET,效率高。
  5. 拷贝
    1. select、poll 需要将有关 fd 的数据结构拷贝进内核,最后再拷贝出来。
    2. epoll:有关数据结构本身就存于内核态中,利用 mmap() 文件映射,减少开销。

img

Redis 6 多线程

网络 IO 多线程

只处理 Socket 读写,执行命令仍是单线程。

在这里插入图片描述

posted @ 2022-04-13 21:50  Jaywee  阅读(13)  评论(0编辑  收藏  举报

👇