<font size=3 face="黑体" >疯狂创客圈 Java 高并发【 亿级流量聊天室实战】实战系列 【 博客园总入口 】</font >
疯狂创客圈 (笔者尼恩创建的高并发研习社群)Springcloud 高并发系列文章,将为大家介绍三个版本的 高并发秒杀:
一、 版本1 :springcloud + zookeeper 秒杀
二、版本2 :springcloud + redis 分布式锁秒杀
三、版本3 :springcloud + Nginx + Lua 高性能版本秒杀
以及有关Springcloud 几篇 核心、重要的文章 :
一、 Springcloud 配置, 史上最全 一文全懂
二、 Springcloud 中 SpringBoot 配置全集 , 收藏版
三、 Feign Ribbon Hystrix 三者关系 , 史上最全 深度解析
四、 SpringCloud gateway 详解 , 史上最全
五、 图解:tomcat的maxConnections、maxThreads、acceptCount | 秒懂
本文,是《tomcat的maxConnections、maxThreads、acceptCount》篇 ,为大家解读tomcat的maxConnections、maxThreads、acceptCount, 大家可以藏好,一定有用的到时候 。
首先,这和tomcat的使用的IO模式有关
关于Java IO模式、以及IO处理的线程模型等基础的通信框架的知识,是Java程序员的重要、必备的内功,具体请参见尼恩编著的《Netty、Zookeeper、Redis高并发实战》一书,这里不做过多的赘述。
其次,也和tomcat的配置参数有关
尤其是以下三个配置项:maxConnections、maxThreads、acceptCount。
tomcat中maxConnections、maxThreads、acceptCount的具体含义是什么呢?参考官方文档,对三者的含义说明如下:
官方文档的说明为:当所有的请求处理线程都在使用时,所能接收的连接请求的队列的最大长度。当队列已满时,任何的连接请求都将被拒绝。accept-count的默认值为100。
详细的来说:当调用HTTP请求数达到tomcat的最大线程数时,还有新的HTTP请求到来,这时tomcat会将该请求放在等待队列中,这个acceptCount就是指能够接受的最大等待数,默认100。如果等待队列也被放满了,这个时候再来新的请求就会被tomcat拒绝(connection refused)。
官方文档的说明为:
这个参数是指在同一时间,tomcat能够接受的最大连接数。对于Java的阻塞式BIO,默认值是maxthreads的值;如果在BIO模式使用定制的Executor执行器,默认值将是执行器中maxthreads的值。对于Java 新的NIO模式,maxConnections 默认值是10000。
对于windows上APR/native IO模式,maxConnections默认值为8192,这是出于性能原因,如果配置的值不是1024的倍数,maxConnections 的实际值将减少到1024的最大倍数。
如果设置为-1,则禁用maxconnections功能,表示不限制tomcat容器的连接数。
maxConnections和accept-count的关系为:当连接数达到最大值maxConnections后,系统会继续接收连接,但不会超过acceptCount的值。
每一次HTTP请求到达Web服务,tomcat都会创建一个线程来处理该请求,那么最大线程数决定了Web服务容器可以同时处理多少个请求。maxThreads默认200,肯定建议增加。但是,增加线程是有成本的,更多的线程,不仅仅会带来更多的线程上下文切换成本,而且意味着带来更多的内存消耗。JVM中默认情况下在创建新线程时会分配大小为1M的线程栈,所以,更多的线程异味着需要更多的内存。线程数的经验值为:1核2g内存为200,线程数经验值200;4核8g内存,线程数经验值800。
明白了 Tomcat的maxConnections、maxThreads、acceptCount三大配置之后,可以通过application.yml配置文件来改变这个三个值,一个标准的示例如下:
maxConnections、maxThreads、acceptCount关系之间,具体的关系如何呢? 在疯狂创客圈社群中,有不少的同学对于这个问题是云里雾里的,并且多次进行求助。这里用一个形象的比喻,通俗易懂的解释一下tomcat的最大线程数(maxThreads)、最大等待数(acceptCount)和最大连接数(maxConnections)三者之间的关系。
我们可以把tomcat比做一个火锅店,流程是取号、入座、叫服务员,可以做一下三个形象的类比:
(1)acceptCount 最大等待数
可以类比为火锅店的排号处能够容纳排号的最大数量;排号的数量不是无限制的,火锅店的排号到了一定数据量之后,服务往往会说:已经客满。
(2)maxConnections 最大连接数
可以类比为火锅店的大堂的餐桌数量,也就是可以就餐的桌数。如果所有的桌子都已经坐满,则表示餐厅已满,已经达到了服务的数量上线,不能再有顾客进入餐厅了。
(3)maxThreads:最大线程数
可以类比为厨师的个数。每一个厨师,在同一时刻,只能给一张餐桌炒菜,就像极了JVM中的一条线程。
(1)取号:如果maxConnections连接数没有满,就不需要取号,因为还有空余的餐桌,直接被大堂服务员领上餐桌,点菜就餐即可。如果 maxConnections 连接数满了,但是取号人数没有达到 acceptCount,则取号成功。如果取号人数已达到acceptCount,则拿号失败,会得到Tomcat的Connection refused connect 的回复信息。
(2)上桌:如果有餐桌空出来了,表示maxConnections连接数没有满,排队的人,可以进入大堂上桌就餐。
(3)就餐:就餐需要厨师炒菜。厨师的数量,比顾客的数量,肯定会少一些。一个厨师一定需要给多张餐桌炒菜,如果就餐的人越多,厨师也会忙不过来。这时候就可以增加厨师,一增加到上限maxThreads的值,如果还是不够,只能是拖慢每一张餐桌的上菜速度,这种情况,就是大家常见的“上一道菜吃光了,下一道菜还没有上”尴尬场景。
最后,介绍一下疯狂创客圈: 疯狂创客圈,一个Java 高并发研习社群 【 博客园 总入口 】
疯狂创客圈,倾力推出: 面试必备 + 面试必备 + 面试必备 的基础原理+实战 书籍 《 Netty Zookeeper Redis 高并发实战 》
Tomcat 作为 Java Web 程序比较常用的 Servlet 容器实现,在 Web 开发中有比较重要的地位。
Tomcat 有三种 IO 模式,BIO、NIO、APR。
在 Tomcat7 及以下 Linux 中默认启用的是 BIO 模式,Tomcat8 及以上使用的是 NIO 模式,利用 Java 的异步 IO 处理,可以通过少量的线程处理大量的连接请求。
除这两种方式外,还有一种 APR(Apache Portable Runtime) 模式,从 *** 作系统层面解决 IO 阻塞问题。Tomcat7 或Tomcat8 在 Win7 或以上的系统中启动默认使用这种方式。
要注意的是,在 SpringBoot 内嵌的 Tomcat 不自动开启 APR 模式,需要手动进行配置。
可以通过启动日志看到 SpringBoot 中启用的 IO 模式:
关于 BIO、NIO、APR 的详解不做过多介绍。
这个参数是指在同一时间,Tomcat 能够接受的最大连接数。对于 Java 的阻塞式 BIO,默认值是 maxthreads 的值;可以通过配置 Executor 执行器来修改这个值。
对于 Java 新的 NIO 模式,maxConnections 默认值是 10000。
对于 windows 上 APR/native IO模式,maxConnections 默认值为 8192,这是出于性能原因,如果配置的值不是 1024 的倍数,maxConnections 的实际值将减少到 1024 的最大倍数。
如果设置为 -1,则禁用 maxconnections 功能,表示不限制tomcat容器的连接数。
简单来说就是 Tomcat 总共允许建立多少连接。
每一次 Http 请求到达 Web 服务,Tomcat 都会创建一个线程来处理该请求,最大线程数决定了 Web 服务同时可以处理多少请求。maxThreads 默认值为 200,建议增加,但是增加线程是有成本的,更多的线程代表会有更多的上下文切换,也意味着 JVM 会分配更多的内存。
当 Tomcat 的最大连接数 maxConnections 被占满之后,后续的请求就会进行排队,排队的最大数量就是 acceptCount,举个例子,当前 maxConnections 为 10,acceptCount 为 5,并且 maxConnections 已经使用了 10,那么后续的请求就会排队,每来一个请求,acceptCount 就会 +1 ,当 acceptCount 增加到 5 ,在后续的请求就会被直接放弃。
HTTP 协议运行在 TCP 之上,所以每次请求到来,客户端和服务端会建立一次 TCP 连接,建立连接需要三次握手,所以就需要一定的时间,connection-timeout 限制了连接建立的时间,当建立连接时间超过这个值,连接就会建立失败。默认为 20000ms。
常用配置:
我们可以把 Tomcat 比作餐厅,餐厅有排队取号区域,餐桌,厨房,厨师。
maxConnections 可以类比为餐桌数量,acceptCount 可以类比为排队取号队列长度,maxThreads 可以类比为厨房里厨师的数量。
当客人来的时候,如果餐桌数量没坐满,客人可以直接上餐桌点餐,点餐之后,厨师就会做这一桌的食物,一个厨师同时只能为一桌服务。
当客人来的时候,如果餐桌坐满了,就需要去排队取号区排队取号,如果取号区人也排满了,餐厅就会赶你走。
由于厨师数量可能少于餐桌的数量,所以会出现多个厨师负责多个餐桌的情乱,也就是线程数量不够,连接等待处理的情况。
SpringBoot 配置:
接口定义(模拟处理需要 5 秒):
使用 Jmeter 同时使用 50 个线程访问测试:
查看测试报告:
测试结果:
只有两个请求请求成功,因为最大连接数为1 ,排队数量为 1,所以最多只能处理两个请求,其余的 48 个请求直接被丢弃。
java性能优化原则:代码运算性能 内存回收 应用配置(影响java程序注意原因是垃圾回收)
代码层优化:避免过多的循环嵌套 调用和复杂逻辑
Tomcat调优主要内容
1.增加最大连接数
2.调整工作模式
3.启用gzip压缩
4.调整JVM内存大小
5.作为web服务器时 与Apache整合或Nginx
6.合理选择垃圾回收算法
7.尽量使用较新版的JDK
生产环境实例
<connector p=""
maxThreads="1000"
minSpareThreads="100"
maxSpareThreads="200"
acceptCount="900"
disableUploadTimeout="true"
connectionTimeout="20000"
URIEncoding="UTF-8"
enableLookups="false"
redirectPort="8443"
compression="on"
compressionMinSize="1024"
compressableMimeType="text/html,text/xml,text/css,text/javascript"/>
参数说明:
org.apache.coyote.http11.Http11NioProtocol:调整工作模式为Nio
maxThreads:最大线程数,默认150。增大值避免队列请求过多,导致响应缓慢。
minSpareThreads:最小空闲线程数
maxSpareThreads:最大空闲线程数,如果超过这个值,会关闭无用的线程。
acceptCount:当处理请求超过此值时,将后来请求放到队列中等待。
disableUploadTimeout:禁用上传超时时间
connectionTimeout:连接超时,单位毫秒,0代表不限制
URIEncoding:URI地址编码使用UTF-8
enableLookups:关闭dns解析,提高响应时间
compression:启用压缩功能
compressionMinSize:最小压缩大小,单位Byte
compressableMimeType:压缩的文件类型
Tomcat的三种工作模式: Bio、Nio和Apr 工作原理分别为
Bio(Blocking I/O):默认工作模式 阻塞式I/O *** 作 没有任何优化技术处理 性能比较低
Nio(New I/O or Non-Blocking):非阻塞式I/O *** 作 有BIO更好的并发处理性能
Apr(apache portable runtime,apache可移植运行库):首选工作模式 主要为上层的应用程序提供一个可以跨越多 *** 作系统平台使用的底层支持接口库
Tomcat利用基于APR库Tomcat-native来实现 *** 作系统级别控制 提供一种优化技术和非阻塞式I/O *** 作 大大提高并发处理能力
但是需要安装APR和Tomcat-native库
Java性能问题主要来自于jvm jvm GC也比较复杂
1、jvm内存划分为年轻代(Young Generation)、年老代 Old Generation)、永久代(Permanent Generation)
2、年轻代又分为Eden和Survivor区。Survivor区由FromSpace和ToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认8:2
3、堆内存Heap=年轻代+年老代 非堆内存=永久代
4、堆内存用途:存放的是对象 垃圾收集器就是收集这些对象的 然后根据GC算法回收
5、非堆内存用途:JVM本身使用 存放一些类型 方法 常量 属性等
6、年轻代:新生成的对象首选放到年轻代的E区中 当E区满时 经过GC后 还存活的对象被复制到Survivor区的FromSpace中 如果survivor区满
会再被复制到survivor区的ToSpace区 如果还有存活的对象 会再被复制到老年代
7、老年代:在年轻代中经过GC后还存活的对象会被复制到老年代中 当老年代空间不足时 jvm会对老年代进行完全的垃圾回收(Full GC)
如果GC后 还是无法存放从survivor区复制过来的对象 就会出现OOM
8、永久代:也称为方法区 存放静态类型数据 比如类 方法 属性等
垃圾回收算法
1、标记 清除
2、复制
3、标记 整理
垃圾收集器
单线程/多线程收集器
GMS收集器
JAVA_OPTS="-server -Xms1024m -Xmx1536m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:+UseParallelGCThreads=8 XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:-PrintGC -XX:-PrintGCDetails -XX:-PrintGCTimeStamps -Xloggc:../logs/gc.log"
参数 描述
-Xms 堆内存初始大小 单位M、G
-Xmx 堆内存最大允许大小 一般不要大于物理内存的80%
-XX:PermSize 非堆内存初始大小 一般应用设置初始化200M 最大1024M就够了
-XX:MaxPermSize 非堆内存最大允许值
-XX:+UseParallelGCThreads=8 并行收集器线程数 同时有多少个线程进行垃圾回收 一般与CPU数量相等
-XX:+UseParalle101dGC 指定老年代为并行收集
-XX:+UseConcMarkSweepGC CSM收集器
-XX:+UseCMSCCompactAtFullCollection 开启内存空间压缩和整理 防止过多内存碎片
-XX:CMSFullGCsBeforeCompaction=0 表示多少次Full GC后开始压缩和整理 0表示每次Full GC后立即执行压缩和整理
-XX:CMSInitiatingOccupancyFracetion=80% 表示老年代内存空间使用80%时开始执行CMS收集 防止过多的Full GC
注意:不是jvm内存设置越大越好 具体还是根据项目对象实际占内存大小而定 可以通过java自带的分析工具来查看
如果设置过大 会增加回收实际 从而增加暂停应用时间
gzip压缩作用:节省服务器流量和提高网站访问速度 客户端请求服务器资源后 服务器将资源文件压缩 再返回给客户端 有客户端的浏览器负责压缩并浏览
Apache和Tomcat结合
由于Tomcat处理静态文件能力远远不足Apache 所有用Apache处理静态文件 Tomcat负责处理jsp
session会话的保持
TomcatSessionID持久化三种方法
session粘性:通过浏览器cookie绑定sessionID 通过sticky模式将同一session请求分片到同一Tomcat上
session复制:tomcat通过广播形式将session同步到其它Tomcat节点 并且Linux下要手动开启开放广播地址 不宜后端节点过多
session保持数据库(memcache redis):将sessionID保存在共享的数据库中
OOM异常的几个原因
老年代内存不足:java.lang.OutOfMemoryError:Javaheapspace
永久代内存不足:java.lang.OutOfMemoryError:PermGenspace
代码bug 占用内存无法及时回收
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)