专栏首页北京马哥教育Web APP编程模型和IO策略

Web APP编程模型和IO策略

现代大型高性能网站诸如淘宝,京东,微博,FB,知乎等等,网站架构涉及很多知识。像业务分层,软件分割模块化,分布式部署,集群服务器,负载均衡等技术可以帮助架构师将一个大的复杂的问题切分成小的简单的问题。这篇文章着眼于解决这些切好的小问题上,单机上有哪些编程实践或者模型可以很好的做到高并发。本人web开发小白一枚,写文章是想梳理自己的思路,求得大牛斧正,希望各位多多批判。文章的内容大多来自网上的阅读加上些自己的理解,文末附上参考阅读的文章。

一个极简高并发模型

因为有数年的嵌入式领域的经验,先说一下我认为的比较高效的处理模型。

  • 硬件环境:单机30core, 1G Hz。
  • 软件环境:6Wind fastpath,每个core上都是run-to-complete的endless loop.没有操作系统。
  • 功能:一个超级简单的reverse proxy,具有load balance的简单功能。

衡量并发性能,我们看一下一个IP包从网口缓冲区收上来处理到发出去大约需要多长时间呢?

收+处理+发大概是500+1000+500=2000 cycles,时间也就是2us。单机1s内可以支持30*(1s/2us)=15,000,000 request/s的并发。屌炸天的并发能力了吧!原因有两个:

  • 没有操作系统overhead。
  • 包处理简单,IP层的处理,直接c函数调用,总共1000 cycle。

当然这是从嵌入式得来的经验,web开发中不可能这样,没有Nginx,没有web框架,没有lib没有各种open source,甚至没有linux。回到原始社会造出飞机大炮来,这不把web开发者逼疯了。软件也是一个社会化协作的过程,os,framework,lib,opensource给开发者带来极大方便的同时,也伴随着性能的开销。如何在性能和可扩展性、维护性等其他指标找到一个平衡点,如何选择合适的编程模型,合适的第三方模块达到最小的overhead,这是成长为高手的开发者都会不断思考的问题。

High Performance architecture,这篇文章总结了四个性能杀手:

  • 数据复制
  • 上下文切换
  • 动态内存分配
  • 锁竞争

上面的编程模型之所以高效,就是将CPU用到极致,尽量避免这4种情况发生。心中有这么一个极简的高效模型,后面学习其他模式的时候可以暗做对比看一下到底会有哪些额外的开销。

常用的server端linux高并发编程模型

Nginx Vs Apache

大名鼎鼎的Nginx使用了多进程模型,主进程启动时初始化,bind,监听一组sockets,然后fork一堆child processes(workers),workers共享socket descriptor。workers竞争accept_mutex,获胜的worker通过IO multiplex(select/poll/epoll/kqueue/…)来处理成千上万的并发请求。为了获得高性能,Nginx还大量使用了异步,事件驱动,non-blocking IO等技术。”What resulted is a modular, event-driven, asynchronous, single-threaded, non-blocking architecture which became the foundation of nginx code.”

Nginx 架构

对比着看一下Apache的两种常用运行模式,详见 Apache Modules

  • 1. Apache MPM prefork模式

主进程通过进程池维护一定数量(可配置)的worker进程,每个worker进程负责一个connection。worker进程之间通过竞争mpm-accept mutex实现并发和链接处理隔离。 由于进程内存开销和切换开销,该模式相对来说是比较低效的并发。

  • 2. Apache MPM worker模式

由于进程开销较大,MPM worker模式做了改进,处理每个connection的实体改为thread。主进程启动可配数量的子进程,每个进程启动可配数量的server threads和listen thread。listen threads通过竞争mpm-accept mutex获取到新进的connection request通过queue传递给自己进程所在的server threads处理。由于调度的实体变成了开销较小的thread,worker模式相对prefork具有更好的并发性能。

小结两种webserver,可以发现Nginx使用了更高效的编程模型,worker进程一般跟CPU的core数量相当,每个worker驻留在一个core上,合理编程可以做到最小程度的进程切换,而且内存的使用也比较经济,基本上没有浪费在进程状态的存储上。而Apache的模式是每个connection对应一个进程/线程,进程/线程间的切换开销,大量进程/线程的内存开销,cache miss的概率增大,都限制了系统所能支持的并发数。

IO策略

由于IO的处理速度要远远低于CPU的速度,运行在CPU上的程序不得不考虑IO在准备暑假的过程中该干点什么,让出CPU给别人还是自己去干点别的有意义的事情,这就涉及到了采用什么样的IO策略。一般IO策略的选用跟进程线程编程模型要同时考虑,两者是有联系的。

同步阻塞IO

同步阻塞IO是比较常见的IO模型,网络编程中如果创建的socket的描述符属性设置为阻塞的,当socket对应的用户空间缓冲区内尚无可读数据时,该进程/线程在系统调用read/recv socket时,会将自己挂起阻塞等待socket ready。

同步非阻塞IO和非阻塞IO同步复用

同步非阻塞IO

非阻塞IO同步复用

对比着同步阻塞IO,如果socket数据没有ready,系统调用read/recv会直接返回,进程可以继续执行不会挂起让出CPU。当然这样做对单个socket来说没有多大的意义,如果要支持大量socket的并发就很有用了,也就是IO复用。select/poll/epoll就是这样的应用,IO的read是非阻塞式调用,select是阻塞式的,同步发生在select上。程序通过select调用同时监控一组sockets,任何一个socket发生注册过的事件时,select由阻塞变为ready,函数调用返回后程序可以读取IO了。前面提到的Nginx(使用epoll)和apache(使用select)都有使用这一IO策略。select/epoll这种IO策略还有另外一个名字叫Reactor,具体他们之间的细节区别再另开一文。

异步非阻塞IO

对比同步非阻塞IO,异步非阻塞IO也有个名字—Proactor。这种策略是真正的异步,使用注册callback/hook函数来实现异步。程序注册自己感兴趣的socket 事件时,同时将处理各种事件的handler也就是对应的函数也注册给内核,不会有任何阻塞式调用。事件发生后内核之间调用对应的handler完成处理。这里暂且理解为内核做了event的调度和handler调用,具体到底是异步IO库如何做的,如何跟内核通信的,后续继续研究。

原文链接:https://segmentfault.com/a/1190000004547892

本文分享自微信公众号 - 马哥Linux运维(magedu-Linux)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2016-07-11

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何查看并杀死僵尸进程

    In UNIX System terminology, a process that has terminated,but whose parent has n...

    小小科
  • 如何查看并杀死僵尸进程

    In UNIX System terminology, a process that has terminated,but whose parent has n...

    小小科
  • Linux性能及调优指南(翻译)之Linux进程管理

    本文为IBM RedBook的Linux Performanceand Tuning Guidelines的1.1节的翻译 原文地址:http://www.re...

    小小科
  • 理解Linux里面的IO模型

    User space(用户空间)和 Kernel space(内核空间)。Linux里面这么设计的目的主要是为了安全,即使用户空间崩溃了,内核也不受影响。所以在...

    我是攻城师
  • IO模型梳理-从操作系统到应用层

    IO模型是编程语言和软件开发中重要的知识。本篇从IO模型这个切入点横向梳理了从操作系统到应用层IO模型相关知识。考虑到技术本身具有横向迁移的特点,也可以帮助大家...

    春哥大魔王
  • C++IO流简介

    输入输出(IO)是指计算机同任何外部设备之间的数据传递。常见的输入输出设备有文件、键盘、打印机、屏幕等。数据可以按记录(或称数据块)的方式传递,也可以 流的方式...

    Dabelv
  • IO FILE之劫持vtable及FSOP

    之前的文章对IO FILE相关功能函数的源码进行了分析,后续将对IO FILE相关的利用进行阐述。

    迅达集团
  • redis中save和bgsave区别

    SAVE 和 BGSAVE 两个命令都会调用 rdbSave 函数,但它们调用的方式各有不同:

    实时计算
  • python定时任务最强框架APScheduler详细教程

    上次测试女神听了我的建议,已经做好了要给项目添加定时任务的决定了。但是之前提供的四种方式中,她不知道具体选择哪一个。为了和女神更近一步,我把我入行近10年收藏的...

    无涯WuYa
  • 2016年移动安全趋势及威胁预测

    2015年已经过去,这一年间发生了很多令我们很震惊的事件,透过这些大事件和漏洞,我们可以预测一下2016年移动安全趋势和可能存在的安全威胁。 1. 恐怖威胁 ...

    FB客服

扫码关注云+社区

领取腾讯云代金券