• redis极速的奥秘


    1.基于内存存储实现

    内存读写是比在磁盘快很多的,Redis 基于内存存储实现的数据库,相对于数据存在磁盘的 MySQL 数据库,省去磁盘 I/O的消耗。
    而使用数据持久化的情况下,Redis会将数据同时保存在内存和磁盘中。
    Redis提供了两种持久化方式:RDB(Redis Database)和AOF(Append Only File)。

    • RDB持久化方式会定期将内存中的数据快照以二进制形式保存到磁盘上。当Redis重启时,可以通过加载RDB文件将快照数据恢复到内存中。
    • AOF持久化方式会将每一条写命令追加到磁盘上的AOF文件中。当Redis重启时,会通过重新执行AOF文件中的所有命令来恢复数据。
      无论是RDB还是AOF,都会将数据保存在磁盘上,以保证数据的持久性和可靠性。同时,数据也会保留在内存中,以确保Redis在读取和处理数据时的高性能。
      需要注意的是,如果同时开启了RDB和AOF持久化方式,Redis在进行数据恢复时,会优先选择AOF文件进行恢复,因为AOF文件包含了更完整的历史记录。如果AOF文件损坏或不完整,才会使用RDB文件进行恢复。

    2.高效的数据结构

    MySQL 的索引使用的是B+树,而redis则是由多种数据结构和内部编码
    在Redis中,每种数据结构的底层实现数据结构如下:

    1. 字符串(String):字符串数据结构是简单的动态字符串(SDS),它是一个包含了字符数组和长度信息的结构体。如C语言中字符串会遇到’\0’会结束,SDS标志字符串结束的是len属性。它是对C语言中的字符串的一种封装,而SDS提供了更多的功能和优势。
      简单动态字符串具有以下特点:

      • 动态调整大小:SDS的长度可以根据需要动态地调整,通过记录字符串的长度和分配的空间大小来实现。在进行字符串修改操作时,SDS会根据需要自动扩展或缩小内存空间,避免了频繁的内存分配和拷贝。
      • 二进制安全:SDS不仅可以存储文本字符串,还可以存储二进制数据。由于SDS内部维护了字符串的长度信息,所以它可以准确地表示任意二进制数据,而不受到C字符串中使用’\0’字符作为字符串结束符的限制。
      • 高效的常数时间操作:SDS支持常数时间的字符串长度获取、追加、删除等操作。这是通过维护字符串的长度信息和使用预分配的空间来实现的。
      • 兼容C字符串:SDS可以将C字符串转换为SDS,并且可以直接通过指针访问SDS中的数据。这使得SDS可以与现有的C库函数和代码无缝集成。
    2. 哈希表(Hash):哈希表的底层实现是字典(Dictionary)。字典是一种用于存储键值对的散列表,采用了哈希算法来实现高效的查找和插入操作。

    3. 列表(List):列表的底层实现是双向链表(Doubly Linked List)。双向链表是一种每个节点都包含前后指针的数据结构,可以在常数时间内进行节点的插入、删除、访问等操作。

    4. 集合(Set):集合的底层实现有两种:一种是基于哈希表的实现,另一种是基于有序集合的实现。具体使用哪种实现方式取决于集合的大小和元素类型。

    5. 有序集合(Sorted Set):有序集合的底层实现是跳跃表(Skip List)和哈希表的组合。跳跃表是一种有序的、快速查询的数据结构,可以按照分数进行有序存储和查询。跳表的特色:

      • 高效的查找、快速定位到需要的元素、通过跳过一部分数据,查找操作的平均时间复杂度为O(log N),其中N是元素的数量。这使得跳表在实现有序集合时非常高效,不需要像传统的有序数组那样进行线性搜索。
      • 支持范围查找、有序集合中十分重要

    3.合理的数据编码

    Redis 支持多种数据数据类型,每种基本类型,可能对多种数据结构。什么时候,使用什么样数据结构,使用什么样编码,是 redis 设计者总结优化的结果。

    • String:如果存储数字的话,是用 int 类型的编码;如果存储非数字,小于等于39 字节的字符串,是 embstr;大于 39 个字节,则是 raw 编码。
    • List:如果列表的元素个数小于 512 个,列表每个元素的值都小于 64 字节(默认),使用 ziplist 编码,否则使用 linkedlist 编码
    • Hash:哈希类型元素个数小于 512 个,所有值小于 64 字节的话,使用ziplist 编码,否则使用 hashtable 编码。
    • Set:如果集合中的元素都是整数且元素个数小于 512 个,使用 intset 编码,否则使用 hashtable 编码。
    • Zset:当有序集合的元素个数小于 128 个,每个元素的值小于 64 字节时,使用ziplist 编码,否则使用 skiplist(跳跃表)编码

    4.合理的线程模型

    I/O多路复用(IO Multiplexing)是一种同时监视多个I/O流的机制,它允许单个线程同时处理多个I/O操作,提高系统的并发性能。通过使用I/O多路复用,可以避免单线程在处理阻塞式I/O时出现的等待时间,从而提高系统的效率。
    在Redis中,I/O多路复用是用来处理客户端连接和网络通信的关键机制。Redis服务器在启动时会创建一个I/O多路复用的事件循环(Event Loop),它负责监听和处理客户端的请求和网络事件。
    具体表现在以下几个方面:

    1. Redis采用非阻塞式I/O模型,通过设置非阻塞套接字(non-blocking socket)来实现异步的I/O操作。这样当一个客户端连接有数据到达时,Redis可以立即进行读取操作,而不会被阻塞等待数据到达。
    2. Redis使用I/O多路复用机制来同时监听多个客户端连接的事件。通过使用系统调用(如epoll、select、kqueue等),Redis可以将多个套接字注册到事件循环中,并在有事件发生时及时做出相应的处理。
    3. 当有新的客户端连接建立或已有的连接有数据到达时,Redis的事件循环会触发相应的事件,并调用相应的回调函数来处理。例如,当有新的连接建立时,会调用accept()函数来接受客户端连接;当客户端有数据到达时,会调用read()函数来读取数据。
    4. Redis使用事件驱动的方式处理客户端请求,将任务交给相应的工作线程进行处理。通过事件循环和线程池的结合,Redis可以高效地处理大量的并发客户端请求,并且保持较低的系统资源消耗。
      通过采用I/O多路复用机制,Redis能够高效地处理大量的并发客户端请求,提高系统的吞吐量和响应速度。
      但Redis的其他功能,比如持久化、异步删除、集群数据同步等等,实际是由额外的线程执行的。

    5. 虚拟内存机制

    内存数据库系统,但它也提供了一种虚拟内存机制,允许将数据持久化到磁盘而不仅仅存储在内存中。
    虚拟内存机制允许Redis将部分数据从内存中移动到磁盘上,以便处理大于物理内存的数据集。这对于处理大型数据集的情况非常有用,但需要谨慎使用,因为虚拟内存可能导致性能下降。以下是一些关于Redis虚拟内存的关键要点:

    1. 虚拟内存配置:Redis的虚拟内存可以通过配置文件中的vm-enabled参数启用或禁用。默认情况下,虚拟内存是禁用的。

    2. 虚拟内存限制:你可以配置Redis的虚拟内存限制,即vm-max-memory参数,来指定Redis可以使用的虚拟内存的最大大小。当达到这个限制时,Redis会将一些不常用的数据移到磁盘上,以腾出更多的内存。

    3. 数据分页:Redis的虚拟内存将数据分为不同的页(pages),每个页的大小由vm-page-size参数定义。这些页存储在磁盘上,根据数据的访问频率进行移动。

    4. 数据置换策略:Redis使用一种称为"页置换"的策略来决定哪些数据会被移动到磁盘上。常见的策略包括LRU(最近最少使用)和LFU(最不常使用)。

    5. 警告和性能影响:使用虚拟内存时,需要注意性能问题。频繁的数据移动和磁盘访问可能会导致性能下降。Redis会在达到一定的内存使用阈值时发出警告,以提醒你。

    6. 数据持久化:与传统的Redis内存数据库不同,虚拟内存Redis在磁盘上存储数据,因此不需要单独的持久化选项。数据将在Redis服务器重新启动时从磁盘加载到内存中。

    实现原理

    内存机制的实现原理可以简要概括如下:

    1. 数据分页:Redis将数据分成固定大小的页面(pages),每个页面的大小由vm-page-size参数定义。这些页面存储在磁盘上,并根据需要进行加载和卸载。

    2. 内存映射:Redis使用内存映射(memory mapping)技术来管理虚拟内存。它会将磁盘上的页面映射到进程的地址空间中,这使得可以像访问内存一样访问磁盘上的数据。

    3. 页置换策略:Redis使用一种页面置换策略来决定哪些数据页应该从内存中移动到磁盘上,以便腾出内存空间。常见的策略包括LRU(最近最少使用)和LFU(最不常使用),可以通过配置文件中的vm-max-policy参数进行选择。

    4. 内存管理:Redis会维护一个内存使用情况的统计信息,以了解哪些数据页需要被置换到磁盘上。当内存使用接近虚拟内存限制时,Redis会启动虚拟内存机制,将一些不常用的页面移动到磁盘上,以释放内存。

    5. 持久化:虚拟内存中的数据页也会被持久化到磁盘上,以便在Redis服务器重新启动时能够恢复数据。这是通过Redis的RDB快照机制来完成的。
      需要注意的是,虚拟内存机制在Redis中并不是主要的工作模式,而是一种辅助的机制,用于处理大型数据集。在实践中,虚拟内存通常需要谨慎配置,以避免性能下降。通常情况下,更好的方法是根据实际需求适当地分片数据,或者使用更大的物理内存来容纳数据集,以获得更好的性能。虚拟内存通常用于处理数据集过大,无法完全加载到内存的特殊情况。

  • 相关阅读:
    docker 使用数据库mysql
    【Spring】Spring事务失效原因及解决方法
    Air780E模块休眠控制应用指南
    2022安洵杯babybf
    PHP 同城服务共享茶室小程序系统是如何实现的?
    (一)使用Mybatis实现在student数据库中插入一个学生信息
    LeetCode142.环形链表-II
    [Linux]----文件系统
    最新基于R语言lavaan结构方程模型(SEM)技术
    【必知必会】手把手教你配置MySQL环境变量——图文详解
  • 原文地址:https://blog.csdn.net/m0_51663233/article/details/133786716