- 论坛徽章:
- 9
|
本帖最后由 wlmqgzm 于 2015-11-07 11:21 编辑
独立做了一个基于BOOST ASIO的代码中完全无锁(mutex或者atomic等类似的东西) 的高并发高可靠网络服务器架构.
适应数百CPU的超级服务器, 无阻塞 无锁 免"线程切换", 充分发挥高性能服务器的处理能力.
可以说,基本上, 自己还没有见过如此无锁的基础网络架构.
完全无锁的东西, 自己是第一次做, 没有任何参考的情况, 终于想出了办法, 最终实现了, 这样一个统一的无锁服务器架构.
其次是网络流程实现了网络高可靠性规范设计要求.
核心技术包括: 基于BOOST ASIO开发, 全部异步事件驱动, 在代码中没有使用一个锁(mutex), 多线程多并发, M:N少量线程驱动大量任务, 免"线程切换"
所有的连接等全部在BOOST IO_SERVICE上处理, 中间没有任何线程的切换, 没有任何的阻塞. 所有代码全部是异步事件驱动的,没有同步调用.
"定时器"等 处理, socket检查time out的代码, 等 由 单线程work执行, 逐个处理, 因为超时(time out)分辨率只需要做到10毫秒级别, 处理非常轻松. 这部分涉及btree的检索,删除,增加等, 但是, 由于全部跑在一个线程上, 就没有冲突的可能性, 没有任何锁(如mutex)或者其他的同步的东西. 并且大的处理内容是基本上每秒才处理一次, 基本不消耗CPU.
对共享数据的读写, 均转化为 向单线程work的调用, 全部是通过任务调度器传递 post过去, 自己写的程序中不用加锁(mutex)
最终做到的结果, 就是: 无mutex, 真正无锁的高并发服务器架构, 呵呵.
还有高可靠网络内核设计.
最新的驱动模式, 可以适应上百CPU的超级服务器的工作, 收发work数量=逻辑CPU数量, 底层每个epoll事件由1个线程驱动(1线程时是彻底无锁模式, 连ASIO的底层也无锁, 单一线程解决了锁冲突问题. 实现了超高性能) , 多个epoll并发, 实现超高的性能.
新的驱动模式适应性最强, 基本可以适应2-1024个逻辑CPU的各类服务器.,
测试达到了ECHO服务器 每秒32万QPS包处理性能, 4.6万每秒新建连接的处理能力.性能突出. 下个月, 将给出在更多CPU的服务器下的测试报告.
主要还是intel 双核 奔腾G3258 的性能太差, 毕竟是最低端的CPU,
测试操作系统版本是国产桌面版 Ubuntu Kylin 桌面, 换服务器版本性能还能提高.
大约每3微秒处理一个收发包, 效率确实很高,
具体每个步骤, 都是尽量按照高可靠服务器的网络设计规范要求来实现, 每个操作又分为多个子步骤, 例如: 即使是简单的主动拆除连接, 就不是简单的socket close了之, 就包括: shutdown receive, wait, shutdown send, wait, hard close或者soft close等, 可以保证满足在网络连接正常的情况下, 正常退出服务器, 按照高可靠设计规范来设计的标准网络客户端不丢失一个数据包. 不是民用级别的
在正常网络情况下, 无论是哪一端主动拆线, 在底层TCP/IP协议的协调下, 在 服务器端不会出现典型的常见的30秒到4分钟(取决于linux版本)的 time_wait socket, 这个是aparche服务器未开长连接的经典情况,
在高可靠网络设计中, 无论是否使用长连接, time_wait socket一律出现在标准客户端.
在网络正常情况下, 大部分民用级别的软件, 服务器和客户端, 做不到服务端重启和退出过程中不丢失一个数据包, 这个也是我要开发这个基础包的原因之一.
总之, 关键设计满足 高可靠服务器 的 流程 设计 规范, 不是民用级别的,
后续展望:
网络服务器这一层的开发定型后, 后续是更高一层的数据接口层, 夹在应用层 和TCP/IP层之间, 类似 Google flatbuffer, Google protbuff等, 实现了数据切包. 但是我的多一个设计, 就是可靠性设计, 也是纠错处理的层
这一层的数据包规范的开发, 以及安全可靠层, Google其实没有公开全部信息, 还有部分高可靠性设计在里面, 不是民用级别的,
高可靠网络设计, 即使TCP/IP层出现错误, 也能满足不丢失一个数据包, 就是在网络服务器层上再包装一个安全可靠层级, 最后的代码流, 使用上与TCP/IP一样, 但是, 可靠性达到了永远不会错一个码的. 错误检测码有2组以上, 位数很长.
TCP/IP最大的问题是纠错检测码只有16bit, 远程传输如果出错, 或者路由器端少发一个字节, 有6.5万分之一的概率, 错误无法检测到, 民用级别的,
总之, 后续的部分代码也已经开发出来, 即使是增加了大量检错流程后, 我希望性能还是能够过Google protbuff协议, 现在还在做代码中, 呵呵呵呵
2015.10.21 最新性能指标为30.7万QPS ECHO, 降低8%, 新增指定socket debug功能, 内部增加了一个shared_ptr, 实践中发现新增shared_ptr对于性能指标有明显影响, 应该是shared_ptr内部使用了锁的原因. 改进时钟精度为微秒, 后台管理从1秒改为100毫秒检查一次. sever主动发起socke read wait timeout过程, 双方经过一系列响应, 最终client主动拆线后, server拆线并删除管理数据的反应时间降低到100毫秒. 系统继续采用整个server单定时器轮询方式工作,(考虑 每socket一个定时器的开销会很大). 我觉得单定时器轮询, 也算一个解决的办法吧. 正在制作调试防简单DDOS的模块.
2015.10.23 高性能"lock-free"无锁队列的应用: boost::lockfree::spsc_queue 一个无等待的单生产者/单消费者队列
在做抗DOS处理的代码时, 存在2个线程之间, 必须要交换数据的问题, 其中一个线程是管理线程, 一个是acceptor线程.
对于此类问题, 传统的方式就是: 生产者和消费者模式, 二者之间, 通过队列QUEUE, 双方都加锁(mutex)处理队列.
我的解决方案是采用 Boost 高性能 无锁队列来实现, 只用了三条代码就解决了此问题. (后面有详细代码)
无锁队列的优势:
它将保证线程无限次调用这个方法都能够在有限步内完成,而不会因为其他线程被阻塞而导致本线程无法在有限步内完成,即“无锁”。
保证在任何情况下所有并发中有一个操作能够得到执行, 不必考虑"多线进程的优先级反转等策略".
2015/10.26 性能提高到32万QPS, 后台数据管理全部采用accept_time(微秒)作为主索引, 形成了唯一性, 减少了管理代码的数量, 降低了难度.
管理数据形成双索引结构, 对不同时间要求的数据使用不同的索引, 采用了最高效率的HASH表.
acceptor, timer1全部集中管理, 析构代码中主动释放, 减少代码复杂度,
整个系统可以更简单更安全的退出, 对整体析构增加了时间追踪代码, 退出前全部安全拆线流程增加到了二级(第一级是标准流程,第二级是强制退出), 对析构流程再次进行了详细的分析, 保证不留死角, 不留隐患.
2015.10.27 自修复协议栈的开发, 正在做代码中. 这一层提供给应用层一个高可靠全透明的网络环境, 数据的读写结构是struct, 最终目标是读写远端数据跟读本地共享内存中的一样.
2015.10.28 最新目前ECHO SERVER代码继续改进, 已经改进可以适应数百CPU的超级服务器的工作, 无阻塞无锁, 充分发挥高性能服务器的处理能力.
2015.11.01 在市售的最低端服务器CPU E3-1231V3上进行测试, 测试软件和服务器同机器, 网络层的性能是: ECHO SERVER每秒82万QPS ECHO.
2015.11.04 实现网络架构层和应用逻辑层双异步, 就是说包处理的流程也可以是异步的,当网络层把数据包交给上层代码,
1)简单的同步系统中, 上层代码就直接放到一个函数中, 函数引用收发数据的容器, 处理数据包, 要发送的数据包放到容器中, 调用过程是当前函数处理完毕后, 函数返回. 是同步调用过程, 因为就一个函数, 并且在同一个线程中,
返回0后,网络层内部处理收发包, 上层不用关注网络层的调用过程, 这种可以适应简单的全内存操作的处理过程.
2)复杂的异步系统, 上层代码收到网络层的数据包后, 启动上层代码的异步过程, 调用函数返回1, 网络层暂时没有发包可以处理, 可以继续io_service内部循环,
网络层继续执行当前io_service下其他socket的收发包处理, 减少数据收发包的延时,
网络层线程不涉及上层调用, 上层应用不占用网络线程的CPU处理能力,
上层代码经过其他专用线程处理各类复杂调用, 包括各类异步IO事件(例如:读写硬盘,读写远端网络,读写数据库等)的处理等, 最终形成要输出的结果, 再异步调用网络层接口, 实现发包处理,
这个就是 网络架构层和应用逻辑层双异步.
2015.11.06 实现每秒87万QPS ECHO, 改进是: 线程池底层, 换用自己的实现(原来是Boost::thread_group), 指定各线程的CPU亲缘性, 并且双份连接建立后不变的数据, 尽量使用线程内部内存, 减少对全局内存的读, 避免cache丢失, 提高了多核下高并发的处理能力, 但也降低了单核下的处理能力.
2015.11.07 正在做代码实现: 单一网络层对象无锁高性能统一服务架构, 就是: 单一网络对象可以监听多个不同的端口, 实现对外的不同服务, 或者可以连接多个外部服务器的端口, 但是只使用了单一网络层对象, 实现了多listen端口,多connect的各类资源统一管理,调度, 包括: 任务调度层, CPU资源, socket资源的管理, 超时的管理等等, 内部没有使用一个锁, 也不需要使用锁, 因为所有可能冲突的地方全部是指定专门的单线程执行的.
换句话说, 就是过去, 多个listen服务, 对应多个底层网络架构对象, 每个网络对象都是完全独立的, 甚至是独立进程, 独立程序.
现在, 多个listen服务, 多个对外connect连接, 底层网络架构对象可以只有一个, 优点就是:共享一切资源, 共享一切代码, 应用层代码异常简单, 降低CPU任务切换.
这个无锁高性能统一架构的优势之一就是做代理服务器特别方便, 应用层就几行代码, 多数功能都在网络层实现, 也有利于开发多个产品, 共享网络层的各类资源.
可以实现单一对象,http,mail,ftp等多种服务, 不会浪费一点服务器资源, 都共享了, CPU没有切换, ASIO没有冲突.
|
|