您的当前位置:首页>全部文章>文章详情

【PHP】从服务器负载一路走到PHP-FPM优化终于搞定了PHP项目偶尔很慢的问题

CrazyPanda发表于:2024-06-21 10:59:50浏览:249次TAG:

原文链接https://zhuanlan.zhihu.com/p/681575918

项目情况: 阿里云Rds 阿里云Redis PHP8 IN Docker

本文会从几个方面来讲PHP线上项目怎么进行性能瓶颈定位,以及优化方法。

前段时间有个PHP项目开始出现偶尔有一些请求会超时,最长的请求可能需要长达20S。 一般出现这总情况的时候,我们首先想到的会不会服务器负载不够,或者个某个查询花了太多时间。

观察服务器负载

  • 服务器负载 30% 左右,一切正常

  • 数据库负载 60% 左右,一切正常

  • Redis负载 30% 左右,一切正常

首先排除了是因为服务器负载的原因,那么接下来想到的就是 Mysql 部分查询很慢导致的。

检查数据库负载以及 Sql慢查询

  • 数据库负载一切正常,当看到这个情况的时候我们心里其实排除了是数据库的原因了。

  • 继续查看 Sql慢日志,发现有一些日志,都是1-2 秒之间,没有什么特别需要关心的。

这里也排除了数据库的原因,接下来继续查看 Nginx情况。

检查 Nginx 日志

这里检查 Nginx 日志主要是查询是否又Http 状态码 是429这样的请求,如有出现很频繁,那么表示是 Nginx Worker不够,或者是 PHP程序内部返回的 429。其实我们这次的原因可以排除是这个可能,因为如果是这个问题,那么那么请求不应该很慢,应该会直接返回错误码。那么当我们遇到Nginx返回429我们一般怎么处理呢。

429 (Too Many Requests)

首先我们要知道什么时候 Nginx会返回这个错误码:在Nginx服务器中遇到HTTP状态码429(Too Many Requests)时,通常意味着客户端在短时间内发送了过多的请求,超出了服务器允许的速率限制。

常用解决方案

一、调整 Nginx worker_processesworker_connections

首先检查worker_processesworker_connections看看设置的大小是多少

worker_processes它定义了Nginx要启动的工作进程(worker process)的数量。工作进程是实际处理客户端请求的核心单元,负责接收和处理HTTP请求、读写磁盘上的文件以及与上游服务器通信等任务。通过设置多个工作进程,Nginx可以充分利用多核CPU的优势,分散负载到不同的核心上并行处理请求,从而提高系统的并发处理能力和整体性能。

自动检测CPU核心数,并设置相应数量的工作进程(推荐)
worker_processes auto;
如果你的服务器是4核CPU或多核CPU但希望限制为使用4个核心,当然我们通常可以设置到 2-3 倍,比如 8 或者 12.
worker_processes 4;

worker_connections 是 Nginx 服务器配置中的一个重要参数,它定义了每个工作进程(worker process)可以同时处理的最大并发连接数。这个设置直接影响到Nginx服务器能够同时服务的客户端请求数量。每一个工作进程都有一个最大连接数的限制,超过这个限制后,新的连接将无法被接收和处理。合理设置 worker_connections 可以有效利用系统资源,避免因并发连接数过大导致内存溢出或其他资源耗尽问题。

worker_rlimit_nofile 10240;
events {
    use epoll; # 对于Linux环境,推荐使用epoll事件模型
    multi_accept on; # 允许一个工作进程接受多个连接
    worker_connections 6144; # 每个工作进程允许的最大并发连接数
}

这里设置的是每个工作进程可同时处理的并发连接数为6144。实际应用中,根据服务器硬件性能、操作系统参数(如打开文件描述符数量上限)、以及预期业务负载进行调整。另外,在设置 worker_connections 参数时,需要确保其值小于或等于 worker_rlimit_nofile 参数设置的值(即每个工作进程允许打开的最大文件描述符数量),因为每个网络连接都需要占用一个文件描述符。 worker_rlimit_nofile 指令用于设置每个工作进程可以打开的最大文件描述符数量,这对于处理高并发连接至关重要。当Nginx作为Web服务器或反向代理时,它需要为每个活动连接保持一个打开的文件描述符(例如套接字)。如果这个限制过低,可能会导致无法处理更多的客户端连接,即使系统资源充足。 那么如何设置worker_rlimit_nofile ,对于worker_rlimit_nofile的设置我们可以参考系统自身最大打开文件数。

ulimit -n
65535

这里最大为 65535 所以我们可以设置为65535 .但是如果直接把worker_rlimit_nofile 设置到65535,如果请求过大的时候可能就会影响其他的进程。

二、限速限流

可以对某一个 IP 进行限流限速,这样可以排除一些异常的请求。也可以保障其他请求的正常执行。

二、负载均衡与扩展性考虑:

如果是因为服务器处理能力达到瓶颈,可以考虑负载均衡技术,将流量分散到多个服务器上,或者根据需要扩展服务器资源。

检查PHP-FPM

当服务器,数据库,Nginx都正常之后,我就想到最后的一个可能,PHP-FPM进程不能够用了。 查看 Docker 默认的FPM进程配置

cat /usr/local/etc/php-fpm.d/www.conf

pm = dynamic

; The number of child processes to be created when pm is set to 'static' and the
; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'.
; This value sets the limit on the number of simultaneous requests that will be
; served. Equivalent to the ApacheMaxClients directive with mpm_prefork.
; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP
; CGI. The below defaults are based on a server without much resources. Don't
; forget to tweak pm.* to fit your needs.
; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand'
; Note: This value is mandatory.
pm.max_children = 5

; The number of child processes created on startup.
; Note: Used only when pm is set to 'dynamic'
; Default Value: (min_spare_servers + max_spare_servers) / 2
pm.start_servers = 2

发现默认只有 最大只有 5 个进程,所以我们增大到 20 个,修改配置如下

pm = dynamic
pm.start_servers = 5
pm.max_children = 20
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
pm.process_idle_timeout = 10s

由于这里使用的Docker ,所以我们尽量使用挂载配置文件的方式来修改配置,使用Docker-compose 来挂载新增的php配置zz-docker.conf

volumes:
      - "./docker/php/zz-docker.conf:/usr/local/etc/php-fpm.d/zz-docker.conf:cached"

最后重启Docker,通过一周观察,一切回到正常状态。

最后:常用的PHP-FPM各个参数的含义以及配置

PHP-FPM(参数优化是提高服务器性能和稳定性的关键步骤之一,以下是一些主要的PHP-FPM配置参数及其优化建议:

  1. 进程管理方式 (**pm**):

  • pm = static: 静态模式,固定数量的子进程。

pm.max_children = N # 设置最大子进程数
  • pm = dynamic: 动态模式,根据负载自动调整子进程数量。

pm.max_children = N # 最大子进程数
pm.start_servers = M # 启动时创建的进程数
pm.min_spare_servers = X # 空闲时最小进程数
pm.max_spare_servers = Y # 空闲时最大进程数
  1. 子进程数量 (**max_children**): 根据服务器内存大小和单个PHP请求的平均内存消耗计算出合适的值。确保所有子进程占用的总内存不超过服务器物理内存的75%左右并需要根据实际情况调整,以免出现内存溢出。

  2. 请求处理超时 (**request_terminate_timeout**):

request_terminate_timeout = T # 请求处理超时时间(秒)

设定一个合理的脚本执行超时时间,防止因个别耗时过长的请求导致资源浪费或服务卡顿。

  1. 监听队列 (**listen.backlog**):

这个参数决定了等待连接队列的最大长度,可以根据系统负载和并发需求进行适当调整。

  1. 错误日志级别 (**log_level**):

log_level = notice # 或 error, warning, debug等

选择适当的日志级别以平衡调试需要与减少日志输出对性能的影响。

  1. 慢日志记录 (**slowlog**):

slowlog = /path/to/slow.log
request_slowlog_timeout = S # 超过多少秒的请求会被记录到慢日志

记录执行时间过长的请求,帮助分析和优化代码。

每个参数的优化都需要结合实际情况,如服务器硬件资源、网站访问量特点以及PHP应用程序的具体行为等因素综合考虑,并且可能需要反复测试和调优。

猜你喜欢

【PHP】PHP静态化
随着互联网的快速发展,网站访问量越来越大,同时网站的性能也成为了设计者们需要考虑的重要问题之一。对于使用php语言的开发人员来说,静态化是提高网站性能的一种有效方法。在本文中,我们将探讨php中静态化的方法。一、什么是静态化静态化是指将动态生成的网页文件(如PHP文件)转换为静态的HTML文件存储在服务器上。当用户请求时,直接访问静态HTML文件,避免了每次请求都要执行PHP代码的情况,从而提高了网站的性能响应速度。二、静态化的优劣静态化虽然能够提高网站响应速度,但它也存在一些缺陷:优点:1.减
发表于:2024-06-18 浏览:262 TAG:
【PHP】php如何创建关联数组表格
随着互联网技术的不断发展,Web 应用程序的开发变得越来越重要。其中,关联数组表格是 Web 应用程序中常用的一种数据结构,它可以将数据按照列与行的方式分组存储,并且可以方便地在前端界面中进行展示。那么,如何使用 PHP 创建关联数组表格呢?本文将为您一一介绍。一、创建关联数组在 PHP 中,我们可以使用关联数组来存储数据,关联数组是以字符串为索引的数组。相较于索引数组(使用数字作为索引的数组),关联数组更加灵活,可以通过索引来直接访问每个元素。下面的示例代码创建了一个关联数组,包含了
发表于:2023-12-18 浏览:324 TAG:
【PHP】PHP防止XSS攻击的主流方法
概述跨站点脚本 (XSS) 是一种严重的安全漏洞,允许恶意行为者将恶意脚本引入网站,使毫无戒心的访问者处于危险之中。使用 XSS,攻击者可以在受害者的 Web 浏览器中执行任意代码,可能导致敏感数据被盗、未经授权的访问或网站污损。本文旨在深入探讨 XSS 攻击的主要形式,阐明其根本原因,探索 XSS 利用的潜在后果,并深入了解防止 PHP 中 XSS 攻击的有效措施。介绍当恶意行为者成功将有害脚本插入受信任的网站时,就会发生跨站脚本 (XSS) 攻击。这些受感染的网站在不知不
发表于:2024-07-14 浏览:233 TAG: #php
【PHP】PHP8如何通过Sanitize Filters来增强应用程序的安全性
PHP是一门广泛应用于Web开发的脚本语言,而安全性一直是Web应用程序开发者需要关注的重要问题。PHP8提供了一种称为Sanitize Filters的机制,通过对用户输入进行过滤和清理,可以增强应用程序的安全性。本文将详细介绍PHP8中Sanitize Filters的使用方法,并提供一些具体的代码示例,帮助开发者更好地了解如何应用这一特性。首先,让我们来了解一下Sanitize Filters是什么。Sanitize Filters是一组用于过滤和清理用户输入数据的PHP函数,可以帮助开发
发表于:2023-12-30 浏览:277 TAG:
【PHP】PHP8如何优化代码性能
PHP8的新特性和底层开发原理探索:如何优化代码性能随着互联网的迅猛发展和信息技术的不断更新,PHP作为一门重要的互联网开发语言也在不断演进。PHP8作为最新版本,带来了许多全新的特性和改进,同时也提供了更强大的底层开发能力。本文将探讨PHP8的新特性,并给出一些代码示例,展示如何优化代码性能。JIT编译器PHP8引入了Just-In-Time(即时编译)编译器。JIT编译器可以将PHP代码动态地编译成本地机器码,从而提高代码执行的效率。在PHP8中,JIT编译器默认是关闭的,需要手动启用。下面
发表于:2024-01-07 浏览:308 TAG:
【PHP】PHP中使用ElasticSearch
在es中,使用组合条件查询是其作为搜索引擎检索数据的一个强大之处,在前几篇中,简单演示了es的查询语法,但基本的增删改查功能并不能很好的满足复杂的查询场景,比如说我们期望像mysql那样做到拼接复杂的条件进行查询该如何做呢?es中有一种语法叫bool,通过在bool里面拼接es特定的语法可以做到大部分场景下复杂条件的拼接查询,也叫复合查询首先简单介绍es中常用的组合查询用到的关键词,filter:过滤,不参与打分 must:如果有多个条件,这些条件都必须满足 and与 should:如果有多个条
发表于:2024-07-26 浏览:251 TAG: #php #Elasticsearch
【PHP】php替换字符串
在PHP中,字符串替换是常见的操作,而替换所有匹配的字符串更是常见需求。本文将详细介绍如何使用PHP中的替换函数来替换所有匹配字符串。一、str_replace函数PHP中最常用的替换函数是str_replace()函数,它可以替换一个字符串中的指定部分。其语法如下:string str_replace(mixed $search, mixed $replace, mixed $subject[, int 
发表于:2023-12-29 浏览:305 TAG:
【PHP】intervention/image设置文字竖排显示
在使用 intervention/image 库时,要让文字竖排显示,可以通过设置文字的样式和使用 rotate 方法将文字旋转90度来实现。以下是一个示例代码:use Intervention\Image\ImageManagerStatic as Image;   // 初始化ImageManager $imageManager = new Image();   // 加载背景图片 $back
发表于:2024-04-08 浏览:320 TAG:
【PHP】php怎么将汉字转为拼音
PHP是一种非常流行的服务端脚本语言,它具有灵活、快速、安全等优点,因此被广泛应用于Web开发、互联网应用和企业级软件开发等领域。而将汉字转为拼音是一个常见的需求,特别是在中文搜索、排序、筛选等场景下,可以提高用户体验和检索准确性。本文将介绍如何使用PHP实现将汉字转为拼音的方法。一、使用PHP拓展PHP中有一个名为pinyin的拓展,通过它可以很方便地将汉字转为拼音。首先需要在php.ini文件中开启拓展,找到下面这行并取消注释,保存并重启PHP服务:extension=pinyin.so登录
发表于:2024-01-05 浏览:313 TAG:
【PHP】php代码规范七大原则
hp代码规范七大原则包括一致性、可读性、简洁性、可复用性、可测试性、安全性和性能。详细介绍:1、一致性,代码应该保持一致性,即在整个代码库中使用相同的命名规范、缩进风格、代码注释等,这样可以使团队成员更容易理解和阅读代码,减少出错和混淆的可能性;2、可读性,代码应该易于阅读和理解,为了提高可读性,可以使用有意义的变量和函数命名,避免使用过于复杂的表达式和嵌套结构等等。本教程操作系统:windows10系统、PHP 8.1.3版本、DELL G3电脑。在PHP开发中,遵循良好的代码规范是非常重要
发表于:2024-03-17 浏览:294 TAG: