찾다
백엔드 개발PHP 튜토리얼[实践好文]PHP 死锁问题分析

背景:对于死锁的问题,人们往往想到出现一些关于访问很缓慢,有白页现象,要是测试环境(我就真实遇到测试环境有本文谈及一样的问题)你也就重启一下PHP的php-fpm进程发现又好了,隔一段时间又出类似的问题,你会看下日志,你会发现有很多日志是“Max execution timeout of 60 seconds exceeded”,你会发现这可能是一些php的守护进程导致的,你为了解决测试环境的问题,于是觉得应该把那个php-fpm的进程数开多点,可能会好一些,于是你开多了,一直没有面对这个问题的原因,为什么呢,因为公司装PHP的是运维装的,你没有办法或时间去装一个debug版本的php,你说这个问题让运维的人来查,你觉得能查出来?So,这个问题一拖再拖,但就是没解决,但是有一天你发现磁盘满了,用du去看整体时发现满了,但是如果一个个目录去看发现并没有占用多少,也万万没有想到PHP的死锁还会导致磁盘空间占用太多,上面这种情况我就真实遇到过,后来重新reboot操作系统,磁盘又回来了,所以,我认为是一篇好文章,所以转了此文,也想说明对于PHP的扩展这方面代码质量把关需要严格,再就是PHP本身关于锁这块要弱化(除开cookie/session和cache锁外,其它能不用就不用),尽可能少用锁,这是博主一点小看法,下面言归正传。

引子:

本期我们邀请到了 云盘服务端 团队的技术达人- 徐铁成,一个隐蔽已久的PHP死锁问题被层层掘出,感谢铁成为我们带来这次畅快的体验,小伙伴们,准备好这次技术之旅了么?

---------------

发现问题

近期发现线上很多机器的磁盘空间报警, 且日志文件已经清理,但是磁盘空间没有释放。通过ps aux | grep php-cgi 发现, 很多进程的启动时间在几天到几周甚至几个月之前。我们线上的php-cgi都有最大执行次数的。一般在1天内都会重启一次。初步结论,这些cgi进程有问题。

通过lsof -p [pid] 发现, 启动时间很久的cgi进程中打开了一些日志文件句柄,并且没有关闭。这些日志文件在文件系统中已经删除了。但是句柄没关闭,导致磁盘空间没有释放。到此,磁盘空间异常的问题基本确定。是由于cgi没有关闭文件句柄造成的。

进一步分析进程, strace -p [pid], 发现所有异常的进程都阻塞与 fmutex 状态。换句话所,异常的cgi进程死锁了。进程死锁导致打开的文件句柄没有关闭,所以导致磁盘空间异常。

为什么cgi进程会死锁呢?

什么是死锁

学过操作系统的通同学,都了解多线程的概念。在多线程中访问公共资源,需要对资源加锁。访问结束后,释放锁。如果没有释放锁,那么下一个线程来获取资源的时候就会永远都无法获取资源的锁,于是这个线程死锁了。那么CGI是多线程的公共资源访问导致的死锁吗? 答案是NO。

1. CGI 是单线程进程,通过ps 就能看到。(进程状态 Sl的才是多线程进程)。

2. 即使是多线程的,死锁发生在PHP的shutdown过程中调用glibc 中time 函数的位置,不是php模块造成的。而glibc 中的time相关函数是线程安全的,不会产生死锁。

那是什么导致的死锁呢?

通过分析linux中死锁产生的机制,发现除了多线程会产生死锁外,信号处理函数同样会产生死锁。那么cgi是由于信号处理导致的死锁吗?在这之前介绍一个感念。

函数的可重入性与信号安全

函数可重入是指,无论第几次进入该函数,函数都能正常执行并返回结果。那么线程安全函数是可重入的吗?答案是NO。 线程安全函数,在第一次访问公共资源时,会获取全局锁。如果函数没有执行完成,锁还没释放,此时进程被中断。那么在中断处理函数中,再次访问该函数,就会产生死锁。那么什么样的函数才可以在中断处理函数中访问呢? 除了没有使用全局锁的函数,还有一些signal safe的系统调用可以使用。调用任何其他的非signal safe的函数都会产生不可预知的后果(比如 死锁)。 详见 man signal。在分析死锁的原因前,我们先看看cgi执行的流程,分析其中有没有产生死锁的可能。

PHP-CGI的执行流程

Glibc中的时间函数使用到了全局锁,保证函数的线程安全,但没有保证信号安全(signal safe)。经过之前的分析,我们初步怀疑死锁是由于PHP-CGI进程接收到了一个信号,然后在signal handle中执行了非signal safe的函数。主流程在中断前,正在执行glibc中的时间函数。在函数获取的锁没释放前,进入中断流程。而中断过程中又访问了glibc中的时间函数。于是导致了死锁。

PHP-CGI的执行流程,如下图所示:

进一步分析发现,所有死锁的cgi进程的sapi_global中都记录了一个错误信息

“Max execution timeout of 60 seconds exceeded”.

60s 是我们php-cgi中设置执行超时。所以我们确认了,cig在执行过程中的确产生了超时异常,然后由于longjmp进入了shutdown过程。在shutdown过程中访问了glibc中的时间函数。导致了死锁。

void zend_set_timeout(long seconds)

{

TSRMLS_FETCH();

EG(timeout_seconds) = seconds;

if(!seconds) {

return;

}

……

setitimer(ITIMER_PROF, &t_r, NULL);

signal(SIGPROF, zend_timeout); // 此处会调用zend异常处理函数

sigemptyset(&sigset);

sigaddset(&sigset, SIGPROF);

……

}

通过gdb调试发现,所有PHP-CGI都阻塞在zend_request_shutdown中。zend_request_shutdown会调用用户自定义的php脚本中实现的shutdown函数。如果CGI执行超市,那么定时器会产生SIGPROF信号使执行流程中断。如果此时脚本刚好处于调用时间函数的状态,且还没有释放锁资源。然后执行流程进入了 timeout 函数,继续跳转到zend_request_shutdown。此时如果自定义的shutdown函数中访问了时间函数。就会产生死锁。我们从代码中找到了证据:

register_shutdown_function ('SimpleWebSvc:: shutdown’);

我们在php代码中使用qalarm系统,qalarm系统会在cgi执行结束(shutdown)的时候,注入一个钩子函数,来分析cgi执行是否正常,如果不正常,则发送报警信息。而刚好qalarm的报警处理函数中访问了时间函数。于是就有一定的概率产生死锁。

结论

通过上面的分析,我们找到了cgi死锁产生的原因,是应为在signal handler中使用了非signal safe的函数,导致了死锁。

解决办法

去掉或简化qalarm注册到shutdown中的钩子函数。避免不安全的函数调用。

来自:http://www.v2gg.com/lady/shishangzixun/20140924/57266.html

성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
PHP와 Python : 다른 패러다임이 설명되었습니다PHP와 Python : 다른 패러다임이 설명되었습니다Apr 18, 2025 am 12:26 AM

PHP는 주로 절차 적 프로그래밍이지만 객체 지향 프로그래밍 (OOP)도 지원합니다. Python은 OOP, 기능 및 절차 프로그래밍을 포함한 다양한 패러다임을 지원합니다. PHP는 웹 개발에 적합하며 Python은 데이터 분석 및 기계 학습과 같은 다양한 응용 프로그램에 적합합니다.

PHP와 Python : 그들의 역사에 깊은 다이빙PHP와 Python : 그들의 역사에 깊은 다이빙Apr 18, 2025 am 12:25 AM

PHP는 1994 년에 시작되었으며 Rasmuslerdorf에 의해 개발되었습니다. 원래 웹 사이트 방문자를 추적하는 데 사용되었으며 점차 서버 측 스크립팅 언어로 진화했으며 웹 개발에 널리 사용되었습니다. Python은 1980 년대 후반 Guidovan Rossum에 의해 개발되었으며 1991 년에 처음 출시되었습니다. 코드 가독성과 단순성을 강조하며 과학 컴퓨팅, 데이터 분석 및 기타 분야에 적합합니다.

PHP와 Python 중에서 선택 : 가이드PHP와 Python 중에서 선택 : 가이드Apr 18, 2025 am 12:24 AM

PHP는 웹 개발 및 빠른 프로토 타이핑에 적합하며 Python은 데이터 과학 및 기계 학습에 적합합니다. 1.PHP는 간단한 구문과 함께 동적 웹 개발에 사용되며 빠른 개발에 적합합니다. 2. Python은 간결한 구문을 가지고 있으며 여러 분야에 적합하며 강력한 라이브러리 생태계가 있습니다.

PHP 및 프레임 워크 : 언어 현대화PHP 및 프레임 워크 : 언어 현대화Apr 18, 2025 am 12:14 AM

PHP는 현대화 프로세스에서 많은 웹 사이트 및 응용 프로그램을 지원하고 프레임 워크를 통해 개발 요구에 적응하기 때문에 여전히 중요합니다. 1.PHP7은 성능을 향상시키고 새로운 기능을 소개합니다. 2. Laravel, Symfony 및 Codeigniter와 같은 현대 프레임 워크는 개발을 단순화하고 코드 품질을 향상시킵니다. 3. 성능 최적화 및 모범 사례는 응용 프로그램 효율성을 더욱 향상시킵니다.

PHP의 영향 : 웹 개발 및 그 이상PHP의 영향 : 웹 개발 및 그 이상Apr 18, 2025 am 12:10 AM

phphassignificallyimpactedwebdevelopmentandextendsbeyondit

스칼라 유형, 반환 유형, 노조 유형 및 무효 유형을 포함한 PHP 유형의 힌트 작업은 어떻게 작동합니까?스칼라 유형, 반환 유형, 노조 유형 및 무효 유형을 포함한 PHP 유형의 힌트 작업은 어떻게 작동합니까?Apr 17, 2025 am 12:25 AM

PHP 유형은 코드 품질과 가독성을 향상시키기위한 프롬프트입니다. 1) 스칼라 유형 팁 : PHP7.0이므로 int, float 등과 같은 기능 매개 변수에 기본 데이터 유형을 지정할 수 있습니다. 2) 반환 유형 프롬프트 : 기능 반환 값 유형의 일관성을 확인하십시오. 3) Union 유형 프롬프트 : PHP8.0이므로 기능 매개 변수 또는 반환 값에 여러 유형을 지정할 수 있습니다. 4) Nullable 유형 프롬프트 : NULL 값을 포함하고 널 값을 반환 할 수있는 기능을 포함 할 수 있습니다.

PHP는 객체 클로닝 (클론 키워드) 및 __clone 마법 방법을 어떻게 처리합니까?PHP는 객체 클로닝 (클론 키워드) 및 __clone 마법 방법을 어떻게 처리합니까?Apr 17, 2025 am 12:24 AM

PHP에서는 클론 키워드를 사용하여 객체 사본을 만들고 \ _ \ _ Clone Magic 메소드를 통해 클로닝 동작을 사용자 정의하십시오. 1. 복제 키워드를 사용하여 얕은 사본을 만들어 객체의 속성을 복제하지만 객체의 속성은 아닙니다. 2. \ _ \ _ 클론 방법은 얕은 복사 문제를 피하기 위해 중첩 된 물체를 깊이 복사 할 수 있습니다. 3. 복제의 순환 참조 및 성능 문제를 피하고 클로닝 작업을 최적화하여 효율성을 향상시키기 위해주의를 기울이십시오.

PHP vs. Python : 사용 사례 및 응용 프로그램PHP vs. Python : 사용 사례 및 응용 프로그램Apr 17, 2025 am 12:23 AM

PHP는 웹 개발 및 컨텐츠 관리 시스템에 적합하며 Python은 데이터 과학, 기계 학습 및 자동화 스크립트에 적합합니다. 1.PHP는 빠르고 확장 가능한 웹 사이트 및 응용 프로그램을 구축하는 데 잘 작동하며 WordPress와 같은 CMS에서 일반적으로 사용됩니다. 2. Python은 Numpy 및 Tensorflow와 같은 풍부한 라이브러리를 통해 데이터 과학 및 기계 학습 분야에서 뛰어난 공연을했습니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

Atom Editor Mac 버전 다운로드

Atom Editor Mac 버전 다운로드

가장 인기 있는 오픈 소스 편집기

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

DVWA

DVWA

DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는