1.redis源码解读(一):事件驱动的编译io模型,为什么,源译r源码是码编什么,怎么做
2.Redis 时报源码剖析 3 -- redisCommand
3.Redis源码解析:一条Redis命令是如何执行的?
4.redis7.0源码阅读:Redis中的IO多线程(线程池)
5.Redis系列(一)-安装配置
6.windows下cygwin编译redis 6.2.6源码教程,再也不用担心没有高版本redis版本了(附win版本)
redis源码解读(一):事件驱动的编译io模型,为什么,源译r源码网易云爬虫源码代源码是码编什么,怎么做
Redis作为一个高性能的时报内存数据库,因其出色的编译读写性能和丰富的数据结构支持,已成为互联网应用不可或缺的源译r源码中间件之一。阅读其源码,码编可以了解其内部针对高性能和分布式做的时报种种设计,包括但不限于reactor模型(单线程处理大量网络连接),编译定时任务的源译r源码实现(面试常问),分布式CAP BASE理论的码编实际应用,高效的数据结构的实现,其次还能够通过大神的代码学习C语言的编码风格和技巧,让自己的代码更加优雅。
下面进入正题:为什么需要事件驱动的io模型
我们可以简单地将一个服务端程序拆成三部分,接受请求->处理请求->返回结果,其中接收请求和处理请求便是我们常说的网络io。那么网络io如何实现呢,首先我们介绍最基础的io模型,同步阻塞式io,也是很多同学在学校所学的“网络编程”。
使用同步阻塞式io的单线程服务端程序处理请求大致有以下几个步骤
其中3,4步都有可能使线程阻塞(6也会可能阻塞,这里先不讨论)
在第3步,如果没有客户端请求和服务端建立连接,那么服务端线程将会阻塞。如果redis采用这种io模型,那主线程就无法执行一些定时任务,比如过期key的清理,持久化操作,集群操作等。
在第4步,如果客户端已经建立连接但是没有发送数据,服务端线程会阻塞。若说第3步所提到的定时任务还可以通过多开两个线程来实现,那么第4步的阻塞就是硬伤了,如果一个客户端建立了连接但是一直不发送数据,服务端便会崩溃,无法处理其他任何请求。所以同步阻塞式io肯定是不能满足互联网领域高并发的需求的。
下面给出一个阻塞式io的服务端程序示例:
刚才提到,阻塞式io的主要问题是,调用recv接收客户端请求时会导致线程阻塞,无法处理其他客户端请求。那么我们不难想到,既然调用recv会使线程阻塞,那么我们多开几个几个线程不就好了,让那些没有阻塞的线程去处理其他客户端的请求。
我们将阻塞式io处理请求的步骤改造下:
改造后,我们用一个线程去做accept,也就是获取已经建立的连接,我们称这个线程为主线程。然后获取到的手淘js源码每个连接开一个新的线程去处理,这样就能够将阻塞的部分放到新的线程,达到不阻塞主线程的目的,主线程仍然可以继续接收其他客户端的连接并开新的线程去处理。这个方案对高并发服务器来说是一个可行的方案,此外我们还可以使用线程池等手段来继续优化,减少线程建立和销毁的开销。
将阻塞式io改为多线程io:
我们刚才提到多线程可以解决并发问题,然而redis6.0之前使用的是单线程来处理,之所以用单线程,官方给的答复是redis的瓶颈不在cpu,既然不在cpu那么用单线程可以降低系统的复杂度,避免线程同步等问题。如何在一个线程中非阻塞地处理多个socket,进而实现多个客户端的并发处理呢,那就要借助io多路复用了。
io多路复用是操作系统提供的另一种io机制,这种机制可以实现在一个线程中监控多个socket,返回可读或可写的socket,当一个socket可读或可写时再去操作它,这样就避免了对某个socket的阻塞等待。
将多线程io改为io多路复用:
什么是事件驱动的io模型(Reactor)
这里只讨论redis用到的单线程Reactor模型
事件驱动的io模型并不是一个具体的调用,而是高并发服务器的一种抽象的编程模式。
在Reactor模型中,有三种事件:
与这三种事件对应的,有三种handler,负责处理对应的事件。我们在一个主循环中不断判断是否有事件到来(一般通过io多路复用获取事件),有事件到来就调用对应的handler去处理时间。
听着玄乎,实际上也就这一张图:
事件驱动的io模型在redis中的实现
以下提及的源码版本为 5.0.8
文字的苍白的,建议参照本文最后的方法下载代码,自己调试下
整体框架
redis-server的main方法在 src/server.c 最后,在main方法中,首先进行一系列的初始化操作,最后进入进入Reactor模型的主循环中:
主循环在aeMain函数中,aeMain函数传入的参数 server.el ,是一个 aeEventLoop 类型的全局变量,保存了主循环的一些状态信息,包括需要处理的读写事件、时间事件列表,epoll相关信息,回调函数等。
aeMain函数中,我们可以看到当 eventLoop->stop 标志位为0时,while循环中的内容会被重复执行,每次循环首先会调用beforesleep回调函数,然后处理时间。beforesleep函数在main函数中被注册,会进行集群状态更新、AOF落盘等任务。
之所以叫beforesleep,是因为aeProcessEvents函数中包含了获取事件和处理事件的逻辑,其中获取读写事件时通过epoll_wait实现,会将线程阻塞。
在aeProcessEvents函数中,东方财富bbi源码处理读写事件和时间事件,参数flags定义了需要处理的事件类型,我们可以暂时忽略这个参数,认为读写时间都需要处理。
aeProcessEvents函数的逻辑可以分为三个部分,首先获取距离最近的时间事件,这一步的目的是为了确定epoll_wait的超时时间,并不是实际处理时间事件。
第二个部分为获取读写事件并处理,首先调用epoll_wait,获取需要处理的读写事件,超时时间为第一步确定的时间,也就是说,如果在超时时间内有读写事件到来,那么处理读写时间,如果没有读写时间就阻塞到下一个时间事件到来,去处理时间事件。
第三个部分为处理时间事件。
事件注册与获取
上面我们讲了整体框架,了解了主循环的大致流程。接下来我们来看其中的细节,首先是读写事件的注册与获取。
redis将读、写、连接事件用结构aeFileEvent表示,因为这些事件都是通过epoll_wait获取的。
事件的具体类型通过mask标志位来区分。aeFileEvent还保存了事件处理的回调函数指针(rfileProc、wfileProc)和需要读写的数据指针(clientData)。
既然读写事件是通过epoll io多路复用实现,那么就避不开epoll的三部曲 epoll_create epoll_ctrl epoll_wait,接下来我们看下redis对epoll接口的封装。
我们之前提到aeMain函数的参数是一个 aeEventLoop 类型的全局变量,aeEventLoop中保存了epoll文件描述符和epoll事件。在aeApiCreate函数(src/ae_epoll.c)中,会调用epoll_create来创建初始化epoll文件描述符和epoll事件,调用关系为 main -> initServer -> aeCreateEventLoop -> aeApiCreate
调用epoll_create创建epoll后,就可以添加需要监控的文件描述符了,需要监控的情形有三个,一是监控新的客户端连接连接请求,二是监控客户端发送指令,也就是读事件,三是监控客户端写事件,也就是处理完了请求写回结果。
这三种情形在redis中被抽象为文件事件,文件事件通过函数aeCreateFileEvent(src/ae.c)添加,添加一个文件事件主要包含三个步骤,通过epoll_ctl添加监控的文件描述符,指定回调函数和指定读写缓冲区。
最后是通过epoll_wait来获取事件,上文我们提到,在每次主循环中,首先根据最近到达的时间事件来计算epoll_wait的超时时间,然后调用epoll_wait获取事件,再处理事件,糖果丘比特源码其中获取事件在函数aeApiPoll(src/ae_epoll.c)中。
获取到事件后,主循环中会逐个调用事件的回调函数来处理事件。
读写事件的实现
写累了,有空补上……
如何使用vscode调试redis源码
编译出二进制程序
这一步有可能报错:
jemalloc是内存分配的一种更高效的实现,用于代替libc的默认实现。这里报错找不到jemalloc,我们只需要将其替换成libc默认实现就好:
如果报错:
我们可以在src目录找到一个脚本名为mkreleasehdr.sh,其中包含创建release.h的逻辑,将报错信息网上翻可以发现有一行:
看来是这个脚本没有执行权限,导致release.h没有成功创建,我们需要给这个脚本添加执行权限然后重新编译:
2. 创建调试配置(vscode)
创建文件 .vscode/launch.json,并填入以下内容:
然后就可以进入调试页面打断点调试了,main函数在 src/server.c
Redis 源码剖析 3 -- redisCommand
Redis 使用 redisCommand 结构体处理命令请求,其内包含一个指向对应处理函数的 proc 指针。redisCommandTable 是一个存储所有 Redis 命令的数组,位于 server.c 文件中。此数组通过 populateCommandTable() 函数填充,该函数将 redisCommandTable 的内容添加到 server.commands 字典,将 Redis 支持的所有命令及其实现整合。
populateCommandTable() 函数中包含 populateCommandTableParseFlags() 子函数,用于将 sflags 字符串转换为对应的 flags 值。lookupCommand*() 函数族负责从 server.commands 中查找相应的命令。
Redis源码解析:一条Redis命令是如何执行的?
作者:robinhzhang Redis,一个开源内存数据库,凭借其高效能和广泛应用,如缓存、消息队列和会话存储,本文将带你探索其命令执行的底层流程。本文将以源码解析的形式,逐层深入Redis的核心结构和命令执行过程,旨在帮助开发者理解实现细节,提升编程技术和设计意识。源码结构概览
在学习Redis源代码之前,首先要了解其主要的组成部分:redisServer、redisClient、redisDb、redisObject以及aeEventLoop。这些结构体和事件模型构成了Redis的核心架构。redisServer:服务端运行的核心结构,包括监听socket、数据存储的redisDb列表和客户端连接信息。
redisClient:客户端连接状态的存储,包括命令处理缓冲区、回复数据列表和数据库句柄。
redisDb:键值对的数据存储,采用两个哈希表实现渐进式rehash。
redisObject:存储对象的通用表示,包含引用计数和LRU时间,用于内存管理。
aeEventLoop:事件循环,管理文件和时间事件的处理。
核心流程详解
Redis的执行流程从main函数开始,首先初始化配置和服务器组件,进入主循环处理事件。怎么获取外挂源码命令执行流程涉及redis启动、客户端连接、接收命令和返回结果四个步骤:启动阶段:创建socket服务器,注册可读事件,进入主循环。
连接阶段:客户端连接后,接收并处理命令,创建客户端实例。
命令阶段:客户端发送命令,服务端解析并调用对应的命令处理函数。
结果阶段:处理命令后,根据协议格式构建回复并写回客户端。
渐进式rehash与内存管理
Redis的内存管理采用引用计数法,通过对象的refcount字段控制内存分配和释放。rehash操作在Redis 2.x版本引入,通过逐步迁移键值对,降低对单线程性能的影响。当负载达到阈值,会进行扩容,这涉及新表的创建和键值对的迁移。总结
本文通过Redis源码分析,揭示了其命令执行的细节,包括启动流程、客户端连接、命令处理和结果返回,以及内存管理策略。这将有助于开发者深入理解Redis的工作原理,提升编程效率和设计决策能力。redis7.0源码阅读:Redis中的IO多线程(线程池)
Redis服务端处理客户端请求时,采用单线程模型执行逻辑操作,然而读取和写入数据的操作则可在IO多线程模型中进行。在Redis中,命令执行发生在单线程环境中,而数据的读取与写入则通过线程池进行。一个命令从客户端接收,解码成具体命令,根据该命令生成结果后编码并回传至客户端。 Redis配置文件redis.conf中可设置开启IO多线程。通过设置`io-threads-do-reads yes`开启多线程,同时配置`io-threads 2`来创建两个线程,其中一个是主线程,另一个为IO线程。在网络处理文件networking.c中,`stopThreadedIOIfNeeded`函数会判断当前需要执行的命令数是否超过线程数,若少于线程数,则不开启多线程模式,便于调试。 要进入IO多线程模式,运行redis-server命令,然后在调试界面设置断点在networking.c的`readQueryFromClient`函数中。使用redis-cli输入命令时,可以观察到两个线程在运行,一个为主线程,另一个为IO线程。 相关视频推荐帮助理解线程池在Redis中的应用,包括手写线程池及线程池在后端开发中的实际应用。学习资源包括C/C++ Linux服务器开发、后台架构师技术等领域,需要相关资料可加入交流群获取免费分享。 在Redis中,IO线程池实现中,主要包括以下步骤:读取任务的处理通过`postponeClientRead`函数,判断是否启用IO多线程模式,将任务加入到待执行任务队列。
主线程执行`postponeClientRead`函数,将待读客户端任务加入到读取任务队列。在多线程模式下,任务被添加至队列中,由IO线程后续执行。
多线程读取IO任务`handleClientsWithPendingReadsUsingThreads`通过解析协议进行数据读取,与写入任务的多线程处理机制相似。
多线程写入IO任务`handleClientsWithPendingWritesUsingThreads`包括判断是否需要启动IO多线程、负载均衡分配任务到不同IO线程、启动IO子线程执行写入操作、等待IO线程完成写入任务等步骤。负载均衡通过将任务队列中的任务均匀分配至不同的线程消费队列中,实现无锁化操作。
线程调度部分包含开启和关闭IO线程的功能。在`startThreadedIO`中,每个IO线程持有锁,若主线程释放锁,线程开始工作,IO线程标识设置为活跃状态。而在`stopThreadedIO`中,若主线程获取锁,则IO线程等待并停止,IO线程标识设置为非活跃状态。Redis系列(一)-安装配置
Redis是一个高性能的键值数据库,具备如下特点:
1. 高性能:Redis以极高的速度提供数据读写服务,适用于要求实时性高的应用。
2. 支持数据持久化:可将内存中的数据保存至磁盘中,确保重启后数据不丢失。
安装配置Redis步骤如下:
1. 访问Redis官网下载Linux安装包。
2. 选择源码或二进制包,此例下载源码包。
3. 解压文件,进入解压目录。
4. 安装依赖环境gcc-c++,查看安装版本。
5. 编译源码,执行make命令。
6. 执行make install命令,根据需要自定义安装路径。
7. 启动服务,执行./redis-server命令。
8. 复制并修改配置文件redis.conf至/etc/redis.conf,设置为自启动。
9. 启动服务并测试。
. 查看Redis服务进程。
. 使用redis-cli客户端进行操作。
. 测试ping命令验证连接。
. 关闭服务,执行redis-cli shutdown命令。
. 远程连接设置,修改redis.conf文件,取消protected-mode设置,修改bind选项或设置密码。
完成以上步骤后,即可开始Redis的使用。
windows下cygwin编译redis 6.2.6源码教程,再也不用担心没有高版本redis版本了(附win版本)
现在redis已升级至6.2.6版本,市面上大多提供的是Linux下的编译版本,然而在Windows环境下搜索到的大多是3.x和4.x版本,由于官方已停止提供Windows版本,因此编译最新版本成为唯一选择。本文将指导您使用cygwin在Windows环境下编译生成高版本的redis,以下是具体步骤:
首先,您需要下载最新版本的redis源码,下载路径和密码请见“redis源码版本”。
接下来,安装cygwin,可参考“cygwin下载及安装详细教程”。完成安装后,您需要对cygwin的/usr/include目录下dlfcn.h文件进行特定修改,确保编译过程顺利进行。
下载并解压redis压缩文件,将其放置于cygwin的home目录下,home目录是您登录时自动生成的用户名目录。
打开cygwin界面,检查当前位置是否为您的home目录,并确认redis解压后的目录。
执行cd进入redis的deps目录,执行make命令生成指定依赖库。
回到上级目录并执行make命令,如果第1步的修改正确,此时只会出现警告信息,无需理会。
完成make后,执行make install命令将生成的可执行文件安装至指定位置。
进入src目录,查看生成的exe文件,这些就是您编译好的redis相关文件。
将生成的exe文件、依赖库文件以及cygwin1.dll一同复制至Windows目录。
在当前目录输入cmd,执行redis-server.exe以启动redis服务,验证版本信息。
使用redis-cli.exe客户端进行操作,设置并获取值,验证安装成功。
如需简化操作,可直接下载作者提供的编译好的Windows版本redis。
完成以上步骤后,您将成功在Windows环境下编译并安装redis高版本。若对本文内容有所启发,请给予小小的赞以支持。
编译实战 | 手摸手教你在Windows环境下运行Redis6.x
哈喽大家好啊,我是没事就愿意瞎捣鼓的Hydra。
不知道有没有小伙伴像我一样,平常开发中用的是windows操作系统,有时候想装点什么软件,一看只支持linux系统,无奈要么启动虚拟机、要么装在云服务器上。
这不前几天又是这样,刚想用一下Redis 6.x版本来尝试一下新特性,打开官网一看,好家伙我直呼内行,果然不支持windows系统:
不过虽然redis的官网上不提供windows版本下载,但是这也难不倒我这个面向百度编程的小能手,一番查找后让我找到了微软在github上维护的几个可以在windows上运行的redis版本:
项目的git地址是/MicrosoftArchive/redis/releases,我翻了一下,微软维护了2.x和3.x的多个windows版本redis,不过比较遗憾,在维护到3.0.正式版本后就放弃了更新。
不过问题不大,眼看微软撂挑子不干了,波兰的热心市民 Tomasz Poradowski 先生这时候站出来,继续开始提供可以在windows上运行的4.x和5.x版本的redis,并且从年到年一干就是5年。
项目git地址是/tporadowski/redis/releases,没错,其实我本地环境运行的redis-5.0.9就是以前从这里下载的,而且绿色版使用起来真的是干净又卫生,所以我强烈建议大家给这位老哥来一个Star支持一下。
不过绕了这么一大圈,我的问题还是没有解决啊,既然没有现成的可以在windows上运行的redis6.x版本,那我们干脆就来自己编译一个吧。
首先介绍一下我们今天要用到的工具Cygwin,先简单看一下它的官网 /,上面很清晰的解释了几个容易引起大家混淆的问题:
先解释了cygwin是什么:
再纠正了大家的常见误区:
其实可以用一句话来概括一下它的功能,cygwin是一个可运行于原生windows系统上的POSIX兼容环境,可以通过重新编译将linux应用移植到windows中。
好了,这样简单了解一下cygwin的功能对我们来说暂时就足够了,下面我们看看如何使用它来编译windows版本redis。
下面我们先进行编译工具Cygwin的下载和安装,在它的官网上就可以直接下载,完成后就可以开始安装了。下面我会贴出一些需要特殊配置的步骤,如果没有特殊说明的话,那么直接痛快的点击下一步就可以了。
网络连接配置这里选择第二项,也就是直接连接,不需要任何代理方式:
在选择下载源这一步,先手动输入User URL,添加阿里云的镜像/cygwin,点击add后再选择我们刚才添加的这个源,然后点击下一步:
接下来选择需要下载安装的组件包,我们只需要下载我们编译相关的模块即可。先通过上面的搜索框进行定位,选择安装Devel模块下面的make、gcc-core,gcc-g++,以及Libs模块下的libgcc1 、libgccpp1,然后点击New这一列的Skip,选择要安装的版本号,全部添加完成后点击下一步:
接下来会自动进行下载上面选择的模块,等待全部下载结束后安装就完成了:
安装完成后,我们运行Cygwin Terminal,通过命令检测可以看到Status为OK,表示cygwin运行正常:
准备好编译工具后,我们接下来先下载redis6.x版本的源码,6.0.的下载地址为:
download.redis.io/relea...
cygwin安装完成后,会在它的安装路径的home目录下,创建一个以你登录系统的用户名来命名的目录,我们把下载完成后的压缩包放到这个cygwin\home\${ user}目录下,在cygwin命令行中先执行解压命令:
使用下面的命令先切换到解压后的根目录,然后执行编译和安装:
点击回车,然后就开始漫长的等待吧,不得不说编译和安装的过程真的很慢,我这大概花了分钟才全部完成。
不出意外的最后果然出现了意外,报了两个Error,不过貌似没有什么太大影响,切换到src目录下,就已经可以看到编译完成后已经生成了6个exe可执行文件了:
但是如果这个时候双击redis-server.exe尝试进行启动的话,那么就会报错提示缺少dll动态链接库:
我们可以在cygwin的bin目录下找到这个文件,为了方便,把可执行文件、动态链接库文件、redis配置文件拷贝到一个单独的目录下再次尝试启动:
这次能够正常启动成功,我们再使用客户端连接工具连接并进行测试,终于,6.0.版本的redis可以在windows环境下正常运行了。
忙活一大顿总算成功了,我们也终于可以在windows上体验redis6.x版本了,不过这里还是给小伙伴们提个醒,这样编译的redis我们平常自己在学习中体验一下就可以了,尽量不要用在生产上。
因为cygwin编译后的程序,相当于在windows系统上模拟实现了POSIX兼容层,应用程序在底层多了一层函数调用,因此效率比运行在linux系统的原生应用低了很多。因此,这样在windows上运行的redis,无疑会损失掉它引以为傲的高性能这一优势。
秉持着好东西就要分享的原则,我也已经把编译好的windows版redis6.0.上传到了网盘,有需要的小伙伴们可以从下面获取下载方式。
那么,这次的分享就到这里,我是Hydra,下期见。
作者简介,码农参上,一个热爱分享的公众号,有趣、深入、直接,与你聊聊技术。个人微信DrHydra9,欢迎添加好友,进一步交流。
php-8.3.3 源码编译安装以及扩展 redis 、gd和 sodium安装
本文主要记录如何安装PHP 8.3.3版本及其扩展,包括Redis、GD、和Sodium。本教程适合寻求实现最新PHP技术的开发者。
首先,使用阿里云购买配置为4c8G的Rocky Linux 9.3机器用于安装。
开始安装前,进行系统版本的确认和软件包的更新。
然后利用源码方式编译安装PHP 8.3.3版本。在此过程中,需先安装必要的依赖包。
接着,创建www用户用于权限管理。
下载并解压PHP 8.3.3的源码。
运行configure预编译,可能遇到诸如“无法找到ldap.h”或“无法识别ldap库在/usr/lib”等问题,需排查这些依赖问题。
通过访问pkgs.org网站搜索缺失的 oniguruma-devel 包进行安装。注意在搜索到的页面找到oniguruma-devel的安装入口,有时可能需要通过验证。
正确安装依赖后,再次编译,进行make操作。完成编译后,创建php的软链接至系统中。
优化PHP默认配置,并创建php-fpm进程管理脚本。
下一步是安装PHP的扩展。例如,对于Redis、GD和Sodium的扩展。
确保正确安装扩展后,进行验证,确保所有配置都正确实现。
如果希望深入理解安装细节或遇到问题,可以查找更多相关教程或咨询社区成员。
在本教程中,提供了一条基于源码的安装PHP 8.3.3及其扩展的方法,并且避免了一些常见的复杂安装步骤。此方法适合追求高效且全面掌握PHP配置与安装细节的开发者。