共计 2293 个字符,预计需要花费 6 分钟才能阅读完成。
在即时通讯网社区里,多是做 IM、音讯推送、客服零碎、音视频聊天这类实时通信方面的开发者,在波及到即时通讯技术时聊的最多的话题就是高并发、高吞吐、海量用户。
代码还没开始写,就思考万一哪天这 IM 用户量破百万、千万该怎么办的问题,是少数程序员的根本涵养。
在面视即时通讯相干工作的时候,高并发也是必谈问题,那到底什么是高并发?嗯,真要说出个所以然来,还真有点懵。
什么是高并发?
高并发是互联网零碎架构的性能指标之一,它通常是指单位工夫内零碎可能同时解决的申请数。
简略点说,就是 QPS(Queries per second)。
那么咱们在议论高并发的时候,到底在谈什么货色呢?归根结底,到底什么是高并发?
高并发到底是什么?
这里先给出论断:
1)高并发的根本体现为单位工夫内零碎可能同时解决的申请数;
2)高并发的外围是对 CPU 资源的无效压迫。
举个例子:如果咱们开发了一个叫做 MD5 穷举的利用,每个申请都会携带一个 md5 加密字符串,最终零碎穷举出所有的后果,并返回原始字符串。这个时候咱们的利用场景或者说利用业务是属于 CPU 密集型而不是 IO 密集型。
这个时候 CPU 始终在做无效计算,甚至能够把 CPU 利用率跑满,这时咱们议论高并发并没有任何意义。(当然,咱们能够通过加机器也就是加 CPU 来进步并发能力, 这个是一个失常猿都晓得废话计划,议论加机器没有什么意义,没有任何高并发是加机器解决不了,如果有, 那阐明你加的机器还不够多!)
对于大多数互联网利用来说,CPU 不是也不应该是零碎的瓶颈,零碎的大部分工夫的情况都是 CPU 在等 I /O(硬盘 / 内存 / 网络) 的读 / 写操作实现。
这个时候就可能有人会说,我看系统监控的时候,内存和网络都很失常,然而 CPU 利用率却跑满了这是为什么?
这是一个好问题,后文我会给出理论的例子,再次强调上文说的“无效压迫”这 4 个字,这 4 个字会围绕本文的全部内容!
控制变量法
万事万物都是互相联系的,当咱们在议论高并发的时候,零碎的每个环节应该都是须要与之相匹配的。
1)咱们会通过 DNS 服务器的解析,申请达到负载平衡集群;
2)负载平衡服务器会依据配置的规定,想申请摊派到服务层。服务层也是咱们的业务核心层,这里可能也会有一些 RPC、MQ 的一些调用等等;
3)再通过缓存层;
4)最初长久化数据;
5)返回数据给客户端。
要达到高并发,咱们须要负载平衡、服务层、缓存层、长久层都是高可用、高性能的。
甚至在第 5 步,咱们也能够通过压缩动态文件、HTTP2 推送动态文件、CDN 来做优化,这里的每一层咱们都能够写几本书来谈优化。
本文次要探讨服务层这一块,即图红线圈进去的那局部。不再思考讲述数据库、缓存相干的影响。
高中的常识通知咱们,这个叫控制变量法。
那咱们再谈谈上下文切换:
在议论上下文切换之前,咱们再明确两个名词的概念:
1)并行:两个事件同一时刻实现;
2)并发:两个事件在同一时间段内交替产生,从宏观上看,两个事件都产生了。
线程是操作系统调度的最小单位,过程是资源分配的最小单位。因为 CPU 是串行的,因而对于单核 CPU 来说,同一时刻肯定是只有一个线程在占用 CPU 资源的。因而,Linux 作为一个多任务 (过程) 零碎,会频繁的产生过程 / 线程切换。
在每个工作运行前,CPU 都须要晓得从哪里加载,从哪里运行,这些信息保留在 CPU 寄存器和操作系统的程序计数器外面,这两样货色就叫做 CPU 上下文。
过程是由内核来治理和调度的,过程的切换只能产生在内核态,因而虚拟内存、栈、全局变量等用户空间的资源,以及内核堆栈、寄存器等内核空间的状态,就叫做过程上下文。
后面说过,线程是操作系统调度的最小单位。同时线程会共享父过程的虚拟内存和全局变量等资源,因而父过程的资源加上线上本人的公有数据就叫做线程的上下文。
对于线程的上下文切换来说,如果是同一过程的线程,因为有资源共享,所以会比多过程间的切换耗费更少的资源。
当初就更容易解释了,过程和线程的切换,会产生 CPU 上下文切换和过程 / 线程上下文的切换。而这些上下文切换,都是会耗费额定的 CPU 的资源的。
进一步谈谈协程的上下文切换:
那么协程就不须要上下文切换了吗?须要,然而不会产生 CPU 上下文切换和过程 / 线程上下文的切换,因为这些切换都是在同一个线程中,即用户态中的切换,你甚至能够简略的了解为,协程上下文之间的切换,就是挪动了一下你程序外面的指针,CPU 资源仍旧属于以后线程。
须要深刻理解的,能够再深刻看看 Go 的 GMP 模型。
最终的成果就是协程进一步压迫了 CPU 的无效利用率。
回到开始的那个问题
这个时候就可能有人会说,我看系统监控的时候,内存和网络都很失常,然而 CPU 利用率却跑满了这是为什么?即时通讯软件开发征询蔚可云开发。
留神本篇文章在谈到 CPU 利用率的时候,肯定会加上无效两字作为定语,CPU 利用率跑满,很多时候其实是做了很多低效的计算。
以 ” 世界上最好的语言 ” 为例。
典型 PHP-FPM 的 CGI 模式,每一个 HTTP 申请:
1)都会读取框架的数百个 php 文件;2)都会从新建设 / 开释一遍 MYSQL/REIDS/MQ 连贯;3)都会从新动静解释编译执行 PHP 文件;4)都会在不同的 php-fpm 过程间接不停的切换切换再切换。
php 的这种 CGI 运行模式,基本上就决定了它在高并发上的灾难性体现。
找到问题,往往比解决问题更难。当咱们了解了高并发之后,咱们会发现高并发和高性能并不是编程语言限度了你,限度你的只是你的思维。
找到问题,解决问题!当咱们能无效压迫 CPU 性能之后,能达到什么样的成果?
上面咱们看看 php+Swoole 的 HTTP 服务与 Java 高性能的异步框架 Netty 的 HTTP 服务之间的性能差别比照。