Web-Server有一个配置,工作线程的数量。服务一般也有一个配置,工作线程的数量。有经验的架构师知道如何配置这些参数以达到最佳的系统性能:有的服务设置为2倍CPU核心数,有的服务设置为8倍CPU核心数,有的服务设置为100%的CPU核心数。CPU核心数。32次。设置“线程数”的依据是本文要讨论的问题。工作线程数是否设置得越大越好?答案显然是否定的:服务器CPU核数有限,能并发的线程数有限。单核CPU设置1000个工作线程是没有意义的;线程切换有开销。如果线程切换过于频繁,会降低性能;调用sleep()函数,线程是否一直占用CPU?没有被占用,睡眠时会释放CPU给其他需要CPU资源的线程。不仅仅是sleep,一些阻塞调用,比如网络编程中:阻塞accept(),等待客户端连接;阻塞recv(),等待下行数据包;会放弃CPU资源。为单核CPU设置多线程有意义吗?单核CPU,多线程能否提高并发性能?即使是单核,使用多线程也是有意义的,在大多数情况下可以提高并发性:多线程编码可以让代码更清晰,例如:IO线程收发包,Worker线程执行任务处理,Timeout线程进行超时检测;if有任务一直在占用CPU资源进行计算。此时添加线程并不会增加并发。比如下面的代码会一直占用CPU,使CPU占用率达到100%:while(1){i++;一般来说,WorkerThreads一般不会一直占用CPU进行计算。即使CPU是单核,加入Worker线程也能提高并发性,因为当这个线程休息时,其他线程可以继续工作;有多少种常见的服务线程模型?理解常见的服务线程模型有助于理解服务并发的原理。一般来说,网上常见的服务线程模型有两种:IO线程和工作线程通过任务队列解耦;纯异步;第一个是IO线程,工作线程通过队列与类模型分离。如上图所示,大多数Web-Server和服务框架都采用这样一种“IO线程和Worker线程通过队列解耦”的线程模型:少数IO线程监听上游发来的请求,收发数据包。(制作人);有一个或多个任务队列,作为IO线程和Worker线程异步解耦的数据传输通道(关键资源);有多个工作线程执行真正的任务(消费者);这种线程模型应用非常广泛,适用于绝大部分场景。这种线程模型的特点是工作线程被同步阻塞执行任务,因此可以通过增加工作线程的数量来提高并发能力。今天讨论的重点是“本模型的Worker线程数设置为多少才能达到最大并发”。第二种是纯异步线程模型。没有阻塞,这种线程模型只需要设置少量的线程就可以达到高吞吐量。这种模式的缺点是:如果使用单线程模式,很难发挥多CPU多核的优势;程序员更习惯于编写同步代码和回调方法,对代码的可读性有影响,对程序员的要求更高;框架比较复杂,往往需要服务器端收发组件、服务器端队列、客户端收发组件、客户端队列、上下文管理组件、有限状态机组件、超时管理组件的支持;不过,这种模式并不是今天讨论的重点。第一类线程模型是“IO线程和工作线程通过队列解耦”。工作线程的工作模式是什么?了解工作线程的工作模式,对于线程数设置的量化分析很有帮助:上图是一个典型的工作线程处理流程,从开始处理到结束处理结束,共有7个步骤这个任务的处理:从工作队列中取出任务,进行一些本地的初始化计算,比如http协议解析,参数解析,参数校验等;访问缓存以获取一些数据;拿到缓存中的数据后,在本地进行一些计算,这些计算和业务逻辑相关;通过RPC调用下游服务获取一些数据,或者让下游服务处理一些相关的任务;RPC调用完成后,进行一些本地的计算,这个计算和业务逻辑有什么关系;访问数据库执行一些数据操作;操作完成后在数据库之后做一些收尾工作,这些收尾工作也是本地计算,和业务逻辑相关;分析整个处理的时间线,会发现:(1)其中,步骤1、3、5、7(上图中粉色时间线),线程在执行本地业务逻辑计算时需要占用CPU;(2)在步骤2、4、6(上图中橙色时间轴)中,线程在访问cache、service、DB的过程中,处于等待结果的状态。需要占用CPU,进一步分解,“等待结果”的时间分为三部分:请求在网络上传输到下游的缓存、服务、DB;下游缓存、服务、任务处理的DB;缓存、服务、DB将消息上传回网络上的工作线程;如何量化分析并合理设置工作线程数?通过以上分析,Worker线程执行过程中:部分计算时间需要占用CPU;另一部分等待时间不需要占用CPU;通过量化分析,比如打日志统计,可以统计整个Worker线程执行的过程。两部分时间的比例,例如:执行计算,CPU占用的时间(粉色时间轴)为100ms;等待时间,不占用CPU的时间(橙色时间轴)也是100ms;结果是这个线程计算和等待的时间是1:1,即50%的时间在计算(占用CPU),50%的时间在等待(不占用CPU):假设它此时是单核,设置为2个工作线程可以充分利用CPU。利用它,让CPU运行到100%;假设此时是N核,则设置为2N个工位充分利用CPU,让CPU跑到N*100%;当当当当!!!结论在这里:N核服务器通过业务的单线程执行分析本地计算时间为x,等待时间为y。工作线程数(线程池中的线程数)设置为N*(x+y)/x,可以最大化CPU的利用率。一般来说,非CPU密集型业务(加解密、压缩解压、搜索排序等业务是CPU密集型业务),瓶颈在后端数据库访问或RPC调用,本地CPU计算时间很少,所以设置几十个或几百个工作线程可以提高吞吐量。
