>  기사  >  백엔드 개발  >  PHP 읽기 및 쓰기 파일 충돌에 대한 높은 동시성 솔루션 요약

PHP 읽기 및 쓰기 파일 충돌에 대한 높은 동시성 솔루션 요약

伊谢尔伦
伊谢尔伦원래의
2017-07-17 10:09:212295검색

PHP에서는 Flock이 잘 작동하지 않는 것 같아요! 다중 동시성의 경우 리소스가 독점되어 즉시 해제되지 않거나 전혀 해제되지 않는 경우가 많아 교착상태를 일으키고, 서버의 CPU 사용량이 매우 높아지며, 때로는 서버가 완전히 죽는 경우도 있는 것으로 보입니다. 이는 많은 Linux/Unix 시스템에서 발생하는 것 같습니다. 그러므로 플록을 사용하기 전에 신중하게 고려해야 합니다.

flock()을 올바르게 사용하면 교착상태 문제를 완전히 해결할 수 있습니다. 물론, Flock() 함수 사용을 고려하지 않는다면 우리 문제에 대한 좋은 해결책도 있을 것입니다. 해결책은 대략 다음과 같이 요약됩니다.
옵션 1: 파일을 잠글 때 시간 초과를 설정합니다. 대략적인 구현은 다음과 같습니다.

if($fp=fopen($fileName,'a')){
 $startTime=microtime();
 do{
  $canWrite=flock($fp,LOCK_EX);
  if(!$canWrite){
   usleep(round(rand(0,100)*1000));
  }
 }while((!$canWrite)&&((microtime()-$startTime)<1000));
 if($canWrite){
  fwrite($fp,$dataToSave);
 }
 fclose($fp);
}

제한 시간은 1ms로 설정됩니다. 이 시간 내에 잠금을 획득하지 못하면 물론 파일 작동 권한을 획득할 때까지 반복적으로 획득하게 됩니다. 시간 초과 제한에 도달한 경우 즉시 종료하고 다른 프로세스가 작동할 수 있도록 잠금을 포기해야 합니다.

옵션 2: 무리 기능을 사용하지 말고 임시 파일을 사용하여 읽기 및 쓰기 충돌 문제를 해결하세요. 일반적인 원칙은 다음과 같습니다.
(1) 업데이트해야 할 파일의 복사본을 임시 파일 디렉터리에 넣고 파일의 마지막 수정 시간을 변수에 저장한 후 이 임시 파일을 무작위로 지정합니다. -반복할 파일 이름 .
(2) 임시 파일을 업데이트한 후 원본 파일의 마지막 업데이트 시간이 이전에 저장된 시간과 일치하는지 확인하세요.
(3) 마지막 수정 시간이 동일한 경우 수정된 임시 파일의 이름을 원본 파일로 변경하여 파일 상태가 동기적으로 업데이트되도록 하려면 파일 상태를 지워야 합니다.
(4) 단, 마지막 수정 시간이 이전에 저장된 시간과 일치하면 이 기간 동안 원본 파일이 수정되었음을 의미하며 이때 임시 파일을 삭제한 후 false를 반환해야 함을 나타냅니다. 현재 파일에 다른 수정 사항이 있습니다.
구현 코드는 다음과 같습니다.

$dir_fileopen=&#39;tmp&#39;;
function randomid(){
    return time().substr(md5(microtime()),0,rand(5,12));
}
function cfopen($filename,$mode){
    global $dir_fileopen;
    
clearstatcache
();
    do{
  $id=md5(randomid(rand(),TRUE));
        $tempfilename=$dir_fileopen.&#39;/&#39;.$id.md5($filename);
    } while(
file_exists
($tempfilename));
    if(file_exists($filename)){
        $newfile=false;
        copy($filename,$tempfilename);
    }else{
        $newfile=true;
    }
    $fp=fopen($tempfilename,$mode);
    return $fp?array($fp,$filename,$id,@
filemtime
($filename)):false;
}
function cfwrite($fp,$string){
 return fwrite($fp[0],$string);
}
function cfclose($fp,$debug=&#39;off&#39;){
    global $dir_fileopen;
    $success=fclose($fp[0]);
    clearstatcache();
    $tempfilename=$dir_fileopen.&#39;/&#39;.$fp[2].md5($fp[1]);
    if((@filemtime($fp[1])==$fp[3])||($fp[4]==true&&!file_exists($fp[1]))||$fp[5]==true){
        rename($tempfilename,$fp[1]);
    }else{
        unlink($tempfilename);
  //说明有其它进程 在操作目标文件,当前进程被拒绝
        $success=false;
    }
    return $success;
}
$fp=cfopen(&#39;lock.txt&#39;,&#39;a+&#39;);
cfwrite($fp,"welcome to beijing.\n");
fclose($fp,&#39;on&#39;);

위 코드에 사용된 함수를 설명해야 합니다.
(1) rename(); 이 함수는 실제로 Linux의 mv와 비슷합니다. 파일이나 디렉터리의 경로나 이름을 업데이트하는 것이 편리합니다. 하지만 위 코드를 윈도우에서 테스트할 때 새 파일 이름이 이미 존재하면 현재 파일이 이미 존재한다는 알림이 표시됩니다. 하지만 리눅스에서는 잘 작동합니다.
(2)clearstatcache(); 파일 상태를 지웁니다. PHP는 더 높은 성능을 제공하기 위해 모든 파일 속성 정보를 캐시하지만 때로는 여러 프로세스가 파일을 삭제하거나 업데이트할 때 PHP가 캐시를 업데이트할 시간이 없습니다. 파일 속성으로 인해 액세스한 마지막 업데이트 시간이 실제 데이터가 아니라는 사실이 쉽게 드러날 수 있습니다. 따라서 저장된 캐시를 지우려면 이 기능을 사용해야 합니다.

옵션 3: 동시성 가능성을 줄이기 위해 운영되는 파일을 무작위로 읽고 씁니다.
이 솔루션은 사용자 접속 로그를 기록할 때 더 자주 사용되는 것 같습니다. 이전에는 무작위 공간을 정의해야 했습니다. 공간이 클수록 동시성 가능성은 작아졌습니다. 무작위 읽기 및 쓰기 공간이 [1-500]이라고 가정하면 로그 파일의 분포 범위는 log1에서 log500입니다. 사용자가 접속할 때마다 log1~log500 사이의 임의의 파일에 데이터가 무작위로 기록됩니다. 동시에 로그를 기록하는 두 개의 프로세스가 있습니다. 프로세스 A는 업데이트된 log32 파일일 수 있지만 프로세스 B는 어떻습니까? 그렇다면 이때의 업데이트는 log399가 될 수 있다. 프로세스 B도 log32를 동작시키길 원한다면 그 확률은 기본적으로 1/500으로 거의 0에 가깝다는 것을 알아야 한다. 액세스 로그를 분석해야 하는 경우 먼저 이러한 로그를 병합한 다음 분석하기만 하면 됩니다. 로그를 기록하기 위해 이 솔루션을 사용하면 프로세스 작업을 대기열에 넣을 가능성이 상대적으로 작아 프로세스가 각 작업을 매우 빠르게 완료할 수 있다는 이점이 있습니다.

옵션 4: 작업할 모든 프로세스를 대기열에 넣습니다. 그런 다음 전용 서비스를 넣어 파일 작업을 완료하세요. 대기열에서 제외된 각 프로세스는 첫 번째 특정 작업과 동일하므로 처음으로 서비스는 대기열에서 특정 작업 항목만 가져오면 됩니다. 여기에 파일 작업 프로세스가 많으면 문제가 되지 않습니다. . , 대기열의 뒤쪽에 줄을 서실 의향이 있는 한 대기열의 길이는 중요하지 않습니다.

이전 옵션의 경우 각각 고유한 이점이 있습니다! 대략 두 가지 범주로 나눌 수 있습니다.
(1) 옵션 1, 2, 4와 같은 대기열 필요(느린 영향)
(2) 대기열이 필요하지 않습니다. (빠른 영향) 옵션 3
캐싱 시스템을 설계할 때 일반적으로 옵션 3을 채택하지 않습니다. Plan 3의 분석 프로그램과 글쓰기 프로그램이 동기화되지 않기 때문에 글쓰기를 할 때 글쓰기가 좋다면 분석의 난이도는 전혀 고려되지 않습니다. 캐시를 업데이트할 때 임의의 파일 읽기 및 쓰기도 사용한다면 캐시를 읽을 때 많은 프로세스가 추가될 것 같습니다. 하지만 옵션 1과 2는 완전히 다릅니다. 쓰기 시간은 기다려야하지만 (잠금 획득에 실패하면 반복적으로 획득됩니다) 파일을 읽는 것이 매우 편리합니다. 캐시를 추가하는 목적은 데이터 읽기 병목 현상을 줄여 시스템 성능을 향상시키는 것입니다.

위 내용은 PHP 읽기 및 쓰기 파일 충돌에 대한 높은 동시성 솔루션 요약의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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