nginx设计中的性能优化点

一些指标

  • 10000个非活跃 http keep alive 连接在nginx消耗2.5MB内存
  • 单机支持10万以上并非连接

和nginx有关的内核调优:

可以修改/etc/sysctl.conf来更改内核参数调优

  • file-max: 一个进程最大可以打开的文件句柄数, 这个参数直接限制了nginx的最大并发连接数
  • tcp-tw-reuse: 设置为1时表示允许将time-wait状态的socket重新新的tcp连接。 ps. 内存方面现在linux已经优化的很好, 处于time-wait状态的socket只占用很少的内存, 释放/复用端口最重要, 毕竟端口数就就那些。
  • tcp-keepalive-time: 当keep-alive启用时,tcp发送keep-alive消息的频率, 默认两小时, 设置的低一些可以更快清理无效连接。
  • tcp_fin_timeout: 服务器主动断开连接时, socket保持在fin-wait-2状态的最大时间
  • tcp_max_sync_backlog: syn队列最大长度
  • ip_local_port_range: tcp/udp端口取值范围(是设置本地, 不能设置远端)
  • net.ipv4.tcp_rmem/net.ipv4.tcp_wmem: tcp接受/发送滑动窗口的最小值, 最大值, 默认值
  • netdev_max_backlog: 网卡接收数据包的速度大于内核处理速度时, 有一个队列保存这些数据包, 这个参数表示队列最大值
  • rmem_default/wmwm_default: 内核套接字接收/发送缓存区的默认大小
  • rmem_max/wmem_max: 内核套接字接收/发送缓存区的最大大小

nginx为访问第三方服务做的优化

在用nginx开发模块时,如果需要访问第三方服务, 不能自己简单的用套接字编程, 会破坏nginx全异步架构。nginx提供了两种全异步通信方式:
upstream: 它把nginx定义成代理服务器, 首要功能时透传。 nginx反向代理功能就是基于此。
subrequest用于处理请求派生出的子请求
两者区别: 比如实现频控模块要去redis读写数据, 这就是一个子请求, 在异步收到响应后, 如果通过频控, 就需要将请求透传给上游, 此时用upstream

配置搜索优化

server 配置通过hash表搜索
location块通过二叉树搜索, 因为是静态的,不会变, 所以不用红黑树, 用的完全平衡二叉树

内存池:

  • 用于减少系统调用次数;

  • 如何避免gc机制: 开发者申请一个内存池后可以从中任意申请内存, 最后用完销毁内存池即可。 nginx是一个web服务器, 每一个请求的生命周期很短, 也决定了每个内存池的生命周期短, 因此不会累积过多没有销毁的内存池。而在开发模块时,直接使用ngx_poll_t即可, 模块结束后自动释放。 ps. 感觉rust的生命周期, 所有权也是类似思想, 超过生命周期就销毁,只不过rust是语言去检查生命周期, nginx这里需要自己检查, 不用像go java需要另外线程/协程 去gc。

  • 申请大内存和小内存的不同处理: 当nginx判断申请内存大(x86 大于4095字节)的时候, 直接从堆上申请内存,挂到一个大内存链表上,大内存的生命周期可能远远小于请求的生命周期的情况就需要nginx考虑了, nginx提供了方法提前释放大类存而不用等到内存池销毁。
    小块内存niginx会一次申请比较大的一块, 后面复用。

  • 内存对齐,碎片整理: p281 ~ p283 重点看p283流程图

事件:

  • 网络事件: epoll
  • 定时事件器: 红黑树实现, 按照每个任务的时间来排序, 每次取最左边的节点的时间和当前时间判断即可。调用ngx_event_expire_timers方法触发所有超时事件。
  • 磁盘事件: linux 真.异步io,书里面吐槽了下glic里的异步io是多用户线程实现的,假异步io, 而nginx的读操作用的是linux内核实现, 只有在内核进程中完成了磁盘操作, 内核才会通知nginx进程。 这样的好处一方面是可以让nginx更充分占用cpu, 另一方面当有大量读磁盘的事件堆积到内核的时候,内核可以通过“电梯算法”降低随机读磁盘的成本。
    为啥是读操作采用异步而写操作不采用呢? 因为linux异步磁盘io写操作不支持缓存, 也就是每次用户进程都要写到磁盘上去, 这样更慢。

进程模型:

  • master-woker: nginx启动时master进程进行初始化读取配置文件后fork出worker进程来监听处理网络事件, 因为时fork出来的, 所以和master监听的是同意个端口, accept事件到来时会有争抢。

    • master进程不负责网络事件的监听和处理, 主要是负责启动服务, 平滑升级, 更换日志文件, 热更新配置等, 管理woker等功能。 是通过信号来管理woker进程。(说白了就是设置标志位)
    • woker进程监听和处理网络事件, 一个woker挂了时master会快速拉起一个新woker
    • 一个优化, nginx通常线程数和核心数相当, 可以配置进程绑定cpu, 减少进程在cpu间的越迁, 高效利用cpu cache
  • 惊群问题: nginx 会fork 多个子进程监听同一个端口, 子进程在accept建立新连接时会争抢,进程数量多时会有性能下降。
    开accept_mutex锁(默认打开)解决。 nginx通过一个进程间同步锁accept_mutex, 保证同一时刻只能由一个woker在监听web端口。释放锁通过定时器事件来实现。
  • 进程间负载均衡问题:多个woker抢一个事件时, 会有一个成功, 但如果这个woker本来就已经堆积了大量事件,另外有空闲进程或者任务少的进程抢不到事件, 子进程间就出现了负载不均衡。
    开accept_mutex锁解决(默认打开), 每个woker有个变量ngx_accept_disabled, 初始为负值,绝对值为配置的总连接数的7/8, 每次使用一个连接就加1。这个值为正时触发负载均衡,此时来accept事件时此woker不会去抢accept_mutex, 而是将ngx_accept_disabled 减一。 疑问, 为何是7/8?

TCP与ngixn(nginx基于tcp上的优化):

p342 全节重点

  • 基础知识:
  1. 三次握手时的syn, accept队列
  2. 用户进程在调用内核send方法时的的流程图 9-9
  3. recv方法的流程图3. recv方法的流程图
  • nginx的优化:
    用户可调整内核内存缓存的上限, p345 下面一段
    nginx也提供了内存自动调整功能, p347 图, 相当于多了几个阈值

再看upstream

  • client 到nginx和nginx到server间的网速是极不对称的, 反向代理的一个重要功能就是, 提供大内存和磁盘文件缓存包, 按照一定策略,接受完一定大小的包后, 再由nginx发给client或server。 这样做减少了server需要维持的连接和缓存的占用时间。
  • 与server:
    • 建立tcp连接三次握手是异步的, 发送syn后epoll注册事件监听, 设置回调函数
    • 向上游发送请求或者接收下游请求时, 请求大小未知,所以发送请求的方法需要被epoll调度多次后才能发/收完请求的全部内容。
    • 包头大小有一个合理范围, 而包体不一定,并且nginx不关心包体内容, 因此nginx将包头全部用内存缓存, 包体则根据情况而定
      -透传请求: nginx将client的请求包体全部接收完后才发给server
    • 透传响应: 可与配置三种模式:
      • 1.不转发响应(不实现反向代理)
      • 2.转发响应时上游网速优先: 若下游网速快于上游网速, 或者相差不大, 不需要nginx开辟大块内存或磁盘文件来缓存上游响应
      • 3.转发响应时下游网速优先: 开辟内存会磁盘缓存响应

《深入理解nginx》总结相关推荐

  1. STL源码剖析学习七:stack和queue

    STL源码剖析学习七:stack和queue stack是一种先进后出的数据结构,只有一个出口. 允许新增.删除.获取最顶端的元素,没有任何办法可以存取其他元素,不允许有遍历行为. 缺省情况下用deq ...

  2. 《STL源码剖析》学习-- 1.9-- 可能令你困惑的C++语法1

    最近在看侯捷的<STL源码剖析>,虽然感觉自己c++看得比较深一点,还是感觉还多东西不是那么明白,这里将一些细小的东西或者概念记录一下. 有些东西是根据<C++编程思想>理解的 ...

  3. 《STL源码剖析》学习--6章--_rotate算法分析

     最近在看侯捷的<STL源码剖析>,其中有许多不太明白之处,后经分析或查找资料有了些理解,现记录一下. <STL源码剖析>学习--6章--random access ite ...

  4. 《STL源码剖析》学习--6章--power算法分析

    最近在看侯捷的<STL源码剖析>,其中有许多不太明白之处,后经分析或查找资料有了些理解,现记录一下. 6章--power算法分析 书本中的算法如下所示: template <clas ...

  5. STL源码剖析——P142关于list::sort函数

    在list容器中,由于容器自身组织数据的特殊性,所以list提供了自己的排序函数list::sort, 并且实现得相当巧妙,不过<STL源码剖析>的原文中,我有些许疑问,对于该排序算法,侯 ...

  6. STL源码剖析---红黑树原理详解下

    转载请标明出处,原文地址:http://blog.csdn.net/hackbuteer1/article/details/7760584       算法导论书上给出的红黑树的性质如下,跟STL源码 ...

  7. STL源码剖析面试问题

    当vector的内存用完了,它是如何动态扩展内存的?它是怎么释放内存的?用clear可以释放掉内存吗?是不是线程安全的? vector内存用完了,会以当前size大小重新申请2* size的内存,然后 ...

  8. STL源码剖析学习二:空间配置器(allocator)

    STL源码剖析学习二:空间配置器(allocator) 标准接口: vlaue_type pointer const_pointer reference const_reference size_ty ...

  9. STL源码剖析 数值算法 copy 算法

    copy复制操作,其操作通过使用assignment operator .针对使用trivial assignment operator的元素型别可以直接使用内存直接复制行为(使用C函数 memove ...

  10. STL源码剖析 算法开篇

    STL源码剖析 算法章节 算法总览_CHYabc123456hh的博客-CSDN博客 质变算法 质变算法 - 会改变操作对象的数值,比如互换.替换.填写.删除.排列组合.分隔.随机重排.排序等 #in ...

最新文章

  1. DirectShow camera demo
  2. python代码基础题-python每日经典算法题5(基础题)+1(中难题)
  3. OpenCV 开闭运算
  4. 和我一起学Windows Workflow Foundation(1)-----创建和调试一个WF实例(转)
  5. 计算机裸机与应用程序及用户之间的桥梁是,2016计算机二级《MS Office》单选试题与解析...
  6. 《天天数学》连载18:一月十八日
  7. Python 机器学习 利用sklearn构建决策树的实现 2
  8. ubuntu安装最新版blender方法
  9. vim编辑器在Linux系统中的用法
  10. 计算机网络管理公开课观后感,青年网络公开课观后感
  11. Matplotlib之直方图绘制
  12. matlab containers,matlab中的containers.Map()
  13. OpenBmc开发13:添加传感器(fan)
  14. 第六讲 复数和复指数
  15. 赵小楼《天道》《遥远的救世主》深度解析(29)优秀的传统文化和弱势思想观念的转变
  16. 数据库防火墙技术展望【终章】
  17. 和游戏服务器的连接中断错误 1,绝地求生“与Steam服务器连接时出现了一个问题”怎么解决...
  18. plsql导出查询结果
  19. 新浪微博PC客户端(DotNet WinForm版)—— 初探
  20. 哪些App适合用HTML5开发?

热门文章

  1. 凸包算法(Convex Hull Algorithm)
  2. mysql解压版安装步骤
  3. 如何使用反编译软件得到源码
  4. python和按键精灵哪个稳定_按键精灵教程,学了这个你也能做出稳定的脚本
  5. modelsim安装_Modelsim10.5安装教程
  6. Python的包管理工具
  7. 2010 模板下载 罗斯文_利用模板建立ACCESS数据库—ACCESS图解操作系列(二)
  8. python处理access数据库教程_Python操作Access数据库基本操作步骤分析
  9. 王爽《汇编语言》笔记(详细)
  10. LINUX移植——内核移植(一)