我用现代 C++ 写了个 Web 框架,这 25 个设计细节让性能拉满

写在前面 两万多行代码写下来,我把踩过的坑和想明白的事都总结在这了。不讲概念,只聊实战中每个设计"为什么这么做"。 搞 C++ Web 框架这事,从第一行代码到现在,说实话走了不少弯路。今天不聊怎么用,聊聊底层那些设计决策——为什么要这么写,当时碰到了什么问题,怎么一步步改成现在这样的。 一、编译期就把活干完 1. 一套模板搞定 TCP 和 SSL 最早我是分别写了 TcpConnection 和 SslConnection 两个类,代码重复率 80%以上,改一个 bug 要改两遍。后来换成 GenericConnection<SocketType>,内部用 if constexpr 做分支: 1 2 3 if constexpr (hIsSslStream<SocketType>) { co_await stream_.async_handshake(...); } 编译器直接在编译期把不匹配的分支丢掉——纯 TCP 的二进制里一个字节的 SSL 代码都没有。维护成本砍半,运行时零开销。这不是什么高深技巧,但真正落地用好的项目不多。 2. 用不到的模块,连编译都不参与 数据库、OpenAPI 这些模块,不是每个项目都用得上。我用 CMake option + 宏隔离的方式处理: 1 option(HICAL_WITH_DATABASE "Enable DB middleware" OFF) 代码里所有 DB 相关的逻辑都包在 #ifdef HICAL_HAS_DATABASE 里。你不开这个 option,这些代码连语法检查都不走,更别说占二进制体积了。比运行时搞个 feature flag 干净太多——运行时 flag 意味着代码虽然不执行,但死代码还在那占着 icache。 3. TRACE 日志:Release 下彻底消失 开发时满屏 TRACE 日志方便调试,但生产环境绝对不能有这些开销。我的做法是 NDEBUG 下 HICAL_LOG_TRACE 直接展开成 ((void)0)——注意,这不是"判断级别后跳过",而是连参数求值的代码都不存在于二进制中。 ...

May 30, 2026 · 4 min · 715 words

Hical 框架开发心得:七个深刻教训

Hical 框架开发心得:七个深刻教训 引言 Hical 是一个基于 Boost.Asio 的现代 C++20/26 高性能 Web 框架,采用原生 HTTP/WebSocket 网络栈(picohttpparser + 自研 WebSocket),从第一行代码到现在的 45+ 测试文件、3 层内存池、协程化数据库中间件、自研日志系统、OpenAPI 自动生成、WsHub 广播管理器、QPS 从 27K 到 159K 的优化历程,一路走来踩了不少坑,也收获了很多。 这篇文章不讲 API 用法,也不讲架构教程——那些在其他文章里都有。这篇只聊开发过程中的真实体会:哪些决策事后证明是对的,哪些看似优雅的方案差点把自己埋了,以及最终选择背后的取舍逻辑。 目录 Hical 框架开发心得:七个深刻教训 引言 目录 一、C++20 协程是双刃剑 1.1 协程让异步代码变清晰了……吗? 1.2 co_await 后 this 可能已经死了 1.3 io_context 析构时的协程帧:成员声明顺序陷阱 1.4 co_spawn(detached) 的悬空引用陷阱 1.5 异常传播:catch 里不能 co_await 1.6 收获:协程不是银弹 二、PMR 三层内存池——收益大但陷阱多 2.1 为什么要三层 2.2 踩坑:upstream 选错导致跨线程竞争 2.3 踩坑:allocator 忘了传播 2.4 收获:PMR 的收益在高并发场景才显现 三、模板 + Concepts 比虚函数继承更适合网络框架 3.1 GenericConnection 的零成本分流 3.2 NetworkBackend concept:可替换但不多态 3.3 收获:编译期分支 > 运行时分支 四、自研日志系统的价值 4.1 为什么不用 spdlog 4.2 六层架构的设计决策 4.3 两个关键的性能优化 4.4 收获:核心框架值得自研,应用项目直接用 spdlog 五、双轨反射——为未来留后路 5.1 问题:C++26 还没来,但 API 要现在设计 5.2 宏回退层的实现策略 5.3 收获:用宏模拟未来语言特性 六、移除 Boost.Beast——火焰图驱动的依赖清退 6.1 Beast 到底慢在哪 6.2 picohttpparser + 零拷贝请求 6.3 自研 WebSocket 栈的取舍 6.4 收获:数据驱动的依赖决策 七、WsHub 广播管理器——从"能用"到"好用"的 WebSocket 架构 7.1 问题:裸连接管理的困境 7.2 WsHub 的核心设计 7.3 写串行化:被忽视的并发陷阱 7.4 收获:框架应该管理连接生命周期 后记:ThreadSanitizer CI 揪出的隐藏竞态(v2.6) Boost.Asio 对象的跨线程操作 stop() 的并发调用:门卫模式 教训 总结:七条核心原则 一、C++20 协程是双刃剑 1.1 协程让异步代码变清晰了……吗? 在引入协程之前,一个 HTTP 请求的处理链是嵌套回调: ...

May 18, 2026 · 16 min · 3291 words