电子商务网站建设预算表,iis 架设 wordpress,本溪市做网站公司,微信小程序api文档前言
前两天面试的时候#xff0c;面试官问我#xff1a;一个ip发请求过来#xff0c;是一个ip对应一个线程吗#xff1f;我突然愣住了#xff0c;对于SpringBoot如何处理请求好像从来没仔细思考过#xff0c;所以面试结束后就仔细研究了一番#xff0c;现在就来探讨一…前言
前两天面试的时候面试官问我一个ip发请求过来是一个ip对应一个线程吗我突然愣住了对于SpringBoot如何处理请求好像从来没仔细思考过所以面试结束后就仔细研究了一番现在就来探讨一下这个问题。
正文
我们都知道SpringBoot默认的内嵌容器是Tomcat也就是我们的程序实际上是运行在Tomcat里的。所以与其说SpringBoot可以处理多少请求到不如说Tomcat可以处理多少请求。
关于Tomcat的默认配置都在spring-configuration-metadata.json文件中对应的配置类则是org.springframework.boot.autoconfigure.web.ServerProperties。 和处理请求数量相关的参数有四个 server.tomcat.threads.min-spare最少的工作线程数默认大小是10。该参数相当于长期工如果并发请求的数量达不到10就会依次使用这几个线程去处理请求。server.tomcat.threads.max最多的工作线程数默认大小是200。该参数相当于临时工如果并发请求的数量在10到200之间就会使用这些临时工线程进行处理。server.tomcat.max-connections最大连接数默认大小是8192。表示Tomcat可以处理的最大请求数量超过8192的请求就会被放入到等待队列。server.tomcat.accept-count等待队列的长度默认大小是100。
举个例子说明一下这几个参数之间的关系 如果把Tomcat比作一家饭店的话那么一个请求其实就相当于一位客人。min-spare就是厨师(长期工)max是厨师总数(长期工临时工)max-connections就是饭店里的座位数量accept-count是门口小板凳的数量。来的客人优先坐到饭店里面然后厨师开始忙活如果长期工可以干的完就让长期工干如果长期工干不完就再让临时工干。图中画的厨师一共15人饭店里有30个座位也就是说如果现在来了20个客人那么就会有5个人先在饭店里等着。如果现在来了35个人饭店里坐不下就会让5个人先到门口坐一下。如果来了50个人那么饭店座位门口小板凳一共40个所以就会有10人离开。
也就是说SpringBoot同时所能处理的最大请求数量是max-connectionsaccept-count超过该数量的请求直接就会被丢掉。
纸上得来终觉浅绝知此事要躬行。
上面只是理论结果现在通过一个实际的小例子来演示一下到底是不是这样
创建一个SpringBoot的项目在application.yml里配置一下这几个参数因为默认的数量太大不好测试所以配小一点 server:tomcat:threads:# 最少线程数min-spare: 10# 最多线程数max: 15# 最大连接数max-connections: 30# 最大等待数accept-count: 10再来写一个简单的接口 GetMapping(/test)public Response test1(HttpServletRequest request) throws Exception {log.info(ip:{},线程:{}, request.getRemoteAddr(), Thread.currentThread().getName());Thread.sleep(500);return Response.buildSuccess();}代码很简单只是打印了一下线程名然后休眠0.5秒这样肯定会导致部分请求处理一次性处理不了而进入到等待队列。
然后我用Apifox创建了一个测试用例去模拟100个请求 观察一下测试结果 从结果中可以看出由于设置的 max-connectionsaccept-count 的和是40所以有60个请求会被丢弃这和我们的预期是相符的。由于最大线程是15也就是有25个请求会先等待等前15个处理完了再处理15个最后在处理10个也就是将40个请求分成了15,15,10这样三批进行处理。 再从控制台的打印日志可以看到线程的最大编号是15这也印证了前面的想法。
总结一下如果并发请求数量低于server.tomcat.threads.max则会被立即处理超过的部分会先进行等待如果数量超过max-connections与accept-count之和则多余的部分则会被直接丢弃。
延伸并发问题是如何产生的
到目前为止就已经搞明白了SpringBoot可以同时处理多少请求的问题。但是在这里我还想基于上面的例子再延伸一下就是为什么并发场景下会出现一些值和我们预期的不一样
设想有以下场景厨师们用一个账本记录一共做了多少道菜每个厨师做完菜都记录一下每次记录都是将账本上的数字先抄到草稿纸上计算x1等于多少然后将计算的结果写回到账本上。 Spring容器中的Bean默认是单例的也就是说处理请求的Controller、Service实例就只有一份。在并发场景下将cookSum定义为全局变量是所有线程共享的当一个线程读到了cookSum20然后计算写回前另一个线程也读到是20两个线程都加1后写回最终cookSum就变成了21但是实际上应该是22因为加了两次。 private int cookSum 0;GetMapping(/test)public Response test1(HttpServletRequest request) throws Exception {// 做菜。。。。。。cookSum 1;log.info(做了{}道菜, cookSum);Thread.sleep(500);return Response.buildSuccess();}如果要避免这样的情况发生就涉及到加锁的问题了就不在这里讨论了。 作者Robod 链接https://juejin.cn/post/7203648441721126972 来源稀土掘金