redis 6.0多线程核心代码分析

Redis核心设计原理(深入底层C源码) 1. 非关系型的键值对数据库,可以根据键以O(1) 的时间复杂度取出或插入关联值  2. Redis 的数据是存在内存中的  3. 键值对中键的类型可以是字符串,整型,浮点型等,且键是唯一的  4. 键值对中的值类型可以是string,hash,list,set,sorted set 等  5. Redis 内置了复制,磁盘持久化,LUA脚本,事务,SSL, ACLs,客户端缓存,客户端代理等功能  6. 通过Redis哨兵和Redis Cluster 模式提供高可用性。这些都是可以通过配置调整的。 阅读详情

第一部分,主流程分析

1.main
1.1 initServer 事件处理器
1.2 InitServerLast  
1.2.1 initThreadedIO 创建io子线程, 注意这里的

    /* Spawn and initialize the I/O threads. */
    for (int i = 0; i < server.io_threads_num; i++) {
        /* Things we do for all the threads including the main thread. */
        io_threads_list[i] = listCreate();
        if (i == 0) continue; /* Thread 0 is the main thread. */

        /* Things we do only for the additional threads. */
        pthread_t tid;
        pthread_mutex_init(&io_threads_mutex[i],NULL);
        io_threads_pending[i] = 0;
        pthread_mutex_lock(&io_threads_mutex[i]); /* Thread will be stopped. */
        if (pthread_create(&tid,NULL,IOThreadMain,(void*)(long)i) != 0) {
            serverLog(LL_WARNING,"Fatal: Can't initialize IO thread.");
            exit(1);
        }
        io_threads[i] = tid;
    }


1.2.2  注意这里创建子线程时的处理,在index=0时,直接continue,猜测这里是为了保持在conf文件中配置的线程数就是总的线程数,而不是io线程数,index为0的就是当前线程,即主线程

2.主循环   beforeSleep
3.事件beforeSleep中   handleClientsWithPendingReadsUsingThreads
3.1 server.clients_pending_read轮转分配到N个io_threads_list队列中

    /* Distribute the clients across N different lists. */
    listIter li;
    listNode *ln;
    listRewind(server.clients_pending_read,&li);
    int item_id = 0;
    while((ln = listNext(&li))) {
        client *c = listNodeValue(ln);
        int target_id = item_id % server.io_threads_num;
        listAddNodeTail(io_threads_list[target_id],c);
        item_id++;
    }

3.2 主线程  通过将原子开关io_threads_op置位为IO_THREADS_OP_READ,开启各个io线程的读操作,然后主线程处理自己的io_threads_list[0],并通过原子开关io_threads_pending来启动io子线程

    /* Give the start condition to the waiting threads, by setting the
     * start condition atomic var. */
    io_threads_op = IO_THREADS_OP_READ;
    for (int j = 1; j < server.io_threads_num; j++) {
        int count = listLength(io_threads_list[j]);
        io_threads_pending[j] = count;
    }

3.3 主线程  自旋检测所有ios线程的处理队列对否都已清空

    /* Wait for all the other threads to end their work. */
    while(1) {
        unsigned long pending = 0;
        for (int j = 1; j < server.io_threads_num; j++)
            pending += io_threads_pending[j];
        if (pending == 0) break;
    }

3.4 主线程  在db中查询client上来的读请求

3.5 io子线程  IOThreadMain 自旋等待,通过原子开关 io_threads_pending 来判断

    while(1) {
        /* Wait for start */
        for (int j = 0; j < 1000000; j++) {
            if (io_threads_pending[id] != 0) break;
        }

        /* Give the main thread a chance to stop this thread. */
        if (io_threads_pending[id] == 0) {
            pthread_mutex_lock(&io_threads_mutex[id]);
            pthread_mutex_unlock(&io_threads_mutex[id]);
            continue;
        }

3.6 io子线程  通过原子开关io_threads_pending和io_threads_op启动客户端请求的解析和查询结果的返回

        listIter li;
        listNode *ln;
        listRewind(io_threads_list[id],&li);
        while((ln = listNext(&li))) {
            client *c = listNodeValue(ln);
            if (io_threads_op == IO_THREADS_OP_WRITE) {
                writeToClient(c,0);
            } else if (io_threads_op == IO_THREADS_OP_READ) {
                readQueryFromClient(c->conn);
            } else {
                serverPanic("io_threads_op value is unknown");
            }
        }
        listEmpty(io_threads_list[id]);
        io_threads_pending[id] = 0;

4.事件beforeSleep中   handleClientsWithPendingWritesUsingThreads, 具体策略类似读操作的io多线程处理

第二部分,关键模块分析

1.readQueryFromClient(connection *conn)

1.1  在多线程模式下会启用postponeClientRead

1.1.1 postponeClientRead, 如果client还没有被加入到server.clients_pending_read队列中,则加入这个全局队列,设置client的CLIENT_PENDING_READ状态,放到下一轮的多线程处理读请求的时候再处理

int postponeClientRead(client *c) {
    if (io_threads_active &&
        server.io_threads_do_reads &&
        !ProcessingEventsWhileBlocked &&
        !(c->flags & (CLIENT_MASTER|CLIENT_SLAVE|CLIENT_PENDING_READ)))
    {
        c->flags |= CLIENT_PENDING_READ;
        listAddNodeHead(server.clients_pending_read,c);
        return 1;
    } else {
        return 0;
    }
}

1.1.2  如果一个client在一个时间片内被加入到了server.clients_pending_read,那么不会被加入第二次, 这样可以保证一个时间片内,不管cleint有多少次请求,都会被同一个io thread处理完,不会存在client的多个请求被分散在多个io thread中导致的数据不一致问题

1.2  在单线程模式下或者client已经在CLIENT_PENDING_READ状态下, 直接解析读请求,查询db

第三部分 总结

redis多线程的核心思想,就是不改动之前的db处理部分,只对前阶段的网络请求解析和后阶段的网络回包做多线程处理,按照作者的说法,前后两部分才是耗时大户。


 

【Redis】 - Redis 6.0 新特性之多线程模型 在执行命令阶段:Redis是单线程来执行命令的,每一条到达读服务端的命令并不会立即执行,所有的命令都会进入一个 socket 任务队列中,当 socket 可读则交给单线程事件分发器逐个被执行,即一个线程处理所有网络请求。如下图所示:从Redis 4.0 以后并不是严格意义上的单线程,除了主线程外,Redis 也有后台线程或子进程处理一些其他较为缓慢的操作(例如:无用连接的释放、慢IO访问和一些其他类似操作 - 清理脏数据、生成快照、AOF重写等)。 阅读详情

相关推荐

redis目前所有的源代码

redis目前所有的源代码 redis目前所有的源代码

Redis 6.0 源码阅读笔记(5)-List 数据类型源码分析

文章目录1. 存储的结构2. 数据存储源码分析 1. 存储的结构 redis 对于 List 的存储共有 3 种存储形式,其中 OBJ_ENCODING_LINKEDLIST已经彻底废弃不再讨论,其它两种存储形式的内存结构如下图示例: OBJ_ENCODING_ZIPLIST:底层结构类似数组,使用特定属性保存整个列表的元信息,如整个列表占用的内存大小,列表保存的数据开始的位置,列表保存的数据的个数等,其保存的数据被封装在 zlentry zlentry 是压缩列表保存数据的节点,其结构与 zipli

谈谈1974 967

退火朗之万动力学采样

退火朗之万动力学采样(Simulated Annealing Langevin Dynamics Sampling)结合了退火技术和朗之万动力学,是一种用于分子模拟和统计物理中的计算方法。这种方法可以帮助系统从局部最小值中逃逸,以找到全局最小值或进行有效的配置空间探索。

weixin_39699362的博客 1949

Redis多线程IO源码分析-第一篇

io_threads_list是一个数组,数组中的每一个元素是一个list,里面存储每个线程要处理的客户端列表,下标为0的元素也就是io_threads_lis[0]存储的是主线程要处理的客户端列表,这里先调用listCreate创建列表,为io_threads_list[i]初始化。2. 对server.io_threads_num的值进行判断,io_threads_num表示配置文件中设置的IO线程数量。,之后将线程保存在io_threads中,io_threads数组存储了创建的线程描述符。

papaya的博客 258

图形学基础|基于SDF的卡通阴影图

图形学基础|基于SDF的卡通阴影图 文章目录图形学基础|基于SDF的卡通阴影图一、前言二、SDF(Signed Distance Field)三、阴影图生成3.1 SDF生成3.2 插值参考博文 一、前言 回顾之前做的卡通渲染,角色面部阴影是靠一张阴影贴图实现的。 为了更好地控制角色的脸部阴影,通过计算脸部朝向与光照方向的夹角和一张单色的FaceMap来判断。 FaceMap的每个像素表示:该像素判断为阴影时候需要达到的夹角。 例如: 当方向光正对角色的时候,夹角为0°,对应的值为0,此时,FaceMap

【黑键】 1万+

Oracle数据库安装及配置(Oracle19c)

Windows 10安装Oracle 19c教程

weixin_69200200的博客 2万+

Redis核心原理解析-(源码)

Redis数据结构 1.Redis基本数据类型 redis基本数据类型有如下5种: 类型 底层数据结构 String 简单动态字符串 Hash 哈希表、压缩列表 List 双向链表、压缩列表 Sorted Set 跳表、压缩列表 Set 整数数组、哈希表 既然redis是key/value存储,那这里的类型肯定说的是value。 2.Redis健值结构 redis健值的存储结构是什么(注意和value区别)? 答:redis的k/v使用的是一张全局哈希表,每次根据ke

by_ron的专栏 3099

C300 | 5680t | 新格林| AN5516 | 远程ONU升级指导

ONU的远程管理升级 1、ZTE C300 OLT : 1.1 环境拓扑: PC1(filezilla server)------(uplink_default-vlanID)OLT---------ONU | | mng1 1.2 配置部署: 1):PC1(filezilla server): IP:192.168.88.252 255.255.255.0 配置FTP-Server的用户名:gp...

Shelly的博客 3770

Redis6.0的多IO线程

Redis6.0的多IO线程 通过上篇文章的学习,我们知道 Redis server 启动后的进程会以单线程的方式,执行客户端请求解析和处理工作。但是,Redis server 也会通过 bioInit 函数启动三个后台线程,来处理后台任务。也就是说,Redis 不再让主线程执行一些耗时操作,比如同步写、删除等,而是交给后台线程异步完成,从而避免了对主线程的阻塞。 实际上,在 2020 年 5 月推出的 Redis 6.0 版本中,Redis 在执行模型中还进一步使用了多线程来处理 IO 任务,这样设计的目

子冉冰清的博客 1358

Mac Studio M5 Ultra本地部署大模型实战:从内存原理到Ollama开发工作流

大模型推理的性能瓶颈往往不在算力,而在于内存能否装下整个模型、带宽能否持续供得上。Transformer架构每生成一个token都需要把权重完整扫一遍,决定了这本质上是内存密集型任务——统一内存架构因此成为本地部署的关键通路,超大容量与高带宽并行,让“装得下”和“跑得快”同时成立。模型量化技术(如Q4_K_M)则是另一项决定性软件策略,用轻微精度损失换取更低的硬件门槛,也是Ollama本地部署从7B到70B各类模型必做的前置功课。当本地推理服务跑起来后,借助VS Code等开发工具的OpenAI兼容API接

weixin_29043895的博客 450

LabVIEW调用.so文件的方法

LabVIEW调用.so文件的方法

m0_37878912的博客 3024

redis系列,redis6.0多线程解密!

文章目录前言io 多线程初识io多线程的读:io多线程的写:多线程io的配置详细注释io 多线程深入io多线程的初始化io多线程的处理io多线程的触发和停止总结 前言 redis 6.0推出,听大家谈论得最多就是redis 变成多线程了,这到底是怎么回事,本文会给你全网最详细的多线程讲解,从多线程初始化,到多线程是如何应用,以及你该如何去配置多线程,本文会给出最详细的讲解。 io 多线程初识 redis 多线程指的是redis 6.0的io 多线程特性,为了避免歧义,首先得说在redis6.0之前并..

偷懒程序员小彭的博客 2201

Python全栈入门到实战【AI实战篇 01】DeepSeek官方API全流程实战,第一个AI项目前置必备

文章摘要 本文介绍了基于DeepSeek API开发智能助手的前期准备和基础调用流程。内容涵盖: 前期准备:访问DeepSeek官网、完成账号注册与实名认证。 API Key获取:充值并创建API Key,强调密钥安全保存的重要性。 查阅文档:定位官方接口文档中的Python调用示例。 环境配置:安装openai依赖包,配置环境变量存储API Key。 代码编写:使用Python调用DeepSeek API实现基础对话功能。 调试与验证:解决常见问题,确保API调用成功。 适合零基础开发者跟随操作,快速入门

那些看似不起波澜的日复一日,会在某天让你看到坚持的意义 3734

Redis 6.0多线程

Redis 6.0多线程 前段时间无意间看到一篇博客,讲述了Redis6即将在年底发布的事情,好奇心驱动下搜索了官网,想看看新版Redis带来了什么新的功能,果然得到证实Redis在年底将发布新的版本:6.0,并且Redis创始人兼核心开发者 antirez 在博客也介绍了将在6.0所提供的新功能 ACL用户权限控制功能 RESP3:新的 Redis 通信协议 Cluster 管理工具 SSL 支持 IO多线程支持 新的Module API 新的 Expire 算法等 具体可以参考相关资料(http://a

lizhengze1117的博客 4984

【学习系列】SAP RAP 16:RAP应用部署集成至Fiori Launchpad 【On-Premise】

本文详细介绍了如何将开发完成的RAP应用部署到S4HANA 2023 On-Premise环境并集成到Fiori Launchpad的完整流程。主要内容包括:1)通过ADT工具创建Fiori项目并配置外部IDE(VSCode);2)使用npm命令部署应用到系统;3)通过事务代码创建语义对象、磁贴目录和目标映射;4)配置PFCG角色分配;5)补充了部署失败解决方案、翻译问题处理、自定义主题设置以及登录页面LOGO修改等内容。文章提供了step-by-step的操作指南,帮助开发者将预览模式的应用正式部署到生产

DeveloperMrMeng的博客 635

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

正式支持多线程!Redis 6.0与老版性能对比评测

导读:Redis 6.0将在今年年底发布,其中引入的最重大的改变就是多线程IO。本文作者深入阅读并解析了关键代码,并且做了基准测试,揭示多线程 IO 特性对Redis性能...

weixin_45583158的博客 2619

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Redis 6.0 源码阅读笔记(2)-Redis 多线程原理

文章目录前言1. Redis 多线程模型2. Redis 多线程源码分析2.1 IO 线程的初始化2.2 IO 线程的启动2.3 IO 线程处理读任务的流程 前言 Redis 6.0 中一个重大的改变就是引入了多线程IO。我们都知道 Redis 基于内存操作,几乎不存在 CPU 成为瓶颈的情况, 它主要受限于内存和网络。从 Redis 自身角度来说,读写网络的 read/write 系统调用占用了 Redis 执行期间大部分 CPU 时间,瓶颈其实主要在于网络的 IO 消耗。基于这种情况,Redis 优化

谈谈1974 3357

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【Redis】Redis6.0新特性与多线程模型(Redis专栏启动)

Redis6.0中增加了很多新特性,比如多线程处理网络 IO(Threaded I/O)、客户端缓存(Client side caching)、Redis集群代理(Cluster proxy)、ACL细粒度权限管控(包括ACL LOG),以及一些内核优化……最值得注意的是多线程I/O和客户端缓存,也是本文中间讲解的内容。

小明的Java问道之路 3408

Redis的6.0以上为啥又支持多线程

引入多线程后的 Redis 6.0 通过将数据操作保持在单线程中、使用锁和原子操作、细粒度锁、无锁设计等多种方式来解决并发带来的线程安全问题。这种设计既能提升性能,又能保证数据的一致性和安全性。

hikktn的博客 1417

redis6.0 IO的多线程

Redis 6.0 引入的多线程机制主要是为了优化网络 I/O 性能,但核心的命令处理仍然是单线程的。”的混合模型,通过分工提升吞吐量,同时保持核心逻辑的线程安全性。Redis 6.0 的多线程是“

2402_82958989的博客 1129

【Redis深度专题】「技术提升」探索Redis 6.0为何必须启用多线程以提升性能与效率

在Redis 6.0版本中,引入了多线程技术,这是为了进一步提高Redis的性能和并发处理能力。通过启用多线程,Redis能够同时处理多个客户端请求,有效地利用多核处理器资源,提高系统的吞吐量和响应速度。开启多线程可以在处理阻塞操作时提供更好的性能,例如慢查询、持久化操作等。此外,多线程还能够更好地应对高并发的情况,减少请求的排队等待时间,提高系统的响应能力。Redis 引入了多线程机制,但主要的数据处理和查询请求处理仍然是基于单线程的。

世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程。 1846

Redis 6.0引入的多线程机制简介

简单介绍了Redis 6.0的多线程模型。

终生学习践行者 2640

Redis重大版本整理(Redis2.6-Redis7.0)

Redis借鉴了Linux操做系统对于版本号的命名规则:node 版本号第二位若是是奇数,则为非稳定版本(例如2.7、2.9、3.1),若是是偶数,则为稳定版本(例如2.6、2.8、3.0、3.2)。 当前奇数版本就是下一个稳定版本的开发版本,例如2.9版本是3.0版本的开发版本,因此咱们在生产环境一般选取偶数版本的Redis。 下面是重大版本新功能的归纳: Redis6.0 多线程 IO(Threaded I/O) 众多新模块(modules)API 更好的过期循环(expire cycle) 支持SS

耕云者~ 1万+

redis面试:redis 6.0 多线程的实现机制

Redis官方在 2020 年 5 月正式推出 6.0 版本,提供很多振奋人心的新特性,所以备受关注。其主要特性如下: 多线程处理网络IO 客户端缓存 细粒度权限控制(ACL); RESP3协议的使用 用于复制的RDB文件不再有用,将立即被删除 RDB 文件加载速度更快; redis6.0之前为什么不使用多线程 使用redis时,几乎不存在CPU成为瓶颈的情况,redis主要受限于内存和网络 在一个普通的linux系统上,redis通过使用pipelining每秒可以处理100万个请求,所以如果应

OceanStar的博客 2500

Redis为什么在6.0之后变成了多线程

在 Java 开发当中,我们用到的关于缓存使用的比较较多的就是 Redis,而关于 Redis 的面试题,也是我们在面试的过程中,会经常性的被问到,比如,Redis 为什么这么快,Redis存储的数据结构等等之类的面试题,而最近,又出现了新的内容,那就是 Redis 中的多线程。

Wewe的博客 1103
上一篇: bat脚本中if子句的errorlevel,一个大坑
下一篇: php中的pb搜索所有子结构的方法
cleanfield
博客等级 码龄21年 126粉丝 189原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值