LNMP架构下WEB服务器如何管理及优化内存?

简介: Ngnix+PHP-FPM的工作方式,似乎是LNMP架构最节省系统资源的工作方式。当然,具体的技术选型更多的应该参考自己想要实现的业务需求。

总结


  1. Ngnix+PHP-FPM的工作方式,似乎是LNMP架构最节省系统资源的工作方式。
  2. 当然,具体的技术选型更多的应该参考自己想要实现的业务需求。


1. 原因:越来越多的并发连接数


  1. 页面的元素增多,交互复杂
  2. 主流浏览器的连接数在增加


2. 辅助方案:通过WEB前端优化,降低服务器的压力


  1. 减少web请求
  2. 减轻web请求
  3. 合并页面请求


3. 推荐方案:节约web服务器的内存


  1. prefork MPM(Apache服务器多道处理器模块),多进程工作模式:
  1. 主进程生成后,他先完成初始化的工作,通过fork的方式预先产生一批子进程(子进程复制父进程的内存空间,不需要再做初始化的工作)
  2. 多进程的好处:进程之间的内存数据是互不干扰的。
  3. 优点:成熟稳定,兼容新老版本,不用担心线程安全的问题
  4. 缺点:不适合高并发的业务场景,一个服务进程占很多内存
  1. worker MPM, 多线程和多进程的混合模式
  1. 和prework一样,也预先fork了几个子进程(数量少),然后每个子进程创建几个线程(包含一个监听线程)。每个请求过来,会交给一个线程来服务。(线程比进程轻量级,所以内存占用更少)。
  2. 注意:并没有解决“keep-alive”长连接的问题,只是把对象编程了更轻量级的线程
  3. 疑问:既然多线程轻量级,为什么不完全采用多线程的方式呢?因为多进程能确保程序的稳定性,如果采用单进程多线程的方式,有一个线程挂了,那么该进程下的其他线程也挂了,会导致全军覆没。
  4. 优点:更优秀的内存管理,高并发场景下表现更优秀。
  5. 缺点:需要考虑线程安全问题,需要引入锁,加大cpu的消耗。
  1. event MPM
  1. 和worker的方式很像,最大的差别在于解决了“keep-alive”场景下,长期被占用的线程资源问题。
  2. 注意:event MPM遇到不兼容的模块时会失效,将回退到worker模式,一个工作线程处理一个请求。
  3. Apache的3种模式中,event MPM是最节约内存的。(需要Linux系统对Epoll的支持才能启用)
  1. 使用轻量级的Ngnix作为web服务器
  1. Ngnix本身就是一个轻量级的web服务器,天生萝莉,比Apache要轻量。
  2. Ngnix通过一个进程来服务N个链接,采用的方式不同于Apache的方式。
  1. sendfile节约内存(这个概念非常重要)
  1. sendfile可以减少数据到“用户态内存空间”(用户缓存区)的拷贝,进而减少对内存的占用。
  2. 为了更好的理解上面所说的原理。笔者先引入下面的概念:内核态和用户态的区别,内核态的优先级高Ring0,而用户态(运行态)的优先级低Ring3;并且当执行用户程序是突然中断,运行状态会从“用户态”切换到“内核态”。
  3. 一般情况下,用户态(程序所在的内存空间)不能直接操作(读写等)各种设备(磁盘,网络,终端等)的。需要使用内核作为中间人来完成对设备的操作。
  4. 来吃个栗子(例子)吧:以最简单的磁盘读写为例,从磁盘A读取文件到磁盘B,其过程是这样的:A文件数据从磁盘开始,然后载入到“内核缓冲区”,然后拷贝到“用户缓存区”,这完成了读操作。写操作也是一样的,从“用户缓存区”拷贝到“内核缓冲区”,最后写入到磁盘B中。
  5. 这样读写文件很累吧。有大神提出了要删繁就简,取消“用户缓存区”那部分拷贝工作,引入了MMP(Memory-Mapping,内存映射)的概念。实现原理是这样的:建立一个磁盘空间和内存的直接映射,数据不再拷贝到“用户缓存区”,而是返回一个指向内存空间的指针。这样我们之前的文件拷贝就变成了如下步骤:A磁盘中文件将数据载入到“内核缓冲区”,B磁盘从“内核缓冲区”拷贝写入文件。减少了一次拷贝过程,减少了内存的占用。
  6. 回到正题:简单来说,sendfile的原理和mmp的方式类似,核心也是减少了“内核缓冲区”到“用户缓冲区”的拷贝。
  7. 优点: 不仅节省了内存,还节省了CPU的开销。


4. 节约web服务器的CPU


  1. 对于web服务器而言,CPU是另一个非常核心的系统资源。就web服务器而言,除了业务程序消耗CPU外,多线程/多进程的上下文切换,也是比较消耗CPU资源的。
  2. 一个进程/线程无法长时间占用CPU,当发生阻塞或者时间片用完时,就无法继续占用CPU,这时会发生时间上下文的切换,即老的时间片切换到新的时间片,也是耗CPU的。
  3. 在并发连接数目很高的情况下,去轮询检测用户建立的连接状态(socket文件描述符),也是消耗CPU的。
  4. 笔者在这里只介绍一下终极问题及解决办法:


5. 多线程下的锁对CPU的开销


  1. Apache中的worker和event模式,都有采用多线程。多线程因为共享父进程的内存空间,在访问共享数据的时候,就会产生竞争,也就是线程安全问题。因此通常会引入锁(Linux下比较常用的线程相关的锁有互斥量metux,读写锁rwlock等),成功获取锁的线程可以继续执行,获取失败的通常选择阻塞等待。引入锁的机制,程序的复杂度往往增加不少,同时还有线程“死锁”或者“饿死”的风险(多进程在访问进程间共享资源的时候,也有同样的问题)。
  2. 死锁现象(两个线程彼此锁住对方想要获取的资源,相互阻塞等待,永远无法达不到满足条件)
  3. 饿死现象(某个线程,一直获取不到它想要锁资源,永远无法执行下一步)
  4. 为了避免这些锁导致的问题,就不得不加大程序的复杂度,解决方案一般有:
  1. 对资源的加锁,根据约定好的顺序,大家都先对共享资源X加锁,加锁成功之后才能加锁共享资源Y。
  2. 如果线程占有资源X,却加锁资源Y失败,则放弃加锁,同时也释放掉之前占有的资源X。
  1. 在使用PHP的时候,在Apache的worker和event模式下,也必须兼容线程安全。通常,新版本的PHP官方库是没有线程安全方面的问题,需要关注的是第三方扩展。PHP实现线程安全,不是通过锁的方式实现的。而是为每个线程独立申请一份全局变量的副本,相当于线程的私人内存空间,但是这样做相对多消耗一些内存。这样的好处:不需要引入复杂的锁机制实现,也避免了锁机制对CPU的开销。
相关文章
|
2月前
|
存储 算法 Java
Java内存管理深度剖析与优化策略####
本文深入探讨了Java虚拟机(JVM)的内存管理机制,重点分析了堆内存的分配策略、垃圾回收算法以及如何通过调优提升应用性能。通过案例驱动的方式,揭示了常见内存泄漏的根源与解决策略,旨在为开发者提供实用的内存管理技巧,确保应用程序既高效又稳定地运行。 ####
|
2月前
|
存储 缓存 JavaScript
如何优化Node.js应用的内存使用以提高性能?
通过以上多种方法的综合运用,可以有效地优化 Node.js 应用的内存使用,提高性能,提升用户体验。同时,不断关注内存管理的最新技术和最佳实践,持续改进应用的性能表现。
142 62
|
2月前
|
存储 缓存 监控
如何使用内存监控工具来优化 Node.js 应用的性能
需要注意的是,不同的内存监控工具可能具有不同的功能和特点,在使用时需要根据具体工具的要求和操作指南进行正确使用和分析。
80 31
|
1月前
|
存储 缓存 监控
Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
本文介绍了Docker容器性能调优的关键技巧,涵盖CPU、内存、网络及磁盘I/O的优化策略,结合实战案例,旨在帮助读者有效提升Docker容器的性能与稳定性。
135 7
|
1月前
|
存储 算法 Java
Java 内存管理与优化:掌控堆与栈,雕琢高效代码
Java内存管理与优化是提升程序性能的关键。掌握堆与栈的运作机制,学习如何有效管理内存资源,雕琢出更加高效的代码,是每个Java开发者必备的技能。
63 5
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
73 1
|
2月前
|
XML 前端开发 JavaScript
PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑
本文深入探讨了PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑;Ajax则通过异步请求实现页面无刷新更新。文中详细介绍了两者的工作原理、数据传输格式选择、具体实现方法及实际应用案例,如实时数据更新、表单验证与提交、动态加载内容等。同时,针对跨域问题、数据安全与性能优化提出了建议。总结指出,PHP与Ajax的结合能显著提升Web应用的效率和用户体验。
61 3
|
2月前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
56 6
|
2月前
|
监控 安全 程序员
如何使用内存池池来优化应用程序性能
如何使用内存池池来优化应用程序性能
|
2月前
|
存储 监控 Java
深入理解计算机内存管理:优化策略与实践
深入理解计算机内存管理:优化策略与实践
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等