什么叫做高并发场景?
高并发场景指数量庞大的操作或请求在同一时间段内发生,列如:双11当晚,庞大的用户在晚上十二点时间段访问淘宝,淘宝的服务器需要在短时间内处理大量的网络请求。
高并发场景所带来的问题
高并发场景会让服务器在短时间内多次进行i/o操作,如取得硬盘上中存储的关于用户的相关信息。i/o操作不是需要cpu来完成,而是通过DMA,例如:一个淘宝用户访问淘宝服务器,cpu这时处理这个请求,cpu和DMA可能会产生这样的对话:
- CPU:'嘿,朋友,我这边需要拿个数据,你能帮我拿一下吗?'
- DMA:'好嘞,稍等一会。'
- 经过等待之后
- DMA:'你要的东西我帮你拿回来了'
- CPU:'太棒了,谢谢~'
- 由上可见,cpu需要等待DMA获取数据,在拿到数据后才进行之后的相应操作,这样CPU等待的时间就白白浪费掉了,也就是说其他需要cpu做得工作也会延因为CPU的等待而延迟了,试想,在高并发环境服务器的cpu对每一个客户的请求都等待一段时间,这样晚到达的请求可能双十一结束了还没有看到淘宝的页面. 如何解决呢?
- CPU可以雇一个高级专家叫做‘进程’来帮他接受用户的请求并等待数据的获取,好比,cpu说‘这是我分配给你的资源,你拿了资源,就好好地从这边等着,DMA数据拿完了告诉我一声’,进程拿了资源就要做事,这样CPU就不用等待了,CPU可以处理其他的工作,等到进程通知它拿到数据之后,他就可以做和数据有关的一些操作了。
- cpu之后发现,雇进程这一个高级专家太昂贵了,例如,每一个客户等请求都需要创建一个进程来服务,如果有100个用户,那么就需要100个进程,cpu通过进程复制来进行创建进程,那么这样每创建一个进程,就要复制相应的内部状态,导致相同的数据在内存中存在多分,造成浪费。怎么办呢?
- cpu发现,我可以不用请高级专家来做接受请求并等待数据这样一件小事情,请几个小朋友就能把事情给做了,于是CPU请来了线程,和进程相比,用线程来等待数据有什么优势呢?在创建线程的过程中,所有创建的线程利用的都是同一份资源,因为‘进程是资源分配的最小单元’---这句话教操作系统的老师几乎都会说一遍,这样就避免了资源浪费。才用线程的复制也只能说比进程的复制好,因为,1.用户请求时,需要切到线程2.当线程接受请求并等待数据后,需要CPU切换到当前进程把数据传回到cpu所在单线程,这也就出现了切换执行上下文---可以理解为程序运行时所需要的资源环境 所造成的浪费,加之创建、销毁线程所需要的资源。当请求过多时,切换上下文所造成的浪费会占据超多的时间。那么怎么办呢?那就出现了node所采用的基于事件驱动的非阻塞异步i/o。
- node是怎么做的呢? node的主线程来处理用户的请求封装请求对象,利用自身底部的线程池*进行请求对象中的I/O操作,等到数据后归还线程,并将数据给主线程中的I/O观察者,cpu主线程从观察者取出回调函数执行。 与线程创建相比,我不用主动创建线程,也不用利用线程去处理用户请求,这样就减少了不必要的创建线程的和切换执行上下文的浪费。
注:node的事件循环,观察者,请求对象的概念都没有进行介绍,请参考《node.js深入浅出》。
参考资料:《计算机操作系统(第四版)》---西安电子科技大学出版社 《node.js深入浅出》---朴灵