一、为什么要进行性能调优?
性能优化就是发挥机器本来的性能。
(说白了就是不要浪费钱,就是用最少的钱,希望满足一个很大批用户量,也就是物美价廉)
衡量的基本术语:
1)QPS:Query Per Second (一秒内可以处理的请求数量称之为服务器的QPS )
2)TPS:每秒钟处理完的事务次数,也就是一个应用系统1S能完成多少事务处 理,一个事务在分布式处理中,可能对应多个请求
举例:比如 对于一个页面的一次访问,形成一个TPS;但一次页面请求,可能产生多次对服务器的请求,服务器对这些请求,就可计入“QPS”之中。访问一个页面会请求服务器3次,对用户来说产生一个T,产生了3个Q
总结:QPS基本类似于TPS,对于衡量单个接口服务的处理能力,用QPS比较多
二、如何发现性能问题?
1、硬件层面
1)内存占用高
2)CPU占用高
3)网络是否发生拥堵了(带宽)
4)硬盘空间满
5)IO占用高
–从硬盘上读取到本机内存中
–从网络上接收信息到本机内存中
–从本机内存写出到硬盘或者网络
(内存:物理内存和虚拟内存,虚拟内存就是把计算的内存空间扩展到硬盘,如RAM和SWAP之间的交换增加了系统的负担)
2、软件层面
主要是通过查看日志文件(各类组件的日志文件)
nginx日志文件:access.log error.log
tomcat日志文件:
(win)catalina.log (linux)catalina.out:在里面可以看到启动的JVM参数以及操作系统等日志信息。
localhost_access_log.txt : 存放访问tomcat的请求的所有地址以及请求的路径、时间,请求协议以及返回码等信息
tomcat7-stderr.log: 这个是log4j的错误日志
tomcat7-stdout.log: 这个是程序中的system语句打印的日志(包含系统抛出的异常) 注意:系统中不能使用System.out
打印进行调试(debug),这些最后都会保存到日志文件浪费磁盘空间,log4j则可以通过控制level来控制是否打印(trace<debug<info<warn<error<fatal)
Jetty日志文件
Web应用日志文件:自定义的日志文件、gc.log 、dump文件
其他日志文件:mysql慢查询日志、solr日志等等
通过日志可以大致发现如下问题:
1)内存溢出
Java.lang.OutOfMemoryError
JVM分配的内存过小或者程序不严密,产生过多的垃圾
2)内存泄漏,对象未释放
老年代使用率一致持续过高,即使发生了多次full gc也不能降下来
3)线程阻塞、死锁
Blocked and Deadlock
4)线程死循环
一直Runnable
5)网络IO连接超时时间过长
建立连接:java.net.SocketTimeoutException: connect timed out
读取阻塞超时:java.net.SocketTimeoutException: Read timed out
6)磁盘不可写
分析两个问题:
1)一个线程发生OOM,其他线程还能运行么?
2)tomcat的假死现象
内存溢出
JVMGC时间过长,导致应用暂停
load太高,已经超出服务的极限了
应用程序出现死锁
大量tcp连接close_wait
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
tomcat线程数不够
三、从什么层面开始你的调优旅行?
1、硬件资源层面
纵向扩展:在单机的情况下,如果有钱可以升级下机器资源!
比如:
如果需要大量的图像计算,把CPU换成GPU
机械硬盘换成固态硬盘
等等
横向扩展:增加机器
2、软件层面
-
Linux系统
-
各种用户进程限制
ulimit -a 打印信息
重点关注:open files
修改命令:ulimit -n 4096,其默认值是1024
其他修改方式:/etc/security/limits.conf 或者 /etc/profile source /etc/profile等
(注意:系统级别的硬限制的查看命令 sysctl -a|grep file-max)例子: 由于solr中每次索引提交都会重新创建一个文件用于索引写入,如果你的索引提交频繁很频繁,那么你可能遇到“Too many open files”异常
-
socket最大的连接数
client最大tcp连接数
# sysctl -a | grep ipv4.ip_conntrack_max
net.ipv4.ip_conntrack_max = 20000
这表明系统将对最大跟踪的TCP连接数限制默认为20000。
# sysctl -a | grep ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 1024 30000server本地监听队列
net.core.somaxconn = 65535 #定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数 (默认是128)
net.ipv4.tcp_max_syn_backlog = 262144 #对于还未获得对方确认的连接请求,可保存在队列中的最大数目
net.core.netdev_max_backlog = 30000 #在每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目PS:最大的连接数也是受机器资源的限制,不可能无限大。还有每一个tcp连接 都要占一个文件描述符,一旦这个文件描述符使用完了, 新的连接到来返回给我们的错误是”Socket/File:Can't open so many files”。 这时你需要明白操作系统对可以打开的最大文件数的限制。 最后也是需要运营商带宽的支持!!!
-
tcp缓冲区大小 (读和写)
例如:
读缓冲区保存了远程主机发送过的数据,如果缓冲区已满,则数据会被放弃,写缓冲期保存了要发送到远程主机的数据,如果写缓冲区溢满,则系统的应用程序在写入数据时会阻塞
sysctl -w net.core.rmem max=l6777216
sysctl -w net.core .wmem max=l6777216
sysctl -w net.ipv4.tcp_rmem=“4096 87380 167772 16”
sysctl -w net.ipv4.tcp_wmem=“ 4096 16384 16777216 ”
-
tcp拥塞控制算法
算法对TCP传输速率的影响很大。丢包使的TCP传输速度大幅下降的主要原因是丢包重传机制,控制这一机制的就是TCP拥塞控制算法。
查看当前系统内核中可用的TCP拥塞控制算法有哪些:
sysctl net.ipv4.tcp_available_congestion_control
修改命令:sysctl -w net.ipv4.tcp_congestion_control = cubic到了这里,你是不是终于清楚为什么面试的时候,
有人会问你了不了解TCP/IP 协议? -
nginx
-
不记录不需要的日志
如:
location ~ .*.(js|jpg|JPG|jpeg|JPEG|css|bmp|gif|GIF)$ {
access_log off;
} -
nginx 缓存时间设置
-
worker_processes 8
nginx进程数,建议按照cpu数目制定 -
worker_rlimit_nofile 65535
这个指令时指当一个nginx进程打开的最多文件描述符数目,设置值为ulimit -n 与nginx进程数相除 -
worker_connections 65535
每个进程允许的最多连接数, 理论上每台nginx 服务器的最大连接数为worker_processes*worker_connections。
等等。。。。。。。。。。。。。。。。。。 -
tomcat
-
JVM 参数设置
(tomcat解压版)修改“%TOMCAT_HOME%\bin\catalina.bat”文件,在文件开头增加如下设置:(一定加在catalina.bat最前面)
set JAVA_OPTS=-Xms512m -Xmx512m
-XX:PermSize=128M -XX:MaxNewSize=256m
-XX:MaxPermSize=512m -
tomcat让其支持NIO
修改前:
protocol=“HTTP/1.1”
connectionTimeout=“20000” redirectPort=“8443”/>
修改成支持NIO的类型,配置如下 :
protocol="org.apache.coyote.http11.Http11NioProtocol
" connectionTimeout=“20000” redirectPort=“8443” /> -
并发数设置
maxThreads=“600” //最大线程数
minSpareThreads=“100” //初始化时创建的线程数
maxSpareThreads=“500” //一旦线程超过这个值,Tomcat会关闭不需要的socket线程
acceptCount=“700”//指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理
connectionTimeout=“20000”
redirectPort=“8443” /> -
maxConnections
这个值表示最多可以有多少个socket连接到tomcat上。NIO模式下默认是10000. -
禁用DNS查询
-
移除静态资源访问配置、移除defaultservlet、移除jspservlet 、移除session、 移除welcome-file-list、移除valve、移除accesslogvalve,可以通过nginx的access.log替代
2)下游软件(程序):如web应用、数据库(mysql\redis)、solr等
- mysql
缓存配置 - solr
JVM参数配置(堆外内存)、查询缓存大小配置 - web应用
JAVA代码优化:如IO资源使用完要关闭、sql查询使用索引、sql大数据排序时使用索引、调整业务逻辑等等