深入了解Redis线程工作模式(redis线程工作模式)

深入了解Redis线程工作模式

Redis作为一种高性能的key-value存储系统,无疑成为了热门技术之一。Redis快速处理大量数据的能力取决于其高效的线程工作模式。本文将深入了解Redis的线程工作模式,以便更好的理解Redis的内部工作原理。

Redis的线程模型

Redis从2.8版本开始,采用了多线程方式实现I/O多路复用,用于处理并发连接请求。Redis线程数默认为cpu核心数量。其中,主线程被用于处理客户端的连接和协议解析,以及同步的I/O操作。工作线程负责处理异步的 I/O 操作(如文件事件),并执行在key空间中定义的命令。下图是Redis多线程架构示意图:

![redis_thread_model](https://img-blog.csdn.net/20181108174349768?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xsbDIwMTg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/q/70)

如上图所示,Redis主线程接收客户端请求,同时与工作线程协作处理I/O读写。工作线程也处理Redis持久化操作和其他底层任务。Redis线程模型的优点是减少锁竞争,在高并发下性能得到强力保障。

Redis的I/O模型

Redis使用了epoll进行I/O多路复用,以实现高并发读写。epoll采取了边缘触发(EPOLLET)的方式,只有当文件描述符状态发生变化时,内核才会通知应用程序。

Redis采用epoll的ET模式以减少CPU上下文切换,处理过程简单,效率高,并且避免了遗漏的文件描述符事件。ET模式需要确保读取或写入的缓存区,都应该被完整的处理一遍。因此,当Redis请求的大小超过系统默认的缓冲区大小时,redis在异步读取/写入时,需要进行多次的读写操作,以确保缓冲区文本被完整地读出/写入。以下是Redis ET读写实现过程的示意图:

![redis_io_model](https://img-blog.csdn.net/20181109170412156?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xsbDIwMTg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/q/70)

Redis的AOF持久化模式

Redis主要支持两种持久化方式:RDB和AOF。不过本文只讨论AOF持久化策略,它也是Redis使用最多的一种策略。AOF的写操作可能会卡住主进程,从而影响性能。为了降低写操作的影响,Redis容器采取了异步AOF持久化模式,即BGREWRITEAOF(后台重写)。该模式通过生成新的AOF文件,然后将其追加到原AOF文件中。该过程在后台完成,不会阻塞Redis的主工作线程。以下为Redis AOF持久化模式示意图:

![redis_aof_model](https://img-blog.csdn.net/20181109171553263?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xsbDIwMTg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/q/70)

从上图中可以看出,Redis将不太重要的任务交给了工作线程,并将I/O操作异步化,以避免重要任务的阻塞。同时,Redis采取了异步AOF持久化模式,以减轻写操作所产生的性能影响。Redis的线程工作模式十分高效,可接受高并发请求,具有出色的稳定性和高可用性。

本文示例代码:

// 1. mn thread

aeMn()

{

// 等待事件

aeApiPoll();

// …

// 接收到 read 命令后

if (socket_read_pending()) {

// 将命令交给工作线程执行

worker_pool.schedule(read_handler, socket_fd);

}

// …

// 在工作线程中处理异步 I/O 请求

worker_pool.run_io_threads();

// …

}

// 2. 工作线程

void run_io_threads()

{

// 利用 poll() 函数进入等待就绪的状态

// 和 poll() 函数类似,这里我们用自己封装的 async_poll() 函数

while(true){

// 处理正在执行的 IO 请求

process_io_requests();

// 查询当前是否有需要执行的操作

if (async_poll(thread_read_fds)) {

// 执行每个客户端的命令

process_read_commands();

// 执行文件事件

process_disk_events();

}

// 执行 Redis 的一些常规操作

process_checkpointing();

process_timers();

process_scroll();

}

}

// 3. 异步 AOF 备份操作

void bg_rewrite_aof()

{

// 创建新文件

aof_file = open(“redis.aof.new”, O_CREAT | O_RDWR, S_IRWXU);

// …

// 异步写入

while(true) {

append_to_file(io_buffer, io_size);

// 写入速度过快

if (a_socket_send_buffer_full()) {

// 等待套接字写空

a_socket_send_wt_until_unblock();

}

// 压缩并移动文件

compress_and_transfer_approved_files();

}

}

// 4. Redis 的多线程模块

class WorkerPool {

public:

// 从工作队列中取出 worker 开始执行

void run_worker(Worker& worker) {

pthread_create(worker.tid, NULL, worker.worker_routine, (void*)&tpool);

}

};

int mn() {

WorkerPool tp;

Worker* threads[THREAD_NUM];

for (int i = 0; i

threads[i].tid = i;

threads[i].worker_routine = worker_routine;

tp.run_worker(threads[i]);

}

}


数据运维技术 » 深入了解Redis线程工作模式(redis线程工作模式)