4.网络设计与redis、memcached、nginx组件(二)

简介: 4.网络设计与redis、memcached、nginx组件(二)

系列文章目录


第四章 网络设计与redis、memcached、nginx组件(一)

第五章 网络设计与redis、memcached、nginx组件(二)


前言


此文章主要是是介绍一下reactor 模型和典型的reactor模型开源软件介绍分析。


一、reactor模型?


Reactor 模型的核心就是把对网络IO的处理转变成对事件的处理。 把网络IO检测功能交由IO多路复用(epoll  select poll)实现检测fd 状态,针对时间的处理进行IO操作,不同职能事件通过不同的事件函数处理。

IO多路复用的主要功能是检测多条链路的状态(可读 可写 错误 断开等),但不具备具体IO操作的功能(比如读写数据)。IO多路复用都是同步网络IO ,常见的IO多路复用器有select、poll,epoll,他们是对IO的管理,检测接入的IO,触发IO事件;注意这三个都是同步IO。


241f055795c6d88613d535160a6b642b_e71f57bf41594d87a2cec0da6fa36749.png


之所以把IO就绪检测的功能交由IO多路复用器,是因为对于服务端而言,某一时刻只有少量的连接有数据交互,如果让IO函数自己检测,在阻塞IO时,每个连接都需要一个线程;非阻塞IO时,每个连接都需要通过while在应用层进行检测。


二、Reactor 开发


1.建立连接

代码如下(示例):

//1.服务端作为被动建立连接
// listenfd 注册监听listenfd 的事件
struct epoll_event  ev;
ev.events = EPOLLIN;
ev.date.fd = listenfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
// 触发listenfd 的读事件,调用accept 接受新的连接
clientfd = accept(listen_fd,(struct sockaddr *)&addr, sizeof(addr))
ev.events = EPOLLIN;
ev.date.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_ADD,clientfd, &ev);
.//服务端主动
// 1. 创建 socket 建立连接
int connectfd = socket(AF_INET, SOCK_STREAM, 0);
connect(connectfd, (struct sockaddr *)&addr,
sizeof(addr));
// 2. 注册监听 connectfd 的写事件
struct epoll_event ev;
ev.events = EPOLLOUT;
ev.data.fd = connetfd
epoll_ctl(efd, EPOLL_CTL_ADD, connectfd, &ev);
// 3. 当 connectfd 写事件被触发,连接建立成功
if (status == e_connecting && e->events &
EPOLLOUT) {
status == e_connected;
// 这里需要把写事件关闭
epoll_ctl(epfd, EPOLL_CTL_DEL, connectfd,
NULL);
}


三、典型reactor 模型


单reactor 模型


典型 readis

redis命令行采用了单reactor 网络事件模型,在启动时会创建一个I/O多路复用的事件处理器(即reactor)用于监听链路的状态,然后将所有客户端请求都注册到该事件处理器中。当有新连接到达或者已有连接有数据可读写时,事件处理器就会触发相应的回调函数进行处理。


由于redis是单线程运行的,因此只需要一个reactor即可满足其并发处理需求。通过合理地利用CPU资源和异步非阻塞IO技术,redis可以实现高效地处理大量并发请求。


radis 中优化

需要注意的是,当Redis遇到某些长时间执行的命令时,可能会导致其他请求被阻塞而影响整个系统性能。比如三个客户端同时向服务端发送数据,服务端是按先后顺序接收处理。这种就会出现如果先到的数据处理比较耗时,会导致后续客户端出现饥饿现象。优化方式是:

1、如果IO耗时,把IO操作放到IO线程池处理,主线程处理computer。read 、write、encode 、decode等丢入线程池处理

2、如果computer耗时,采用分治思想或者不同时间复杂度的算法


多reactor 模型 多线程(one eventloop per thread)

模型图


典型 memcached

memcached是一个基于事件驱动的内存缓存服务器,它使用多个reactor来处理并发连接。开启多个线程,每个线程中都有一个独立的reactor 对象。


为什么支持多线程 多reactor

memcached 也是kv类型的数据库,但是value 支持数据结构比较单一不支持多种数据结构, 对于锁的处理比较简单。


具体来说,memcached使用一个主线程和多个工作线程。每个工作线程都有自己的reactor,用于处理客户端连接和请求。当有新连接到达时,主线程(master epoll )会将新的fd分配给某个工作线程,并且该工作线程的reactor会负责处理这个连接的所有事件。


多reactor 模型 多进程 (one eventloop per process)

模型


典型引用 nginx

nginx是一个基于事件驱动的服务器,它通过多个reactor处理并发连接,它采用多进程的方式(master、slave worker)模型


具体来说,Nginx使用一个主进程(master)和多个worker进程。每个worker进程都有自己的reactor队形,用于处理客户端连接和请求。当有新连接到达时,主进程会将其分配给某个worker进程,并且该worker进程的reactor会负责处理这个连接的所有事件。


在默认情况下,Nginx的worker进程数等于CPU核心数。


nginx流程

Master process 创建的时候会监听listenfd, 然后在fork 出work 进程, work 进程当中都会有一个listenfd 的备份。每个work 进程会创建自己的epoll 对象。并且把listenfd交割epoll 对象管理. 多个进程都监听了listenfd 的读事件,如果listenfd 的全链接队列当中,加入节点的时候,他就会给每一个epoll 对象发送信号,每个epoll 对象都会去触发读事件。这样就产生了惊群现象。在用户层解决这个问题,通过在work 进程当中添加共享锁的方式解决。


总结


单线程单reactor模型,典型是radis 可以把IO放入线程池,也可以把业务计算部分放入线程池。通过回调的方式处理

多线程多reactor模型 如果业务之间交互比较多,但加锁简单,可以用多线程memcached

多进程多reactor模型 如果业务之间交互比较少,可以用多进程ngnix

本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对c/c++linux课程感兴趣的读者,可以点击链接,详细查看详细的服务器课程

目录
相关文章
|
网络协议 算法 Java
基于Reactor模型的高性能网络库之Tcpserver组件-上层调度器
TcpServer 是一个用于管理 TCP 连接的类,包含成员变量如事件循环(EventLoop)、连接池(ConnectionMap)和回调函数等。其主要功能包括监听新连接、设置线程池、启动服务器及处理连接事件。通过 Acceptor 接收新连接,并使用轮询算法将连接分配给子事件循环(subloop)进行读写操作。调用链从 start() 开始,经由线程池启动和 Acceptor 监听,最终由 TcpConnection 管理具体连接的事件处理。
374 2
基于Reactor模型的高性能网络库之Tcpconnection组件
TcpConnection 由 subLoop 管理 connfd,负责处理具体连接。它封装了连接套接字,通过 Channel 监听可读、可写、关闭、错误等
315 1
|
NoSQL 安全 Java
深入理解 RedisConnectionFactory:Spring Data Redis 的核心组件
在 Spring Data Redis 中,`RedisConnectionFactory` 是核心组件,负责创建和管理与 Redis 的连接。它支持单机、集群及哨兵等多种模式,为上层组件(如 `RedisTemplate`)提供连接抽象。Spring 提供了 Lettuce 和 Jedis 两种主要实现,其中 Lettuce 因其线程安全和高性能特性被广泛推荐。通过手动配置或 Spring Boot 自动化配置,开发者可轻松集成 Redis,提升应用性能与扩展性。本文深入解析其作用、实现方式及常见问题解决方法,助你高效使用 Redis。
1450 4
基于Reactor模型的高性能网络库之Poller(EpollPoller)组件
封装底层 I/O 多路复用机制(如 epoll)的抽象类 Poller,提供统一接口支持多种实现。Poller 是一个抽象基类,定义了 Channel 管理、事件收集等核心功能,并与 EventLoop 绑定。其子类 EPollPoller 实现了基于 epoll 的具体操作,包括事件等待、Channel 更新和删除等。通过工厂方法可创建默认的 Poller 实例,实现多态调用。
498 60
基于Reactor模型的高性能网络库之Channel组件篇
Channel 是事件通道,它绑定某个文件描述符 fd,注册感兴趣的事件(如读/写),并在事件发生时分发给对应的回调函数。
539 60
|
安全 调度
基于Reactor模型的高性能网络库之核心调度器:EventLoop组件
它负责:监听事件(如 I/O 可读写、定时器)、分发事件、执行回调、管理事件源 Channel 等。
516 57
|
缓存 索引
基于Reactor模式的高性能网络库之缓冲区Buffer组件
Buffer 类用于处理 Socket I/O 缓存,负责数据读取、写入及内存管理。通过预分配空间和索引优化,减少内存拷贝与系统调用,提高网络通信效率,适用于 Reactor 模型中的异步非阻塞 IO 处理。
371 3
高性能网络库设计之日志组件
高性能网络库设计之日志组件
309 2
|
11月前
|
运维 监控 安全
计算机网络及其安全组件纲要
本文主要介绍了 “计算机网络及常见组件” 的基本概念,涵盖网卡、IP、MAC、OSI模型、路由器、交换机、防火墙、WAF、IDS、IPS、域名、HTTP、HTTPS、网络拓扑等内容。
491 0
|
安全 Java 程序员
分析Muduo网络库源码中的TcpServer组件工作原理
简言之,TcpServer 在 Muduo 中的角色,就是一位终极交通指挥员,它利用现代计算机网络的魔法,确保数据如同车辆一般,在信息高速公路上自由、安全、高效地流动。
170 0