• 如何构建高性能服务器(以Nginx为例)


    方法论

    软件层面

    增大CPU利用率
    • 使用全部CPU, worker进程数等于CPU

    • 进程间不做无用的切换

    • 繁忙时不主动让出CPU

    • worker进程之间不争抢CPU

    • CPU切换需要5us,如果大量进程需要切换,则CPU会浪费大量的时间切换,做无用功

    • worker进程绑定CPU

      pidstat -w可以查看某个进程的切换次数

    • 不被其他进程抢占资源

    • 提高进程优先级,获得更大的CPU时间片

    • 减少其他进程

    • 减少惊群

      场景:多个worker进程accept同一个端口时

      • 默认accept_mutex on

        多个worker进程争抢锁获得连接,同时只有一个worker获得连接

      • accept_mutex off

        一个连接请求唤醒所有worker进程,同时只有一个worker获得连接,存在惊群问题,当worker进程数不多时,影响不大,少了争锁,高并发时可以提高系统响应能力

      • SO_REUSEPORT

        内核3.9+处理大并发连接新特性,开启后,连接通过内核分配worker进程,性能最好

    • 提高CPU缓存命中率

      绑定worker到指定CPU: worker_cpu_affinity cpumask...

    增大内存利用率
    • 使用tcmalloc

      减少内存碎片

      并发能力高于glibc,并发数越多,性能越能体现(小内存分配)

      google-perftools/.../tcmalloc.html

      需要手动编译到nginx

    增大IO利用率
    • 对比

      机械硬盘

      • 价格低
      • 存储量大
      • BPS大,适合顺序读写
      • IOPS小,不适合随机读写
      • 寿命长

      固态应胖

      • 价格高
      • 存储量小
      • BPS大
      • IOPS大
      • 写寿命短
    • 优化读取

      • sendfile零拷贝

        文件直接从内核态的文件到socket的传递

        location /video/{
        	sendfile on;
        	aio on;
        	directio 8m;
        }
        
      • gzip_static

        提前压缩文件,加快gzip报文的返回

      • 内存盘/SSD盘

    • 减少写入

      • empty_gif

        使用返回一张1*1的空白图片,以减少http的返回报文长度

      • AIO

        在磁盘读写时,进程可以处理其他事情

        aio on|off|threads=[pool]

      • 直接IO,减少一次缓存的读写

        directio size|off 超过size则使用直接io,适合大文件

      • 增大error_log级别

      • error.log输出到内存

        error_log memory: 32m debug

        日志在32m的内存进行循环输出,只能看到32m的调试日志,可以提高性能

      • 关闭access_log

      • 压缩access_log

        access_log path [format] [gzip]

      • 是否开启proxy buffering

      • syslog替代本地io

        使用UDP写入代替io写入,提高性能

    • 线程池thread pool

      当某些io会阻塞时,使用线程池

    增大网络宽带利用率
    • syn重试次数

      net.ipv4.tcp_syn_retries = 6

    • 本地端口可用范围

      net.ipv4.ip_local_port_range=32768 60999

      可以放大

    • 连接超时

      proxy_connect_timeout

    • 接收连接最大个数(syn未完成握手)

      net.ipv4.tcp_max_syn_backlog = 262144

      可以适当放大

    • 已完成握手

      net.core.somaxconn:系统最大backlog队列长度

    • 超出队列可以接收报文直接回RST

      net.ipv4.tcp_abort_on_overflow

    • 未被内核处理的报文队列长度

      net.core.netdev_max_backlog

    • syn/ack重试次数

      net.ipv4.tcp_synack_retries

    • 处理syn攻击

      net.ipv4.tcp_syncookies=1

      当syn队列满后,新的syn不进入队列,计算出cookie返回客户端,客户端携带cookie重新连接,服务器验证cookie,通过则建立连接。回导致TCP可选功能失效,例如扩充窗口/时间戳等

    • 操作系统最大句柄

      fs.file-max: 操作系统可以使用最大句柄数

      使用fs.file-nr可以查看当前已分配/正使用/上限

    • 用户最大句柄数

      /etc/security/limits.conf

      root soft nofile 63535

      root har nofile 65535

    • 进程限制最大句柄数

      worker_rlimit_nofile number

    • 进程最大连接数

      worker_connections number

    • Tcp Fast Open

      当TCP再次连接时,通过携带cookie,减少一次syn/ack的rtt时间,达到快速建立TCP连接的目的

    nginxperformace-tfo
    net.ipv4.tcp_fastopen 0|1|2|3

    listen address [:port] [fastopen=number];

    fastopen=number为了防止带数据的syn攻击,限制最大长度,指定TFO连接队列的最大长度

    • TCP缓冲区

      net.ipv4.tcp_rmen = 4096 87380 6291456

      net.ipv4.tcp_wmen = 4096 87380 6291456

      net.ipv4.tcp_men = 1541646 2055528 3083292

      net.ipv4.tcp_moderate_rcvbuf=1开启自动调节缓存模式

      listen address [:port] [recvbuf=size] [sndbuf=size]

      net.ipv4.tcp_adv_win_scale = 1

      应用缓存 = buffer / (2^tcp_adv_win_scale)

      接收窗口 = buffer - buffer/(2^tcp_adv_win_scale)

      BDP = 带宽* RTT/2

      buffer=BDP

    • Nagle算法

      网络中只存在一个未被确认的小报文ACK

      目的:避免一个连接上存在大量的小报文,提高网络利用率

      吞吐量优先:启用Nagle tcp_nodelay off

      低延时优先:禁用Nagle tcp_nodelay on

    • 拥塞窗口

      实际流量=拥塞窗口和接收窗口的最小值

    • 慢启动

      指数扩展拥塞窗口cwnd = cwnd*2

    • 拥塞避免

      窗口大于threshold线性增大

    • 拥塞发生

      发生丢包,

      RTO超时,threshold = cwnd/2, cwnd=1

      Fast Retransmit: cwnd=cwnd/2, threshold=cwnd

    • 快速恢复

      当Fast Retransmit出现时,cwnd调整为threshold+3*MSS

    • 优化慢启动

      增大初始cwnd=10

    • TCP keep-alive

      开启keepalive可以探测到失去连接的socket,并即时关闭,节省系统资源

      net.ipv4.tcp_keepalive_time = 7200

      net.ipv4.tcp_keepalive_intvl = 75

      net.ipv4.tcp_keepalive_probes = 9

    • timewait

      net.ipv4.tcp_orphan_retries = 0

      net.ipv4.tcp_fin_timeout = 60

      net.ipv4.tcp_max_tw_buckets = 262144 最大timewait连接数,超出直接关闭连接

    • lingering_close延迟关闭

      当接收缓冲依然接收到客户端的内容,服务器如果马上发送RST关闭连接,会导致客户端由于接收到RST而忽略http response

      lingering_close off|on|always

      reset_timedout_connection on|off; 当读写超时生效依法连接关闭,通过发送RST马上关闭连接,以释放资源

    • TLS/SLL优化握手

      ssl_session_cache

    • TLS/SSL会话票证tickets

      Nginx将会话session中的信息作为tickets加密发送给客户端,当客户端再次建立连接时带上tickets,Nignx验证复用session

      优点可以减少对称加解密的次数,提高性能

      缺点降低安全性,需要经常更换tickets密钥

      ssl_seesion_tickets on|off

      ssl_session_ticket_key file

    • 使用HTTP长连接

      keepalive_request number;

    • gzip压缩

      提高网络传输效率

      gzip on|off

    • 使用http2

    统计函数调用统计

    google-perltool

    pprof --text|pdf

    goodle_perftools_profiles file

    硬件

    • 网卡:万兆网卡,例如10G/25G/40G
    • 磁盘:固态硬盘,关注IOPS/BPS指标
    • CPU:更快的主频,更大的缓存,更优的架构
    • 内存:更快的访问速度

    DNS

  • 相关阅读:
    MySQL-InnoDB锁(一)
    Java方法调用机制
    并发编程-锁相关的内存语义
    Java开发工具汇总
    并发编程-底层实现原理
    并发编程-Java内存模型
    JsonTest
    PTA(Basic Level)1034.有理数四则运算
    PTA(Advanced Level)1081.Rational Sum
    PTA(Advanced Level)1008.Elevator
  • 原文地址:https://www.cnblogs.com/kukafeiso/p/13957174.html
Copyright © 2020-2023  润新知