C++实现主从Reactor模型实现高并发服务器面试题总结

目录

  • [1. 项目架构概述](#1. 项目架构概述)
    • [1.1 介绍一下你这个高并发服务器项目](#1.1 介绍一下你这个高并发服务器项目)
    • [1.2 请详细解释什么是Reactor模型?为什么选择主从Reactor模式而不是单Reactor模式?](#1.2 请详细解释什么是Reactor模型?为什么选择主从Reactor模式而不是单Reactor模式?)
    • [1.3 解释"One Thread One Loop"的设计思想及其优势](#1.3 解释"One Thread One Loop"的设计思想及其优势)
    • [1.4 为什么将服务器组件和应用层协议支持分离设计?](#1.4 为什么将服务器组件和应用层协议支持分离设计?)
  • [2. 核心组件实现细节](#2. 核心组件实现细节)
    • [2.1 Buffer模块为什么使用vector而不是固定数组?如何实现高效的数据管理?](#2.1 Buffer模块为什么使用vector而不是固定数组?如何实现高效的数据管理?)
    • [2.2 Channel、Poller、EventLoop三者之间的关系是怎样的?](#2.2 Channel、Poller、EventLoop三者之间的关系是怎样的?)
    • [2.3 Connection模块如何管理连接的生命周期?如何处理连接异常?](#2.3 Connection模块如何管理连接的生命周期?如何处理连接异常?)
    • [2.4 定时器模块为什么选择时间轮而不是小根堆?](#2.4 定时器模块为什么选择时间轮而不是小根堆?)
    • [2.5 详细解释时间轮+shared_ptr实现定时刷新机制的原理](#2.5 详细解释时间轮+shared_ptr实现定时刷新机制的原理)
  • [3. 网络编程](#3. 网络编程)
    • [3.1 epoll的LT和ET模式有什么区别?本项目为什么选择LT模式?](#3.1 epoll的LT和ET模式有什么区别?本项目为什么选择LT模式?)
    • [3.2 如何保证非阻塞I/O的正确性?read/write返回0或-1分别表示什么?非阻塞I/O与阻塞I/O的区别是什么?为什么要用非阻塞I/O?](#3.2 如何保证非阻塞I/O的正确性?read/write返回0或-1分别表示什么?非阻塞I/O与阻塞I/O的区别是什么?为什么要用非阻塞I/O?)
    • [3.3 为什么需要忽略SIGPIPE信号?还有什么其他信号需要处理?](#3.3 为什么需要忽略SIGPIPE信号?还有什么其他信号需要处理?)
    • [3.4 eventfd在EventLoop中起什么作用?与pipe相比有什么优势?](#3.4 eventfd在EventLoop中起什么作用?与pipe相比有什么优势?)
    • [3.5 TCP三次握手和四次挥手的过程是什么?在你的服务器中如何体现?](#3.5 TCP三次握手和四次挥手的过程是什么?在你的服务器中如何体现?)
    • [3.6 什么是I/O多路复用?select、poll、epoll有什么区别?](#3.6 什么是I/O多路复用?select、poll、epoll有什么区别?)
  • [4. 多线程与并发控制](#4. 多线程与并发控制)
    • [4.1 如何保证Connection的所有操作都在其绑定的EventLoop线程中执行?](#4.1 如何保证Connection的所有操作都在其绑定的EventLoop线程中执行?)
    • [4.2 EventLoop的任务队列如何实现线程安全?](#4.2 EventLoop的任务队列如何实现线程安全?)
    • [4.3 LoopThreadPool如何分配连接给子Reactor?负载均衡策略是什么?](#4.3 LoopThreadPool如何分配连接给子Reactor?负载均衡策略是什么?)
    • [4.4 多线程环境下如何保证线程安全?](#4.4 多线程环境下如何保证线程安全?)
  • [5. HTTP协议实现](#5. HTTP协议实现)
    • [5.1 HTTP请求解析的状态机设计是如何工作的?](#5.1 HTTP请求解析的状态机设计是如何工作的?)
    • [5.2 如何处理HTTP长连接和短连接?](#5.2 如何处理HTTP长连接和短连接?)
    • [5.3 正则表达式在HTTP路由中起什么作用?性能影响如何?](#5.3 正则表达式在HTTP路由中起什么作用?性能影响如何?)
    • [5.4 HTTP协议的请求和响应格式是什么?](#5.4 HTTP协议的请求和响应格式是什么?)
    • [5.5 如何解析HTTP请求?状态机的作用是什么?](#5.5 如何解析HTTP请求?状态机的作用是什么?)
  • [6. 性能优化与稳定性](#6. 性能优化与稳定性)
    • [6.1 如何避免大量连接时的内存碎片问题?](#6.1 如何避免大量连接时的内存碎片问题?)
    • [6.2 在大文件传输时,如何避免内存占用过大?](#6.2 在大文件传输时,如何避免内存占用过大?)
    • [6.3 业务处理耗时过长导致其他连接超时的问题如何解决?](#6.3 业务处理耗时过长导致其他连接超时的问题如何解决?)
  • [7. 异常处理与稳定性](#7. 异常处理与稳定性)
    • [7.1 服务器如何应对恶意连接或DDoS攻击?](#7.1 服务器如何应对恶意连接或DDoS攻击?)
    • [7.2 如何保证服务器的7x24小时稳定运行?](#7.2 如何保证服务器的7x24小时稳定运行?)
    • [7.3 遇到客户端突然断开连接,服务器如何处理?](#7.3 遇到客户端突然断开连接,服务器如何处理?)
  • [8. 扩展与维护](#8. 扩展与维护)
    • [8.1 如何扩展支持WebSocket协议?](#8.1 如何扩展支持WebSocket协议?)
    • [8.2 如何实现关闭服务器?](#8.2 如何实现关闭服务器?)
  • [9. 综合问题](#9. 综合问题)
    • [9.1 如果让你重新设计这个系统,你会做哪些改进?](#9.1 如果让你重新设计这个系统,你会做哪些改进?)
    • [9.2 这个服务器能支持的最大并发连接数受哪些因素限制?](#9.2 这个服务器能支持的最大并发连接数受哪些因素限制?)
    • [9.3 如何测试服务器的并发性能?需要注意什么?](#9.3 如何测试服务器的并发性能?需要注意什么?)
    • [9.4 如果让你设计一个支持百万并发连接的服务器,你会考虑哪些方面?](#9.4 如果让你设计一个支持百万并发连接的服务器,你会考虑哪些方面?)
    • [9.5 这个项目中你遇到的最大技术挑战是什么?如何解决的?](#9.5 这个项目中你遇到的最大技术挑战是什么?如何解决的?)

1. 项目架构概述

1.1 介绍一下你这个高并发服务器项目

(1)这是一个基于C++11实现的高性能并发服务器框架,模仿了muduo库的"One Thread One Loop"主从Reactor架构。核心特点包括:

  • 采用主从Reactor模型:主Reactor负责接收新连接,子Reactor处理已连接套接字的I/O事件。
  • 实现了完整的TCP服务器组件,包括连接管理、缓冲区、定时器、事件循环等。
  • 支持HTTP应用层协议,可以快速搭建HTTP服务器。
  • 使用epoll实现I/O多路复用,非阻塞I/O,支持高并发连接。
  • 实现了智能指针管理的连接生命周期和超时自动释放机制。

1.2 请详细解释什么是Reactor模型?为什么选择主从Reactor模式而不是单Reactor模式?

  • Reactor模式是一种事件驱动的设计模式,通过一个或多个输入同时传递给服务器的请求处理模式。核心组件包括Reactor(事件分发器)、Handlers(事件处理器)和Acceptor(连接接受器)。
  • 单Reactor单线程无法利用多核CPU,容易达到性能瓶颈;单Reactor多线程虽然可以利用多核,但单个Reactor承担所有事件监听和响应,高并发下容易成为瓶颈。
  • 主从Reactor模式中,主Reactor只负责监听新连接,子Reactor处理已建立连接的I/O事件,实现职责分离,能更好地利用多核CPU,提高并发性能。

1.3 解释"One Thread One Loop"的设计思想及其优势

(1)每个线程运行一个事件循环(EventLoop),该循环负责监控和处理该线程分配的所有描述符的I/O事件。优势如下:

  • 线程隔离:每个连接的所有操作都在同一个线程中完成,避免线程安全问题。
  • 资源高效:减少线程间上下文切换和同步开销。
  • 简化编程模型:开发者无需担心多线程并发问题。
  • 可扩展性:容易增加更多子Reactor线程来处理更多连接。

1.4 为什么将服务器组件和应用层协议支持分离设计?

  • 关注点分离:服务器组件专注于网络I/O、连接管理和事件驱动,协议模块专注于应用层协议解析。
  • 可扩展性:易于支持多种应用层协议(HTTP、WebSocket、RPC等)。
  • 复用性:同一个服务器组件可以支持不同的上层应用。
  • 维护性:协议模块可以独立更新和扩展。

2. 核心组件实现细节

2.1 Buffer模块为什么使用vector而不是固定数组?如何实现高效的数据管理?

(1)优点:

  • 动态扩容:vector可以自动扩容,适应不同大小的数据。
  • 连续内存:保证内存连续性,提高缓存命中率。

(2)实现机制:

  • 维护读偏移(reader_idx)和写偏移(writer_idx)。
  • 提供EnsureWriteSpace保证足够写入空间。
  • 当尾部空间不足时,如果头部有空闲空间,移动数据到头部;否则扩容。
  • 避免频繁的内存分配和拷贝。

2.2 Channel、Poller、EventLoop三者之间的关系是怎样的?

Channel(描述符+事件回调) <--> Poller(epoll封装) <--> EventLoop(事件循环)

  • Channel:封装文件描述符及其感兴趣的事件和回调函数。
  • Poller:对epoll的封装,管理所有Channel的事件监控。
  • EventLoop:事件循环核心,管理Poller和定时器,执行事件回调。
  • 三者协作:Channel通过EventLoop注册到Poller,事件就绪后Poller通知EventLoop,EventLoop调用对应Channel的回调。

2.3 Connection模块如何管理连接的生命周期?如何处理连接异常?

  • 状态管理:使用ConnStatu枚举管理连接状态(DISCONNECTED、CONNECTING、CONNECTED、DISCONNECTING)
  • 异常处理:
    • 读错误:非致命错误(EAGAIN/EINTR)返回0,其他错误触发关闭。
    • 写错误:发送失败触发连接关闭。
    • 连接关闭:处理剩余数据后释放资源。
    • 资源释放:使用shared_ptr引用计数,确保资源正确释放。

2.4 定时器模块为什么选择时间轮而不是小根堆?

(1)时间轮(TimerWheel)优势:

  • O(1)的添加、删除和触发操作。
  • 适合大量定时任务场景。
  • 减少遍历开销,特别适合短时定时任务。

(2)小根堆劣势:

  • O(logN)的添加和删除操作。
  • 每次触发需要调整堆结构。
  • 本项目需求:定时任务通常是短时任务(30秒内),时间轮更合适。

2.5 详细解释时间轮+shared_ptr实现定时刷新机制的原理

(1)核心思想:通过shared_ptr引用计数延迟实际任务执行。

  1. 创建定时任务时,生成shared_ptr< TimerTask >。
  2. 任务添加到时间轮的指定槽位。
  3. 连接活跃时,刷新定时任务:创建新的shared_ptr到新槽位。
  4. 旧槽位触发时,旧shared_ptr析构,但引用计数不为0,不执行任务。
  5. 新shared_ptr在后续槽位触发时才真正执行任务。
  6. 这样实现了"刷新即延迟"的效果。

3. 网络编程

3.1 epoll的LT和ET模式有什么区别?本项目为什么选择LT模式?

(1)LT和ET模式介绍:

  • LT(水平触发):描述符就绪时会持续通知,直到数据处理完。
  • ET(边缘触发):描述符状态变化时只通知一次。

(2)选择LT的原因:

  • 编程简单,不容易遗漏事件。
  • 与阻塞/非阻塞I/O配合更灵活。
  • 本项目Buffer设计可以一次性读取所有数据,避免LT的重复通知问题。
  • 性能考虑:ET理论上更高效,但需要更复杂的缓冲区管理。

3.2 如何保证非阻塞I/O的正确性?read/write返回0或-1分别表示什么?非阻塞I/O与阻塞I/O的区别是什么?为什么要用非阻塞I/O?

(1)非阻塞read:

  • 返回>0:成功读取数据。
  • 返回0:对端关闭连接。
  • 返回-1:检查errno。
  • EAGAIN/EWOULDBLOCK:缓冲区无数据,不是错误。
  • EINTR:被信号中断,应该重试。
  • 其他:真正错误,关闭连接。

(2)非阻塞write:

  • 返回>0:成功写入数据
  • 返回0:表示写了0字节(可能缓冲区满?)
  • 返回-1:错误处理类似read

(3)区别:

  • 阻塞I/O:调用read/write时,如果数据未就绪,线程会一直等待。
  • 非阻塞I/O:调用立即返回,如果数据未就绪,返回错误码(如EAGAIN)。

(4)使用非阻塞I/O的原因:

  • 避免一个慢连接阻塞整个线程。
  • 配合I/O多路复用,实现高并发。
  • 实现真正的异步处理,提高CPU利用率。
  • 避免死锁和线程饥饿问题。

3.3 为什么需要忽略SIGPIPE信号?还有什么其他信号需要处理?

  • SIGPIPE:当向已关闭的连接写数据时,系统会发送SIGPIPE信号,默认行为是终止进程。
  • 忽略SIGPIPE,通过write返回值判断连接状态更可控。
  • 其他可能需要处理的信号:
    • SIGCHLD:处理子进程终止(本项目未使用fork)。
    • SIGALRM:定时器信号(本项目使用timerfd替代)。
    • SIGINT/SIGTERM:优雅关闭服务器。

3.4 eventfd在EventLoop中起什么作用?与pipe相比有什么优势?

(1)作用:唤醒阻塞在epoll_wait上的线程,处理任务队列中的任务。工作机制:

  • 向eventfd写入数据触发可读事件。
  • EventLoop从eventfd读取数据,清空事件。
  • 然后执行任务队列中的任务。

(2)与pipe比较的优势:

  • 更轻量:单一文件描述符,pipe需要两个。
  • 性能更好:内核开销小。
  • 使用简单:专门的eventfd系统调用。

3.5 TCP三次握手和四次挥手的过程是什么?在你的服务器中如何体现?

(1)三次握手:

  • 客户端SYN → 服务器。
  • 服务器SYN+ACK → 客户端。
  • 客户端ACK → 服务器。

(2)四次挥手:

  • 主动方FIN → 被动方。
  • 被动方ACK → 主动方。
  • 被动方FIN → 主动方。
  • 主动方ACK → 被动方。

(3)服务器中的体现:

  • Acceptor处理新连接(三次握手后)。
  • Connection的Shutdown()实现优雅关闭(四次挥手)。
  • 通过EPOLLRDHUP和EPOLLHUP事件检测连接关闭。

3.6 什么是I/O多路复用?select、poll、epoll有什么区别?

(1)I/O多路复用:

  • 一个线程监控多个文件描述符,当某个描述符就绪时进行相应操作。

(2)select、poll、epoll区别对比:

特性 select poll epoll
时间复杂度 O(n) O(n) O(1)
最大连接数 有限制(1024) 无限制 无限制
触发方式 水平触发 水平触发 水平/边缘触发
内核通知 轮询所有fd 轮询所有fd 回调通知
内存拷贝 每次调用都拷贝fd集合 每次调用都拷贝fd集合 使用mmap减少拷贝

4. 多线程与并发控制

4.1 如何保证Connection的所有操作都在其绑定的EventLoop线程中执行?

(1)核心机制:RunInLoop和QueueInLoop。

  1. 每个Connection绑定一个EventLoop。
  2. Connection的操作(Send、Shutdown等)都封装为任务。
  3. 如果当前线程是EventLoop线程,直接执行。
  4. 否则将任务加入EventLoop的任务队列。
  5. 通过eventfd唤醒EventLoop执行任务队列。
  6. 保证线程安全性:操作都在同一个线程执行。

4.2 EventLoop的任务队列如何实现线程安全?

(1)实现要点:

  1. 使用std::mutex保护任务队列。
  2. 添加任务时加锁,加入队列后解锁。
  3. 执行任务时交换队列,减少锁持有时间:
cpp 复制代码
std::vector<Functor> functors;
{
    std::unique_lock<std::mutex> lock(_mutex);
    _tasks.swap(functors);
}
// 执行functors中的任务(已解锁)
  1. 使用eventfd保证及时唤醒

4.3 LoopThreadPool如何分配连接给子Reactor?负载均衡策略是什么?

(1)分配策略:轮询(round-robin)分配。实现方式:

cpp 复制代码
EventLoop *NextLoop() 
{
    if (_thread_count == 0) return _baseloop;
    _next_idx = (_next_idx + 1) % _thread_count;
    return _loops[_next_idx];
}
  • 优点:简单公平,每个子Reactor负载大致均衡。
  • 缺点:没有考虑连接的实际负载情况。

4.4 多线程环境下如何保证线程安全?

  • 连接与线程绑定:每个连接固定在一个EventLoop线程。
  • 任务队列:跨线程操作通过任务队列传递。
  • 锁的使用:
    • 使用std::mutex保护共享数据结构。
    • 使用std::unique_lock和条件变量。
  • 原子操作:简单计数器使用原子类型。
  • 智能指针:使用shared_ptr管理共享资源,自动引用计数。

5. HTTP协议实现

5.1 HTTP请求解析的状态机设计是如何工作的?

(1)状态枚举:

cpp 复制代码
typedef enum {
    RECV_HTTP_LINE,    // 解析请求行
    RECV_HTTP_HEAD,    // 解析请求头
    RECV_HTTP_BODY,    // 解析请求体
    RECV_HTTP_OVER,    // 解析完成
    RECV_HTTP_ERROR    // 解析错误
} HttpRecvStatu;

(2)解析流程:

  1. 初始状态为RECV_HTTP_LINE。
  2. 解析完请求行,状态转为RECV_HTTP_HEAD。
  3. 解析完请求头,状态转为RECV_HTTP_BODY。
  4. 根据Content-Length解析请求体,完成后状态转为RECV_HTTP_OVER。
  5. 任何步骤出错,状态转为RECV_HTTP_ERROR。

5.2 如何处理HTTP长连接和短连接?

(1)判断逻辑:

cpp 复制代码
bool Close() const {
    // Connection头部为"keep-alive"时保持长连接
    if (HasHeader("Connection") && GetHeader("Connection") == "keep-alive") {
        return false;  // 长连接
    }
    return true;  // 短连接
}

(2)处理方式:

  1. 短连接:响应后立即关闭连接。
  2. 长连接:保持连接,继续处理后续请求。
  3. 超时机制:长连接也有超时时间,避免资源泄露。

5.3 正则表达式在HTTP路由中起什么作用?性能影响如何?

(1)作用:

  • 匹配请求路径,实现灵活的路由规则。
  • 示例:匹配/user/123格式。
cpp 复制代码
server.Get("/user/(\\d+)", UserHandler);

(2)性能影响:

  • 正则匹配比简单字符串匹配开销大。
  • 但提供更强大的路由能力。
  • 实际性能影响取决于正则复杂度和请求频率。
  • 优化:常用路由可以缓存匹配结果。

5.4 HTTP协议的请求和响应格式是什么?

(1)HTTP请求格式:

cpp 复制代码
GET /path HTTP/1.1\r\n
Header1: Value1\r\n
Header2: Value2\r\n
\r\n
Body...

(2)HTTP响应格式:

cpp 复制代码
HTTP/1.1 200 OK\r\n
Header1: Value1\r\n
Header2: Value2\r\n
\r\n
Body...

(3)关键点:

  • 请求行/状态行。
  • 头部字段(键值对)。
  • 空行分隔头部和主体。
  • 消息主体。

5.5 如何解析HTTP请求?状态机的作用是什么?

(1)解析步骤:

  • 解析请求行(方法、路径、版本)。
  • 解析请求头(键值对)。
  • 解析请求体(根据Content-Length或Transfer-Encoding)。

(2)状态机的作用:

cpp 复制代码
enum HttpRecvStatu {
    RECV_HTTP_LINE,    // 正在解析请求行
    RECV_HTTP_HEAD,    // 正在解析请求头
    RECV_HTTP_BODY,    // 正在解析请求体
    RECV_HTTP_OVER     // 解析完成
};
  • 跟踪解析进度。
  • 处理不完整请求(数据分多次到达)。
  • 错误恢复和状态重置。

6. 性能优化与稳定性

6.1 如何避免大量连接时的内存碎片问题?

  • Buffer使用vector管理内存,减少小内存分配。
  • Connection使用shared_ptr统一管理,避免内存泄漏。
  • 使用对象池技术(可扩展):预分配Connection对象。
  • 内存池:自定义内存分配器(可优化项)。
  • 避免频繁的new/delete,使用智能指针自动管理。

6.2 在大文件传输时,如何避免内存占用过大?

  • 流式处理:不一次性读取整个文件到内存。
  • 使用sendfile零拷贝技术(可扩展)。
  • 分块传输:设置合适的Buffer大小。
  • 流量控制:监控内存使用,避免OOM。

6.3 业务处理耗时过长导致其他连接超时的问题如何解决?

(1)问题分析:

  1. 业务处理阻塞EventLoop线程。
  2. 导致定时器任务无法及时执行。
  3. 其他连接可能被错误关闭。

(2)解决方案:

  1. 将耗时业务放到工作线程池处理。
  2. EventLoop线程只负责I/O和简单任务。
  3. 工作线程处理完后,通过任务队列返回结果。
  4. 本项目预留了接口,用户可自行实现工作线程池。

7. 异常处理与稳定性

7.1 服务器如何应对恶意连接或DDoS攻击?

  • 连接数限制:单IP最大连接数。
  • 频率限制:请求频率限制。
  • 超时机制:快速释放空闲连接。
  • 资源监控:监控CPU、内存、连接数。
  • 优雅降级:压力大时拒绝新连接。
  • 日志记录:记录异常行为。

7.2 如何保证服务器的7x24小时稳定运行?

  • 资源管理:监控和限制资源使用。
  • 错误恢复:异常捕获和恢复机制。
  • 内存管理:防止内存泄漏和溢出。
  • 日志系统:详细日志便于故障排查。
  • 监控告警:关键指标监控和自动告警。
  • 灰度发布:逐步发布新版本。
  • 压力测试:上线前充分测试。

7.3 遇到客户端突然断开连接,服务器如何处理?

(1)检测机制:

  • read()返回0表示对端关闭。
  • EPOLLRDHUP事件(对端关闭写)。
  • EPOLLHUP事件(连接挂断)。

(2)清理资源:

  • 关闭socket文件描述符。
  • 从epoll中移除监控。
  • 释放Connection对象。
  • 从连接池中移除。

(3)异常处理:

  • 避免向已关闭的连接写数据(SIGPIPE)。
  • 正确处理资源泄漏。

8. 扩展与维护

8.1 如何扩展支持WebSocket协议?

  1. 协议升级:在HTTP握手后升级到WebSocket。
  2. 帧解析:实现WebSocket帧格式解析。
  3. 心跳机制:保持连接活跃。
  4. 集成到现有架构:
    • 创建WebSocketContext类似HttpContext。
    • 在Connection中切换协议处理器。
    • 复用现有的事件驱动框架。

8.2 如何实现关闭服务器?

  • 信号处理:捕获SIGINT/SIGTERM。
  • 停止接受新连接。
  • 等待现有连接处理完成。
  • 逐步关闭所有连接。
  • 清理资源,退出进程。

9. 综合问题

9.1 如果让你重新设计这个系统,你会做哪些改进?

  • 增加工作线程池,分离I/O和业务处理。
  • 支持更丰富的协议(WebSocket、gRPC等)。
  • 改进负载均衡策略,考虑连接活跃度。
  • 增加监控和诊断工具。
  • 优化内存管理,支持内存池。
  • 支持配置热更新。

9.2 这个服务器能支持的最大并发连接数受哪些因素限制?

  • 文件描述符限制(ulimit -n)。
  • 内存限制(每个连接的内存占用)。
  • CPU核心数(线程数优化)。
  • 网络带宽。
  • 操作系统网络栈配置(tcp_max_syn_backlog等)。
  • 应用层协议处理开销。

9.3 如何测试服务器的并发性能?需要注意什么?

  • 测试工具:webbench、wrk、ab等。
  • 测试场景:不同并发数、请求大小、连接保持时间。
  • 监控指标:QPS、响应时间、CPU使用率、内存使用。
  • 注意事项:
    • 测试环境与生产环境一致。
    • 避免测试工具成为瓶颈。
    • 预热阶段和稳定阶段分离。
    • 长时间稳定性测试。

9.4 如果让你设计一个支持百万并发连接的服务器,你会考虑哪些方面?

(1)架构设计:

  • 分布式架构,多机负载均衡。
  • 连接分散到多个进程/机器。

(2)内存优化:

  • 每个连接内存消耗最小化
  • 使用内存池和对象池

(3)CPU优化:

  • CPU亲和性,减少上下文切换
  • 使用RSS(接收端缩放)多队列网卡

(4)网络优化:

  • 使用多端口监听
  • TCP优化(快速打开、窗口缩放)

9.5 这个项目中你遇到的最大技术挑战是什么?如何解决的?

(1)挑战1:定时器刷新和取消的线程安全问题。解决方案:

  • 使用时间轮+shared_ptr,刷新时创建新定时任务。
  • 旧任务shared_ptr计数不为0,不会实际执行。
  • 所有定时器操作都在EventLoop线程执行。
  • 使用weak_ptr保存引用,避免循环引用。
  • 效果:实现了线程安全的定时器,支持动态刷新和取消。

(2)挑战2:需要弄清楚函数bind的路线,在实现的过程当中函数bind太乱容易昏头。

相关推荐
中年程序员一枚2 小时前
php实现调用ldap服务器,实现轻量级目录访问协议(Lightweight Directory Access Protocol,LDAP)
服务器·开发语言·php
随祥2 小时前
windows下搭建MQTT测试环境(服务器/客户端)
运维·服务器
云老大TG:@yunlaoda3602 小时前
华为云国际站代理商IoTDA的设备生命周期管理功能有哪些优势?
服务器·数据库·华为云
智航GIS2 小时前
6.1 for循环
开发语言·python·算法
JHC0000002 小时前
推特(X)平台推文自动保存(支持保存所有推文相关数据到服务器)
运维·服务器·爬虫·python·dreamweaver
无风听海2 小时前
TaskFactory
服务器·开发语言·c#
登山人在路上2 小时前
Vue 2 中响应式失效的常见情况
开发语言·前端·javascript
不要em0啦2 小时前
从0开始学python:python环境的安装和一些基础知识
开发语言·python
董世昌412 小时前
创建对象的方法有哪些?
开发语言·前端