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的开销。
相关文章
|
9天前
|
监控
SMoA: 基于稀疏混合架构的大语言模型协同优化框架
通过引入稀疏化和角色多样性,SMoA为大语言模型多代理系统的发展开辟了新的方向。
24 6
SMoA: 基于稀疏混合架构的大语言模型协同优化框架
|
7天前
|
存储 NoSQL 分布式数据库
微服务架构下的数据库设计与优化策略####
本文深入探讨了在微服务架构下,如何进行高效的数据库设计与优化,以确保系统的可扩展性、低延迟与高并发处理能力。不同于传统单一数据库模式,微服务架构要求更细粒度的服务划分,这对数据库设计提出了新的挑战。本文将从数据库分片、复制、事务管理及性能调优等方面阐述最佳实践,旨在为开发者提供一套系统性的解决方案框架。 ####
|
16天前
|
运维 Serverless 数据处理
Serverless架构通过提供更快的研发交付速度、降低成本、简化运维、优化资源利用、提供自动扩展能力、支持实时数据处理和快速原型开发等优势,为图像处理等计算密集型应用提供了一个高效、灵活且成本效益高的解决方案。
Serverless架构通过提供更快的研发交付速度、降低成本、简化运维、优化资源利用、提供自动扩展能力、支持实时数据处理和快速原型开发等优势,为图像处理等计算密集型应用提供了一个高效、灵活且成本效益高的解决方案。
51 1
|
26天前
|
监控 API 开发者
后端开发中的微服务架构实践与优化
【10月更文挑战第17天】 本文深入探讨了微服务架构在后端开发中的应用及其优化策略。通过分析微服务的核心理念、设计原则及实际案例,揭示了如何构建高效、可扩展的微服务系统。文章强调了微服务架构对于提升系统灵活性、降低耦合度的重要性,并提供了实用的优化建议,帮助开发者更好地应对复杂业务场景下的挑战。
21 7
|
28天前
|
运维 监控 Serverless
利用Serverless架构优化成本和可伸缩性
【10月更文挑战第13天】Serverless架构让开发者无需管理服务器即可构建和运行应用,实现成本优化与自动扩展。本文介绍其工作原理、核心优势及实施步骤,探讨在Web应用后端、数据处理等领域的应用,并分享实战技巧。
|
28天前
|
Cloud Native API 持续交付
利用云原生技术优化微服务架构
【10月更文挑战第13天】云原生技术通过容器化、动态编排、服务网格和声明式API,优化了微服务架构的可伸缩性、可靠性和灵活性。本文介绍了云原生技术的核心概念、优势及实施步骤,探讨了其在自动扩展、CI/CD、服务发现和弹性设计等方面的应用,并提供了实战技巧。
|
24天前
|
存储 Kubernetes 监控
深度解析Kubernetes在微服务架构中的应用与优化
【10月更文挑战第18天】深度解析Kubernetes在微服务架构中的应用与优化
92 0
|
3月前
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
366 0
|
22天前
|
存储 C语言
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
44 1
|
26天前
|
存储
共用体在内存中如何存储数据
共用体(Union)在内存中为所有成员分配同一段内存空间,大小等于最大成员所需的空间。这意味着所有成员共享同一块内存,但同一时间只能存储其中一个成员的数据,无法同时保存多个成员的值。