大家好,我身边的同事邻居都渐渐变羊了。但知北君的暗语依旧坚定。等待着杨的到来。相信羊过后,必有彩虹!如果很多资源没有从共享资源池中获取,就很容易造成内存泄漏和内存溢出。为了实现高并发和合理利用资源,大多数设计方案都会使用各种连接池、线程池等,所有可重用的资源都是从一组资源池中调用。也类似于近几年流行的共享经济,只不过共享经济在软件设计上类似于共享资源池。无需单独持有某项资源,需要使用时可在资源池中申请。下面就来看看各种资源共享池的一些配置和优化策略吧!1、废话不多说Tomcat中的各种连接。下面看一个简单的SpringBoottomcat配置服务器:tomcat:accept-count:500//accept队列长度max-connections:1000//最大连接线程数:max:200//最大工作线程数min-spare:10//最小工作线程数HTTPConnector的工作流程是这样的:每个非异步请求都需要一个线程来处理,如果并发请求大于当前可以处理的线程数,就会创建它额外的线程被创建用于处理,最多达到maxThreads的数量。此时仍然接收到较多的并发请求,Tomcat会接受新的连接,直到连接数达到最大连接数maxConnections。这时,这些连接就会在Connector中创建的服务器socket中排队,直到有线程可以处理这些连接。一旦上述排队数达到maxConnections,有新的请求进来,新的连接就会在OS中排队,操作系统提供的排队数为acceptCount。如果队列已满,后续传入的请求可能会被拒绝或超时。说一个食堂的例子:某学校有食堂,大厅里至少放了100把椅子(min-spare)供学生使用。吃一顿饭。但是,当有超过100名学生同时就餐时,食堂会增加一些椅子(创建线程),这些椅子不会立即收回,等一段时间无人使用后收回时间。但是食堂最多可以放500把椅子(maxThreads)。那么如果500多人同时就餐,其他人只能在大堂排队等待其他人吃完。食堂大厅可容纳1000人排队等候(maxConnections)。当食堂大厅满1000人时,只能在食堂外面排队,外面的排队永远最多200人(acceptCount)。这时候,如果再有人来吃饭,还是排不上去,他们会不耐烦(timeout),就会有人过来告诉后面的同学,别来了,已经满了,走吧去别处吃饭。(reject)通过上面的例子,相信大家可以理解tomcat的一些基本参数配置的作用,针对不同的情况进行调优。2ThreadPool每个人都熟悉Java线程池。下面是基本参数publicThreadPoolExecutor(intcorePoolSize,//核心线程数intmaximumPoolSize,//最大线程数longkeepAliveTime,//大于核心线程数的线程存活时间,如果没有newtask,会关闭TimeUnitunit,//TimeUnitBlockingQueueworkQueue,//线程等待队列ThreadFactorythreadFactory,//创建线程工厂RejectedExecutionHandlerhandler//拒绝策略){线程池基本运行原理介绍提交后任务交给线程池,线程池会检查线程池正在运行的线程数,如果线程数少于核心线程,则创建一个新线程来处理任务。如果线程池中的线程数达到corePoolSize的大小,则将该线程放入等待队列BlockingQueue。如果任务提交时连等待队列都满了,线程池会继续创建新的线程来处理任务,直到线程池数量达到maximumPoolSize。如果线程数达到最大容量,则执行拒绝策略。这里的线程池方案和tomcatConnector方案略有不同。前者是先排队,然后把池容量扩到最大,后者是先扩池,再排队两队。ThreadPoolExecutor线程池的理解我觉得结合工厂工人的例子更好理解。工厂成立。刚开始只有10个工人,后来工厂的工作岗位越来越多。招新工肯定不是最好的策略,多余的工作暂时只能等待和排队。(这个例子,工厂的工作量很大,肯定不可能马上招人,只能先排订单。)工厂里的业务越来越多,任务太挤了。原有职工已不能满足业务需要。向上。为了利益最大化,招新工势在必行,于是招新工,全体工友齐心协力,加快效率。当工厂的工人数量达到饱和时,新的业务不断增加。这个时候工厂已经饱和,没有办法继续接单。那我们只能采用其他方案(拒绝策略),另找一家工厂来做,或者新建工厂。当后续业务量比较小的时候,新招的worker会慢慢裁掉(一段时间不使用会关掉线程!)。线程池优化思路:如果线程需要执行的任务耗时较少,且属于HighCPU类型,可以根据CPU的核心数设置核心线程数。最大线程数不宜设置太大。线程队列可以根据使用场景设置大些,提高线程池的效率。如果线程需要执行的任务耗时较长,属于HighIO类型,依赖其他系统,CPU需要等待时间较长,核心线程数可以大一些,对应的线程队列长度也应该根据不同的使用场景进行调整。线程数不宜设置太大,否则会导致频繁GC。3、RestTemplate的坑与优化SpringBoot微服务与其他Restful资源交互时会用到RestTemplate。如果直接newRestTemplate,那么需要特别注意。使用不慎会造成内存泄漏,触发GC等。RestTemplate底层仍然使用org.apache.http包下的HttpClient。SpringBoot中可以通过PoolingHttpClientConnectionManager设置一些connectionpool的参数PoolingHttpClientConnectionManagerconnectionPoolManager=newPoolingHttpClientConnectionManager();connectionPoolManager.setMaxTotal(100);//最大连接数connectionPoolManager.setDefaultMaxPerRoute(200);//通过HttpRequestFactory可以设置connectTimeOut,connectionRequestTimeout,SocketTimeoutHttpComponentsClientHttpRequestFactoryhttpRequestFactory=新的HttpComponentsClientHttpRequestFactory();httpRequestFactory.setConnectionRequestTimeout(3000);//获取连接超时时间httpRequestFactory.setConnectTimeout(3000);//参考客户端与服务端建立连接的超时时间httpRequestFactory.setReadTimeout(120000);//读取数据超时时间期间总结了比较重要的参数如下:maxTotal:连接池的最大连接数defaultMaxPerRoute:默认每条路由接收的最大连接数socketTimeout:表示客户端与服务器建立连接后,客户端从服务端读取获取数据的超时时间,超时后会抛出SocketTimeOutException。connectionRequestTimout:指从连接池中获取连接的超时时间connectionTimeout:指客户端与服务端建立连接的超时时间。RestTemplate可以如下构造,参数也可以自定义从配置文件中导入。@BeanpublicRestTemplatebuildPoolingRestTemplate(RestTemplateBuilderbuilder){PoolingHttpClientConnectionManagerconnectionPoolManager=newPoolingHttpClientConnectionManager();connectionPoolManager.setMaxTotal(100);//最大连接数connectionPoolManager.setDefaultMaxPerRoute(200);//每条路由默认接收的最大连接数HttpClienthttpClient=HttpClientBuilder.create().setConnectionManager(connectionPoolManager).build();HttpComponentsClientHttpRequestFactoryhttpRequestFactory=newHttpComponentsClientHttpRequestFactory();httpRequestFactory.setHttpClient(httpClient);httpRequestFactory.setConnectionRequestTimeout(3000);//获取链接超时httpRequestFactory.setConnectTimeout(3000);//指客户端与服务端建立连接的超时时间httpRequestFactory.setReadTimeout(120000);//socketTimeout读取数据的超时时间returnbuilder.requestFactory(()->httpRequestFactory).build();}一些建议RestTemplate应该使用RestTemplateBuilde从资源池(PoolingHttpClientConnectionManager)中获取RestTemplater为maxTotal创建一个RestTemplate,defaultMaxPerRoute,可以增加maxTotal来增加并发量,但是也需要调整每个路由的最大并发连接数,这时候也可以增加一个路由的并发量connectionRequestTimeout和connectTimeout设置不宜太长,socketTimeout可以根据需求设置相应的时间。当然还有其他的优化,比如使用不同的ConnectionKeepAliveStrategy,设置maxIdleTime最大空闲时间等。总结本文总结了Tomcat、线程池、RestTemplate的一些日常优化策略。平时要多注意总结。在不同的情况下,优化参数是不同的。因此需要更多的测试才能获得最佳配置。看完这些,不妨在项目中尝试一下,增强记忆力。