【笔记】 c10K

【笔记】 c10K

2013 年 02 月 19 日

写在前面

《The C10K problem》 是十年前的经典文章了, 虽然现在动不动都爱讨论 C100K 乃至 C1000K, 但是经典的东西还是值得回顾.

比较知名的 IO 框架

  • 重量级的 C++ IO 框架, 其中的 Reactor 框架用 OO 的方式处理非阻塞 IO, Proactor 框架用 OO 方式处理异步IO. ACE 的库代码量不小, 真正核心的东东其实不多, 值得学习.
  • C++ 的 IO 框架, 慢慢成为了 Boost 库的一部分.
  • 轻量级的 C IO 框架, 支持 epoll, poll, select, kqueue. 它的分级触发机制 (level-triggered) 各有利弊.

IO 策略

  • 在单线程中是否处理多个 IO, 如何处理?
    • 不处理, 只用阻塞/同步 IO, 通过多线程或者多进程的方式实现并发.
    • 使用非阻塞调用(例如设置 Socket 为 O_NONBLOCK), 当 IO 可用时发出通知.
    • 使用异步调用(例如 aio_write), IO 完成时发出通知.
  • 如何控制每个客户端?
    • 每个客户端一个进程(经典的 Unix 实现方式).
    • 单 OS 线程中处理多个客户端.
    • 每个客户端一个 OS 线程.
    • 每个 Active 客户端一个 OS 线程(例如: Tomcat + Apache, 线程池).
  • 是否使用标准的 OS services, 还是把代码加到 Kernel 中, 例如定制驱动, Kernel模块等.

常用的 IO 策略

  • 每个线程多个客户端, 使用非阻塞 IO 和水平触发通知. 设置网络句柄非阻塞模式(nonblock), 然后使用 Select 或者 Poll 来等待返回可处理的通知. 当磁盘文件不在内存中时, 通过 read() 或者 sendfile() 从磁盘读取文件会成为瓶颈. 所以如果处理磁盘 IO, 最好还是使用异步 IO. 如果在没有 AIO 的系统中, 靠谱的解决方法是当收到通知时, 开启一个 worker 线程来单独处理, 主线程继续处理其他通知.
    • 传统的 select(), 受限于 FD_SETSIZE 句柄数, 这个限制可能被编译进了 stdlib, 改起来麻烦.
    • 传统的 poll(), 由于 poll 的轮询机制, 在句柄数达到K级别时, 速度会变得很慢.
    • /dev/poll, Solaris 上的推荐方式, 核心思想是 poll() 调用时的大部分时间内, 句柄是不变的, 通过写句柄到 /dev/poll 中并读取, 可以提高性能.
    • kqueue, FreeBSD 上的推荐方式, 可以水平触发, 也可以边缘触发.
    • epoll, Linux 上的高性能实现方式, 可以水平触发, 也可以边缘触发.
  • 每个线程多个客户端, 使用非阻塞 IO 和边缘触发通知. 相比于水平触发通知方式, 性能更高, 推荐方式, 但是在代码编写时也需要更加小心. 补充说明一下: 如果就是单线程实现的话, 无法充分利用多核 CPU, 如果多线程实现的话, 代码复杂度会加大, 甚至某些 OS 不支持多线程的 IO 触发通知.
  • 每个线程多个客户端, 使用异步 IO. Linux 2.5.32 开始支持 Linux AIO, 但是没有采用内核线程, 而是使用了一个高效的 underlying API, 目前( Linux 2.6.* ? ) 不支持 AIO Socket. 一般 Windows 平台上 AIO 应用比较广泛.
  • 每个线程一个客户端, 阻塞 IO. 把复杂度转移给 OS 去处理, 比较耗性能, 小规模的应用倒也不失为一个选择.
  • 把 IO 服务代码编译进内核 大多人不是很赞成这么干.

其他的一些观点

  • epoll, kqueue, /dev/poll. epoll 是 Linux 的方案, kqueue 是 FreeBSD 的方案, /dev/poll 是最古老的 Solaris 的方案, 使用难度依次递增. 简单的说, 这些 API 做了两件事:
    1. 避免了每次调用 select/poll 时 Kernel 分析参数建立事件等待结构的开销, Kernel 维护一个长期的事件关注列表, 应用程序通过句柄修改这个列表和捕获 I/O 事件.
    2. 避免了 select/poll 返回后, 应用程序扫描整个句柄表的开销xi, Kernel 直接返回具体的事件列表给应用程序.
  • Select 服务器的一份测试数据.
  • zero-copy, sendfile(), 努力避免在 IO 过程中的无谓的数据拷贝带来的性能流失.
  • TCP_CORK 避免频繁的发送碎片数据, 不过在某些场合不适合, 例如实时性高的游戏服务器. 其他可以参考 《TCP 参数调优》.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏微服务生态

缓存系列文章--热点key问题

我们通常使用 缓存 + 过期时间的策略来帮助我们加速接口的访问速度,减少了后端负载,同时保证功能的更新,一般情况下这种模式已经基本满足要求了。   但是有两个...

11930
来自专栏james大数据架构

我是如何处理大并发量订单处理的 KafKa部署总结

  今天要介绍的是消息中间件KafKa,应该说是一个很牛的中间件吧,背靠Apache 与很多有名的中间件搭配起来用效果更好哦 ,为什么不用RabbitMQ,因为...

41590
来自专栏Java架构

干货:大型互联网公司分布式缓存的优秀实践和线上案例在此我在推荐一个学习架构框架的学习体系:

34160
来自专栏开源优测

一篇文章让你入门API测试

什么是API API是Application Programming Interface的简写。 实现了两个或多个独立系统或模块间的通信和数据交换能力。 什么是...

401100
来自专栏开源优测

一篇文章入门API测试

API是Application Programming Interface的简写。

12220
来自专栏noteless

windows资源管理器多标签打开 windows文件夹多标签浏览 浏览器tab页面一样浏览文件夹 clover win8 win10 报错 无响应问题怎么解决 clover卡死 clover怎么换皮

Clover 是 Windows Explorer 资源管理器的一个扩展,为其增加类似谷歌 Chrome 浏览器的多标签页功能。

40030
来自专栏喔家ArchiSelf

老曹眼中的缓存技术

缓存是系统快速响应中的一种关键技术,是一组被保存起来以备将来使用的东西,介于应用开发和系统开发之间,是产品经理们经常顾及不到的地方,算是技术架构中的非功能性约束...

17920
来自专栏Rainbond开源「容器云平台」

【微服务】微服务实战(二):使用API Gateway

24540
来自专栏架构师小秘圈

大型网站图片服务器架构的演进

作者:丁浪,非著名架构师。关注高并发、高可用的架构设计,对系统服务化、分库分表、性能调优等方面有深入研究和丰富实践经验。热衷于技术研究和分享。 声明:版权归丁浪...

86440
来自专栏开源优测

一篇文章让你入门API测试

什么是API API是Application Programming Interface的简写。 实现了两个或多个独立系统或模块间的通信和数据交换能力。 什么是...

27640

扫码关注云+社区

领取腾讯云代金券