天道酬勤

坚持,努力,让好事发生

无论是 LRU 算法还是 LFU 算法,它们在删除淘汰数据时,实际上都会根据 Redis server 的 lazyfree-lazy-eviction 配置项,来决定是否使用 Lazy Free,也就是惰性删除。

(1) 惰性删除是什么

惰性删除是 Redis 4.0 版本后提供的功能,它会使用后台线程来执行删除数据的任务

(2) 为什么要用惰性删除

可以避免了删除操作对主线程的阻塞。

阅读全文 »

Redis的执行模型,是指 Redis 运行时使用的进程、子进程和线程的个数,以及它们各自负责的工作任务。

我们经常会听到一个问题: Redis 到底是不是一个单线程的程序?

先来看 Redis server 启动时的进程运行。

(1) Redis进程创建

在启动 Redis 实例时

./redis-server ../redis.conf

这个命令后,它实际会调用fork系统调用函数,最终会调用Redis Servermain函数,来新建一个进程。
运行 Redis server 后,我们会看到 Redis server 启动后的日志输出会打印到终端屏幕上

阅读全文 »

经常会遇到这样一道问题:Redis的网络框架是实现了 Reactor 模型吗?

(1) Reactor模型是什么

Reactor模型是网络服务器端用来处理高并发网络IO请求的一种编程模型。

Reactor模型

Reactor的核心思想:Reactor模式 也叫 Dispatcher 模式,将关注的IO事件注册到多路复用器上,一旦有IO事件触发,将事件分发到事件处理器中,执行就绪IO事件对应的处理函数中。

阅读全文 »

(1) Stream是什么

Redis 从 5.0 版本开始支持提供 Stream 数据类型,它可以用来保存消息数据,能帮助我们实现一个带有消息读写基本功能的消息队列,并用于日常的分布式程序通信当中。

(1.1) Stream 消息数据的特征

Stream 作为消息队列,它保存的消息通常具有以下两个特征:

一条消息由一个或多个键值对组成;
每插入一条消息,这条消息都会对应一个消息 ID。

一般会让 Redis 服务器自动生成递增的消息 ID。此时,消息 ID 由时间戳和序号组成。其中,时间戳是消息插入时,以毫秒为单位的服务器当时时间,序号是插入消息在当前毫秒内的序号。

阅读全文 »

Redis整体架构

Redis是典型的 Client-Server 架构,类似于MySQL和RPC框架。
Redis Server类似于RPC框架Server,在客户端使用前需要先启动Redis Server。那么有一个问题,Redis Server启动后会做哪些操作?需要哪些配置,有没有什么坑?

(1) Redis Server启动入口-main函数

源码地址 https://github.com/redis/redis/blob/6.0/src/server.c

//file: src/server.c

// #L5297  5297行
int main(int argc, char **argv) {

    // 1. 初始化配置 设置默认值
    initServerConfig();

    /* We need to init sentinel right now as parsing the configuration file
     * in sentinel mode will have the effect of populating the sentinel
     * data structures with master nodes to monitor. */
    // 2. 判断server是否设置为哨兵模式 
    if (server.sentinel_mode) {
        initSentinelConfig();
        // 初始化哨兵
        initSentinel();
    }

    /* Check if we need to start in redis-check-rdb/aof mode. We just execute
     * the program main. However the program is part of the Redis executable
     * so that we can easily execute an RDB check on loading errors. */
    // 3. 持久化 rdb aof  
    if (strstr(argv[0],"redis-check-rdb") != NULL)
        redis_check_rdb_main(argc,argv,NULL);
    else if (strstr(argv[0],"redis-check-aof") != NULL)
        redis_check_aof_main(argc,argv);

    // 4. 加载Server配置 
    loadServerConfig(configfile,options);

    // 5. 启动RedisServer时 初始化配置及资源
    initServer();

    // 6. 循环处理请求及事件,直到服务器关闭为止
    aeMain(server.el); 

}
阅读全文 »

有序集合(Sorted Set)是Redis中的一种对象,它本身是集合类型,同时也可以支持集合中的元素带有权重,并按权重排序。

(1) 有序集合(Sorted Set)是什么

/*
 * ZSET 是有序集合,使用两个数据结构来保存相同的元素,以便将 O(log(N)) INSERT 和 REMOVE 操作放入已排序的数据结构中。
 * 
 * 这些元素被添加到将 Redis 对象映射到分数的哈希表中。
 * 同时,将元素添加到将分数映射到 Redis 对象的跳跃列表(因此对象在此“视图”中按分数排序)。
 *
 * 请注意,为了节省内存,表示元素的 SDS 字符串在哈希表和跳表中都是相同的。 
 * 为了更容易地管理共享的 SDS 字符串,我们所做的是仅在 zslFreeNode() 中释放 SDS 字符串。 
 * 字典没有设置无值方法。
 * 所以我们应该总是从字典中删除一个元素,然后再从跳过列表中删除。
 */

(1.1) 有序集合结构

/*
 * 有序集合 zset 结构体
 */
typedef struct zset {
    dict *dict; // 字典
    zskiplist *zsl; // 跳表
} zset;

Sorted Set 同时采用跳表哈希表两个索引结构
利用了跳表高效支持范围查询(如 ZRANGEBYSCORE 操作),以及哈希表高效支持单点查询(如 ZSCORE 操作)的特征
可以在一个数据类型中,同时高效支持范围查询和单点查询,这是单一索引结构比较难达到的效果。

阅读全文 »

跳表是一种数据结构,不过奇怪的是大学时数据结构的课本上没有介绍过这种数据结构,但最近几年在实际工作时又经常接触到。
跳表可以支持快速地插入、删除、查找操作,写起来也不复杂,甚至可以替代红黑树(Red-black tree)。

(1) 跳表

跳表

(1.1) 跳表介绍

我理解跳表是加了索引的链表。

对于一个单链表来讲,即便链表中存储的数据是有序的,如果我们要想在其中查找某个数据,也只能从头到尾遍历链表。这样查找效率就会很低,时间复杂度会很高,是 O(n)。
单链表

那怎么来提高查找效率呢?如果像图中那样,对链表建立一级“索引”,查找起来是不是就会更快一些呢?
加了索引的链表

阅读全文 »

(1) 双向链表是什么

生活中的双向链表

链表是一种物理存储单元上非连续非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

双向链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。

双向链表

所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。

阅读全文 »

Redis3.2版本使用 quicklist 代替了 ziplistlinkedlist.

(1) 快速列表(quicklist)是什么

快速列表(quicklist)是 (压缩列表)ziplist 的 双向链表。

A generic doubly linked quicklist implementation .

快速列表

快速列表(quicklist)是把压缩列表(ziplist)和双向链表结合起来。
每个双链表节点中保存一个ziplist,然后每个ziplist中存一批list中的数据(具体ziplist大小可配置),这样既可以避免大量链表指针带来的内存消耗,也可以避免ziplist更新导致的大量性能损耗。

阅读全文 »

Redis的set对象里用到了整数集合(intset)

(1) 整数集合是什么

整数集合(intset)类似于数组,但同时有有序无重复的特点,并且可以根据元素的值,自动选择整数类型来保存元素。

整数集合里的元素 类型一样(整数类型都是int16/int32/int64),里面的值不重复
相比于数组,增加了自动编码转换的功能。

阅读全文 »
0%