end 结束 ,我理解正在码字中
下面别人总结,基本的解释,但是没说点子上。
互联网运用系统开拓肯定常常会看到高并发和高性能这两个词,可谓是耳熟能详,而详细的含义和关系真的如你所想的,真正的理解了吗?

这次,我也结合自己的理解,来跟大家分享一下。
先来看一个例子:
一个蓄池塘,是1m1m1m=1立方米大小,有一个出水口,出水口每秒钟流出0.1立方米,那么这个蓄池塘的并发量是1立方米,出水速率是0.1立方米/秒。
如果增加一个出水口,都是每秒钟流出0.1立方米,那么这个蓄池塘的并发量没变,但是出水速率变成了0.2立方米/秒。
同理,增大了出水口,蓄池塘的出水速率也变快了。
上面我们很随意马虎知道,并发量是一个容量的观点,性能便是出水速率,而且有下面这些结果。
1 增大蓄池塘的长宽高,可以增加并发能力。
2 出水口如果扩大了出口大小,则可以提高出水的速率,也便是性能提高了。
3 增加出水口的数量,则是增加了并行处理的能力,同样可以提高性能。
那么对照我们打算机中,我们的系统中,是怎么样的结果呢?1 增加做事器的内存大小,可以增加并发量。由于内存增加了,就可以开更多的进程,更多的线程,也可以扩大任务行列步队的大小。
2 提高cpu的主频速率,优化程序,可以提高性能。cpu更快了,程序优化的更好了,处理单个任务的韶光也就更短了。
3 增加多核乃至分布式做事器数量,也可以提高性能,同时提高并发量。
如果只是性能提高了,并发量是否也能提高呢?
如果我们静态的理解并发量,那它是不会提高的。
而我更乐意动态的来理解并发量,即:单位韶光内可以进来的最大数量。
那么提高性能,是可以线性提高并发量的,由于单位韶光内,进来的同时也有出去。
接下来,再来详细的剖析下,上面的几种结果,是不是真的可以实现呢?是不是完备精确呢?
我们先来做一个假设,单个进程内存占用10M,单个线程内存占用2M,单个协程内存占用20K,行列步队任务内存占用2K,我们下面来看看内存与并发量的关系。
(详细的内存占用大小在不同的运用处景中会有很大的不同,以是这里只是为了方便打算而做的一个假设)
内存量 进程数 线程数 协程 行列步队任务
1G 100 500 50K 500K
2G 200 1000 100K 1000K
4G 400 2000 200K 2000K
8G 800 4000 400K 4000K
对应的几种运行模式
多进程: php fast-cgi
多线程: java web
协程: go
行列步队: nginx
从上面的结果中,我们可以很直不雅观的看出来,并发能力在不同的运行模式中的巨大差异。
多进程和多线程的模式,不仅是内存开销巨大,而且在数量不断增加的情形下,对CPU的压力也是非常巨大,这也是为什么这类系统在并发量大的情形下会很不稳定,乃至宕机。上面假设中计算出来的数据,都是静态的容量,如果所有任务都不处理,那么肯定都是会很快就被撑爆。
以是要达到更高的并发量,就须要有更快的处理速率,即做好性能优化。
下面,再来做一个假设。我们现在有一台做事器,配置是8核16G内存。
如果我们的运用是打算密集型,纯运算的系统,如:数据索引查询、排序等操作。
而且还要假设,这个运用在多核并走运算时不存在锁竞争的情形(只读)。
qps=1000ms/单个要求耗时8
如果单个要求(任务)耗时100ms,那么我们可以打算出来
qps=1000ms/100ms8=80个/秒
如果我们优化处理的算法,单个要求耗时降落到10ms,那么
qps=1000ms/10ms8=800个/秒
如果可以连续优化,将单个要求耗时降落到1ms,那么
qps就可以达到更高的8k。
上面的情形和优化的效果理解起来该当很随意马虎,由于对做事器资源的依赖更多是CPU的运算能力和数量。
【进程先容】每一个运用运行起来都会有自己的进程,由于进程是系统资源分配的基本单位。
在线程涌现之前,进程也是CPU调度的基本单位。
每一个进程创建出来,都会分配三种基本的内存资源,分别是代码段、数据段和堆栈段。
代码段和数据段分别保存着运用的实行代码和全局变量、常量、静态变量,这些便是不会变革或者很少变革的内容,当然内存占用相对也会比较少。
而运用运行起来,须要的更多资源就会在堆栈中用到。
个中堆空间是存放各种变量数据的地方,内存大小也是可以动态调度的。
而栈空间是子任务(线程、协程)独立存放自己的数据地方,比如:函数调用、参数、返回值和局部变量。
这样一来,子任务(线程、协程)之间就可以独立运行,而且还可以共享堆空间中的变量数据。
【线程先容】
线程在新的操作系统中,也称为轻量级进程,由于现在的线程已经是CPU调度的基本单位了。
操作系统不仅仅坚持一个进程表,而且还会坚持一个线程表,这样操作系统就可以把线程作为调度单位。
线程是进程内创建,可以共享进程的资源,以是,线程自身独立的资源依赖就会少很多,由于只须要为每个线程分配独立的栈空间。
而线程的栈空间是固定大小的,如果程序比较繁芜,或者里面的数据量大,为了不涌现“栈空间不敷”的缺点,就必须把栈空间设置的足够大才行。
于是,线程是固定的栈空间S(足够大),统共运行多少线程T,占用总的栈空间就可以大略打算出来=TS。
这个资源占用量相对T个进程来说,还是少了很多的,毕竟线程是共享了进程的代码段、数据段和堆空间。
【协程先容】
协程是可以在运用态协作的程序,它的调度不是操作系统处理,而是运用系统自己来调度处理,也称为轻量级线程。
在操作系统可以独立调度线程之前,在线程还是作为运用的程序包,有运用程序自己调度和管理的时候,实在那种线程也就跟现在的协程是一个观点了。
以是,这里我们就不再讲以前的那种运用内的线程,只讲新的协程。
如果说到线程,便是新的可以被操作系统独立调度的线程。
协程作为运用系统内调度的子任务单元,当然也是会共享进程的各种资源,除了自己的栈空间(函数调用、参数、返回值、局部变量)。
而协程与线程紧张的差异有两个,最大的便是调度办法,线程是操作系统调度,协程是运用系统自己调度。
其余一个差异,协程的栈空间是可以动态调度的,这样空间利用率就可以更高,一个任务须要2K空间就分配2K内存,一个任务须要20M空间就分配20M,而不用担心栈空间不足或者空间摧残浪费蹂躏。
由于上面的两个缘故原由,协程的上风也就凸显出来。
1 协程可以更好的利用CPU,不用把CPU摧残浪费蹂躏在线程调度和高下文切换上。
2 协程可以更好的利用内存,不用全都分配一个偏大的空间,只须要分配须要的对应空间即可。
libco的特性
无需侵入业务逻辑,把多进程、多线程做事改造成协程做事,并发能力得到百倍提升;支持CGI框架,轻松构建web做事(New);支持gethostbyname、mysqlclient、ssl等常用第三库(New);可选的共享栈模式,单机轻松接入千万连接(New);完善简洁的协程编程接口类pthread接口设计,通过co_create、co_resume等大略清晰接口即可完成协程的创建与规复;__thread的协程私有变量、协程间通信的协程旗子暗记量co_signal (New);措辞级别的lambda实现,结合协程原地编写并实行后台异步任务 (New);基于epoll/kqueue实现的小而轻的网络框架,基于韶光轮盘实现的高性能定时器;【行列步队先容】
这里的行列步队不是独立的行列步队做事,而只是运用中坚持数据的一个行列步队,很多时候会是一个数组或者链表。
行列步队里面保存的也不是一个子任务,而只是一个数据,详细这个数据拿出来之后要启动什么子任务,这个行列步队是不关心的。
行列步队只是一个缓冲带,把更多的独立数据先临时保持住,运用系统有多大的能力消化接管就从里面用多快的速率进行处理。
从上面可以看出,行列步队比协程还要大略,都没有所谓各自独立的子任务,也就没有了独立的栈空间。
以是,这样的简化,也就带来了更少的资源开销,更少的任务调度。
接下来,我们结合实际中的几种运行模式来先容下现状和发展。
【多进程:php fast-cgi】php在利用fast-cgi之前,更多是多线程模式,为什么转而回到多进程模式呢?
多线程模式是为每个网络要求创建一个线程来处理这个要求,当要求实行结束,再销毁这个线程。
于是,当网站的要求量高的时候,意味侧重复的为这些要求创建和销毁线程,这个开销就变得比较大,效率也就低落了。
在多进程模式下,进程是复用的,不会反复的创建和销毁,以是就没有之前多线程模式那样大的资源摧残浪费蹂躏了。
当然,多进程的问题就像上面说到的,内存开销大,系统调度开销大,以是也就意味着并发量相对就会比较小。
以是,新的php swoole框架也把协程引入进来,同时把多路复用的epoll网络模型引入进来,这样就带来了很明显的好处。
1 协程占用内存小,可以同时坚持更多的并发要求。
2 epoll网络模型非壅塞而且系统开销少,可以更好的利用CPU资源,同时避免了网络IO壅塞影响整体的任务实行。
【多线程:java web】java多线程的运行模式用到线程池的技能,并不是每个要求都会启动一个线程来处理,而是复用线程池中的线程,这样也就类似上面php fast-cgi模式,很好的避免了线程频繁创建和销毁所带来的损耗。
线程比进程更轻量,以是单个线程的内存占用会比单个进程少,但是由于线程栈空间固定,在一些个别要求中,数据量很大,也可能会不得已要设置较大的栈空间,这样一来,内存摧残浪费蹂躏也是会比较严重了。
在之前的文章《认识IO的问题才能更好的设计和开拓出高并发和高性能的系统》,也有提到,java中更好支持IO密集型的框架,可以用netty,同样是支持多路复用的epoll模型,也简化了自己去实现NIO的过程。
kotlin.corouties 理解一下,简化的JAVA,1.3版本会发布协程的正式线上支持。
【协程:go】go原生的支持协程,并且有完善的协程调度器,让协程在开拓和运行时变得更加大略和高效。
作为新的开拓措辞,遍及还须要韶光,在网络编程的系统中,还是非常有竞争力的。
一步到位的支持高并发和高性能,说的太多就怕它骄傲了(站在巨人肩膀上,新思维、新技能)。
【行列步队:nginx】nginx实际是一个master+多个worker,也算是多进程模式。但是work是单线程的,却可以支持超高的网络并发量,这便是nginx内部实际便是一个网络事宜行列步队。
每个要求进来都是一个connection,然后这个connection就通过epoll_ctl注册到系统的网络IO事宜中,当connection的网络事宜准备好了才通过回调函数放到已就绪行列步队中。
而nginx便是epoll_wait不断的轮询这个就绪行列步队,然后再处理这里的事宜。
网络要求的处理又有很多的阶段,每个阶段又可以有多个nginx模块来处理,这些nginx模块便是各个真正的任务处理系统。
nginx除了反向代理以及作为静态WEB做事器,也可以作为运用做事器,比如利用ngx_lua模块,就可以对WEB要求做实时动态的处理,来完成一个动态做事。
这样一来,nginx把网络要求放到事宜行列步队中,ngx_lua利用协程把各个要求动态实行,也就可以高效的达到一个运用做事器的效果了,而且并发、性能也非常好。
【总结】
从上面几种模式中,我们都看到协程在新的框架、模块中用的越来越多,而且也确实能非常明显的提高系统的并发量。