《后端服务性能优化指南》
目录
一、 服务器操作系统 2
二、 web服务器/反向代理服务器(nginx) 2
三、 应用服务器(tomcat) 2
四、 应用日志配置 2
五、 数据库(mysql) 3
六、 数据库连接池 3
七、 Restfull服务调用 4
一、服务器操作系统
1、全局所有进程共享上限
查看系统配置最大句柄数 cat /proc/sys/fs/file-nr
修改: /etc/sysctl.conf
fs.file-max = 100000
net.ipv4.ip_conntrack_max = 100000
net.ipv4.netfilter.ip_conntrack_max = 100000
2、单进程最大句柄数
服务器默认配置为1024
查看最大进程数 ulimit -u
查看进程最大句柄数 ulimit -n
修改:/etc/security/limits.conf
* soft nofile = 32768
* hard nofile = 65536
对所有用户单线程最大可打开句柄,软限制32768,硬限制65536;
3、tcp连接存活时间,关闭连接时等待时间
修改/etc/sysctl.conf,添加如下几行:
#系統默认的TIMEOUT时间
net.ipv4.tcp_fin_timeout=30
#启重用,允许将TIME_WAIT sockets重新用于新的TCP连接 默认为0表示关闭
net.ipv4.tcp_tw_reuse=1
#开启TCP连接中TIME_WAIT sockets的快速回收 默认为0 表示关闭
net.ipv4.tcp_tw_recycle=1
4、使用uname -a命令查看系统内核版本,请确保linux系统内核版本高于2.6.28, 从此版本开始linux支持高效异步IO模型epoll,jdk的NIO开发包中含有对当 前操作系统版本号的判断(linux>2.6时调用epoll的native方法),java nio所 用的IO模型的实现方式由操作系统决定。
二、web服务器/反向代理服务器(nginx)
nginx.conf配置文件:
5、nginx单个工作进程最大建立外部连接数
worker_connections 16000
6、nginx进程最大可打开句柄数
worker_rlimit_nofile 65535
7、nginx工作进程数
worker_processes 8 [一般设置为CPU核数的双倍]
三、应用服务器(tomcat)
1、请将connector配置为NIO模式,并设置合适的最大连接数(springboot内嵌的tomcat默认就是NIO,最大连接数max-connections默认10000)
2、调整tomcat工作线程数与排队队列长度
server.tomcat.max-threads=800
server.tomcat.accept-count=200
四、应用日志配置
1、应用日志目前最佳实践为sl4j + logback,代码中应使用sl4j日志门面,禁止直接使用log4j等具体实现。
2、在某些高并发服务应考虑做日志异步优化,减少IO阻塞时间、提高CPU利用率:
<appender name="syslog"
class="ch.qos.logback.core.rolling.RollingFileAppender">
......
</appender>
<appender name="ASYNC_ROLLING_FILE" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>256</queueSize>
<includeCallerData>true</includeCallerData>
<appender-ref ref="syslog"/>
</appender>
<root level="INFO">
<!-- <appender-ref ref="STDOUT"/> -->
<appender-ref ref="ASYNC_ROLLING_FILE"/>
</root>
Logback提供的AsyncAppender使用内置的队列实现异步日志输出,默认256,为保证性能,超过该长度80%则开始丢弃error之外的日志。
属性名 |
类型 |
默认值 |
描述 |
queueSize |
int |
256 |
内置BlockingQueue的最大容量 |
discardingThreshold |
int |
-1 |
默认情况下,当blockingQueue的容量高于阈值时(80%),会丢弃ERROR以下级别的日志,如果不希望丢弃日志(既每次都是全量保存),那可以设置为0,但是如果队列满的时候,会丢弃所有插入队列的日志信息,所以建议设置为-1(默认值)。 如正常日志可以丢弃,那可以极大的提升性能,并保存关键的ERROR日志。 |
includeCallerData |
boolean |
false |
提取调用者数据的代价是相当昂贵的。为了提升性能,默认情况下,当event被加入到queue时,event关联的调用者数据不会被提取。默认情况下,只有"cheap"的数据,如线程名。比如日志中的代码行号如果需要输出则应将该值设为true。实测includeCallerData=true会带来一定性能下降,但高并发下仍远比同步日志方式的tps要高。 |
五、数据库(mysql)
在做压力测试的时候,发现了数据库连接数的限制,以及一些比较长慢查询,以下的配置主要解决这方面的问题
以下的数据库参数在/etc/my.cnf 中进行修改,数据库重启之后生效。
1、 数据库的最大连接数以及用户最大连接数的设置如下,
max_connections=1000(默认151)
max_user_connections=1000
2、查询过程中生成的临时表的大小可以通过tmp_table_size进行设置, max_heap_table_size在做连接查询的时候用到。参数max_heap_table_size比tmp_table_size小时,则系统会把max_heap_table_size的值作为最大的内存临时表的上限,大于这个时,改写硬盘,增加heap表的大小,可达到提高联接查询速度的效果。
如:
tmp_table_size=200M(默认16M)
max_heap_table_size=500M(默认16M)
3、read_buffer_size:是MySQL读入缓冲区大小,对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。如果对表的顺序扫描请求非常频繁,并且如认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。
如下的设置:
sort_buffer_size = 8M
read_buffer_size =8M
read_rnd_buffer_size = 8M
join_buffer_size,这个是跟join table 关联的,如:join_buffer_size = 8M。
六、数据库连接池
以tomcat-jdbc连接池为例,其他连接池如dbcp、c3p0、druid等类似;
1、core portal user identity几个应用的数据库连接池参数修改:user最大连接maxActive、最大空闲maxIdle 300,最小空闲minIdle、初始数initialSize 60;portalcoreidentity:最大连接、最大空闲100, 最小空闲、初始数20;其他应用初始5最大20
2、在生产环境请关闭testOnBorrow和testOnReturn(设置为false),失效连接主要通过testWhileIdle保证。
七、 Restfull服务调用
1、热点服务不允许直接使用jdk自带的java.net.URLConnection进行http client调用
2、推荐使用apache httpclient,okhttp等连接池模式的http库进行rest服务调用,减少反复建立连接的开销。基于spring技术栈的应用比较好的实践方式是使用restTemplate来配置上述实现方式。
3、Apache HttpClient Fluent API底层实现基于自家的httpclient连接池模式,其中代码写死了maxTotal和maxPerRoute所有请求会使用一个公共的连接池,总共200连接,每个destination最多100个连接。在高并发情况下会出现瓶颈,不推荐热点应用使用。