天道酬勤

天下事有难易乎?为之,则难者亦易矣;不为,则易者亦难矣。

0%

# Redis配置文件

# 启用AOF持久化
appendonly yes

# 当AOF文件增长 100% 时重写AOF文件
auto-aof-rewrite-percentage 100

# 当AOF文件大于 64M 时重写AOF文件
auto-aof-rewrite-min-size 64mb
阅读全文 »

Redis Serialization ProtocolRESP)是Redis客户端服务器之间使用的通信协议。它是一种简单、高效的文本协议,易于实现和解析。

阅读全文 »

有一个常见的问题,Redis是如何实现高可用的?

(1) 如何实现高可用

在分布式环境中,有可能出现某台机器挂了,为了保障高可用,首先要提高服务的分区容错性,一般都会通过冗余来实现。

Redis主从是冗余的一种体现。

Redis的高可用是通过主从哨兵来保障的。在主库挂了以后,哨兵可以把流量切到从库,让从库顶上去,来保障服务可用。

那就有一个问题了,顶上去的从库的数据和主库数据一样吗?还有Redis是如何实现主从数据同步的?


(2) Redis主从数据同步

Redis多个副本(主库和从库)之间的数据如何保持一致呢?
数据读写操作可以发给所有的实例吗?

(2.1) 新增数据是如何保存到Redis副本

Redis是通过读写分离的方式,通过主从库模式来保障多个副本数据一致。 (MySQL、Kafka也是类似)

为什么要采用读写分离的方式呢?
set key v1
set key v2

如果允许所有副本接收写操作(新增 修改 删除),数据在这多个副本可能就不一致了(分别是 v1 和 v2)。

如果必须保障新增的数据在多个副本上一致,就要涉及到加锁实例间协商是否完成修改等一系列操作,但这会带来巨额的开销,当然是不太能接受的。

阅读全文 »

在2020年5月推出的 Redis 6.0 版本中,Redis 在执行模型中使用了多线程来处理 IO 任务,这样是为了充分利用当前服务器的多核特性,使用多核运行多线程,让多线程帮助加速数据读取、命令解析以及数据写回的速度,提升 Redis 整体性能。

那么,这些多线程具体是在什么时候启动,又是通过什么方式来处理 IO 请求的呢?

(1) IO多线程

Redis里的IO多线程是指Redis Server读取客户端请求或者向客户端写数据时,使用多个线程,利用CPU资源,加快整体读写速度。

阅读全文 »

无论是 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 操作)的特征
可以在一个数据类型中,同时高效支持范围查询和单点查询,这是单一索引结构比较难达到的效果。

阅读全文 »