Nginx性能优化

总结:

  1. 性能优化概述
  2. 压⼒测试⼯具
  3. 影响性能指标
  4. 系统性能优化
  5. Nginx性能优化

性能优化概述

在做性能优化前, 我们需要对如下进⾏考虑

  1. 当前系统结构瓶颈
    • 观察指标
    • 压⼒测试
  2. 了解业务模式
    • 接⼝业务类型
    • 系统层次化结构
  3. 性能与安全
    • 性能好安全弱
    • 安全好性能低

SOA

SOA粗暴理解:把系统按照实际业务,拆分成刚刚好大小的、合适的、独立部署的模块,每个模块之间相互独立

  • 有一个数据库,一个JavaWeb的网站客户端,一个安卓app客户端,一个IOS客户端。

  • 现在要从这个数据库中获取注册用户列表,如果不用SOA的设计思想,那么就会这样:

    JavaWeb里面写一个查询方法从数据库里面查数据然后在网页显示,安卓app里面写一个查询方法查询后在app上显示,IOS同样如此。

  • 这里就会出现查询方法重叠了,这样的坏处很明显了,三个地方都有相同的业务代码,要改三个地方都要改,而且要改的一模一样。当然问题不止这一个。

  • 于是乎出现了这样的设计思想,比如用Java单独创建一个工程部署在一台服务器上,并且写一个方法执行上述查询操作,然后使其他人可以通过某种途径(可以是http链接,或者是基于socket的RPC调用)访问这个方法得到返回数据,返回的数据类型是通用的json或者xml数据,就是说把这个操作封装到一个工程中去,然后暴露访问的方式,形成“服务”。比如这里就是注册用户服务,而关于注册用户的所有相关增删改查操作这个服务都会提供方法。

  • 这样一来,JavaWeb这边可以访问这个服务然后得到数据使用,安卓和IOS这里也可以通过这个服务得到数据。而且最重要的是,要修改关于注册用户的业务方法只要改这个服务就好了,很好的解耦。同理,其他业务比如商品、广告等业务都可以单独形成服务部署在单独服务器上。

  • 还有就是一旦哪天突然有一堆人要注册,假设这堆人仅仅只是注册而不做其他事情,其他业务比如商品、广告服务等都不忙,唯独注册这个功能压力很大,而原有的一台部署了注册服务的服务器已经承受不了这么高的并发,这时候就可以单独集群部署这个注册服务,提供多几台服务器提供注册服务,而其他服务还不忙,那就维持原样。

服务治理

  • 服务治理,就是当服务越来越多,调用方也越来越多的时候,它们之间的关系就变得非常混乱,需要对这些关系进行管理
  • 还是上面的例子,假如我有一个用户服务,一开始有调用方1和调用方2来使用这个服务,后来越来越多,将近上百个调用方,这个时候作为服务方,它只知道提供服务,却不知道具体为谁提供了服务。而对于开发者来说,知道这N多调用方和N多服务方之间的关系是非常重要的。
  • 所以这个时候就需要能进行服务治理的框架,比如dubbo+zookeeper,比如SpringCloud,有了服务治理功能,我们就能清晰地看到服务被谁谁谁调用,谁谁谁调用了哪些服务,哪些服务是热点服务需要配置服务器集群,而对这个服务集群的负载均衡也是服务治理可以完成的重要功能之一。
  • 实际上SOA只是一种架构设计模式,
  • 而SOAP、REST、RPC就是根据这种设计模式构建出来的规范,
  • SOAP通俗理解就是http+xml的形式
  • REST就是http+json的形式,
  • RPC是基于socket的形式。
  • CXF就是典型的SOAP/REST框架,dubbo就是典型的RPC框架,SpringCloud就是遵守REST规范的生态系统。

压⼒测试⼯具

安装压⼒测试⼯具 ab

1
yum	install	httpd-tools	-y
  • -n : 总的请求次数
  • -c : 并发请求数
  • -k : 是否开启⻓连接
1
ab -n 200 -c 2 http://127.0.0.1/

返回 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
Server Software: nginx/1.12.2
Server Hostname: 127.0.0.1
Server Port: 80
Document Path: /bgx.html
Document Length: 19 bytes
Concurrency Level: 200
# 总花费总时⻓
Time taken for tests: 1.013 seconds
# 总请求数
Complete requests: 2000
# 请求失败数
Failed requests: 0
Write errors: 0
Total transferred: 510000 bytes
HTML transferred: 38000 bytes
# 每秒多少请求/s(总请求出/总共完成的时间)
Requests per second: 9333.23 [/#sec] (mean)
# 客户端访问服务端, 单个请求所需花费的时间
Time per request: 101.315 [ms] (mean)
# 服务端处理请求的时间
Time per request: 0.507 [ms] (mean, across all concurrent requests)
# 判断⽹络传输速率, 观察⽹络是否存在瓶颈
Transfer rate: 491.58 [Kbytes/sec] received

影响性能指标

  1. ⽹络
    • ⽹络的流量
    • ⽹络是否丢包
    • 这些会影响http的请求与调用
  2. 系统
    • 硬件有没有磁盘损坏,磁盘速率
    • 系统负载、内存、系统稳定性
  3. 服务
    • 连接优化、请求优化
    • 根据业务形态做对应的服务设置
  4. 程序
    • 接⼝性能
    • 处理速度
    • 程序执⾏效率
  5. 数据库

系统性能优化

  • ⽂件句柄, Linux⼀切皆⽂件,⽂件句柄可以理解为就是⼀个索引
    • ⽂件句柄会随着我们进程的调用频繁增加
    • 系统默认对⽂件句柄有限制,不能让⼀个进程无限的调用
    • 需要限制每个进程和每个服务使用多大的⽂件句柄
    • ⽂件句柄是必须要调整的优化参数
  • 设置方式
    • 系统全局性修改
    • 用户局部性修改
    • 进程局部性修改

修改root用户的文件描述符限制

1
vim	/etc/security/limits.conf
1
2
3
//针对root用户
root soft nofile 65535
root hard nofile 65535
  • root用户
  • soft : 当文件描述符数量超出最大限制的时候会发出提醒
  • hard : 当文件描述符数量超出最大限制的时候直接中断旧的文件描述符
  • nofile : ⽂件描述符的数量配置项
  • 65535最⼤⼤⼩

修改全部用户的文件描述符限制

和root用户一样 , 修改/etc/security/limits.conf文件

1
vim	/etc/security/limits.conf
1
2
3
//所有用户,	全局
* soft nofile 25535
* hard nofile 25535

修改Nginx进程的文件描述符限制

配置/etc/nginx/nginx.confworker_rlimit_nofile选项

1
vim /etc/nginx/nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
user nginx
worker_processes 1;
worker_rlimit_nofile 45535;
error_log /var/log/nginx/error.log.warn
pid /var/run/nginx.pid

events {
worker_connections 1024;
}
http {

}

Nginx性能优化

CPU 亲和, 减少进程之间不断频繁迁移, 减少性能损耗

查看当前 CPU 物理状态

1
2
3
4
5
lscpu | grep "CPU(s)"
# CPU(s): 24
# On-line CPU(s) list: 0-23
# NUMA node0 CPU(s): 0,2,4,6,8,10,12,14,16,18,20,22
# NUMA node1 CPU(s): 1,3,5,7,9,11,13,15,17,19,21,23
  • 2颗物理cpu,
  • 每颗cpu12核⼼,
  • 总共24核⼼

将 Nginx worker 进程绑到不同的核心上

方式一

配置/etc/nginx/nginx.confworker_processes选项和worker_cpu_affinity选项

1
2
3
# 启动多少worker进程, 官方建议和cpu核心⼀致,
worker_processes 12;
worker_cpu_affinity 000000000001 000000000010 000000000100 000000001000 000000010000 000000100000 000001000000 000010000000 000100000000 001000000000 010000000000 10000000000;

方式二

1
2
worker_processes 2;
worker_cpu_affinity 101010101010 010101010101;

方式三 , 最佳绑定

1
2
worker_processes auto;
worker_cpu_affinity auto;

这里如果nginx是docker的,可以由docker容器绑到固定cpu上

查看 nginx worker 进程绑定至对应 cpu

1
2
3
4
5
ps -eo pid,args,psr|grep [n]ginx
# 9124 grep --color=auto nginx 0
# 18103 nginx: master process ./ngi 0
# 24065 nginx: worker process 0
# 24066 nginx: worker process 0

Nginx 通用优化配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 为了防止入侵,user设置为普通用户
user nginx;
# CPU亲和
worker_processes auto;
worker_cpu_affinity auto;
# 错误日志
error_log /var/log/nginx/error.log warn;
# nginx的进程文件
pid /run/nginx.pid;

# 文件描述符 , 调整⾄1w以上,负荷较⾼建议2-3w以上
worker_rlimit_nofile 35535;

events {
# 网络IO模型
use epoll;
# 限制每个进程能处理多少个连接请求,所以同时最多能处理10240x16个请求
worker_connections 10240;
}

http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 统一使用utf-8字符集
charset utf-8;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';
# access_log日志在http层 , 所有http连接都会到access_log
access_log /var/log/nginx/access.log main;

# Core module,开启文件传输
sendfile on;
# 静态资源服务器建议打开,传输数据包的效率更高
tcp_nopush on;
# 动态资源服务建议打开,需要打开keepalived,传输数据包的速度更快
tcp_nodelay on;
keepalive_timeout 65;

# Gzip module
gzip on;
# 在特定条件下不启用压缩(IE1-6对Gzip不友好,所以不压缩)
gzip_disable "MSIE [1-6]\.";
gzip_http_version 1.1;

# Virtal Server
include /etc/nginx/conf.d/*.conf;
}