2015-11-23 5 views
9

बनाता है मुझे अपाचे सर्वर, php ऐप के साथ एक बड़ी समस्या है।PHP readfile() कभी समाप्त नहीं होता है और अपाचे सर्वर को

सर्वर एक बहुत अधिक यातायात वेबसाइट की सेवा कर रहा है जो php के साथ चल रहा है।

हर 24h या 48h, apache hangs, और मुझे वेबसाइट को फिर से एक्सेस करने में सक्षम होने के लिए इसे रीबूट करना होगा। मुझे इसे रीबूट करना है, क्योंकि अपाचे अधिकतम प्रक्रियाओं/सर्वरों (मेरे लिए 16000) तक पहुंचता है, और यह अन्य प्रक्रियाओं को मुक्त नहीं कर सकता है क्योंकि अन्य प्रक्रियाएं सभी सक्रिय हैं।

इस सर्वर पर होस्ट की गई वेबसाइट एक php ऐप है, जो अंत में एक फ़ाइल की सेवा करती है: मान लें कि यह एक डाउनलोड सर्वर है।

ब्राउज़र द्वारा उन अनुरोधों के माध्यम से अनुरोध किया जाता है जो POST अनुरोध सबमिट करते हैं।

समस्या यह है कि यह पोस्ट अनुरोध कभी खत्म नहीं होता है (मैं देख सकता हूं कि मेरी सर्वर स्थिति पर लगभग सभी 16000 प्रक्रियाएं POST अनुरोध हैं)।

सेवा की जाने वाली फ़ाइलें बड़ी फ़ाइलें (10 एम से 2 जी) हैं, और मैं उन्हें php readfile फ़ंक्शन के साथ सेवा करता हूं (मैं उन्हें एक href लिंक के साथ सेवा नहीं करना चाहता, इसलिए मैं एक फॉर्म POST अनुरोध का उपयोग करता हूं ताकि उपयोगकर्ता कभी नहीं देखता कि फ़ाइल मेरे फाइल सिस्टम पर कहां है)।

फ़ंक्शन रीडफ़ाइल का उपयोग करने वाला फ़ंक्शन कभी भी समाप्त नहीं होता है, भले ही मैं इसके अंत में बाहर निकलें() का उपयोग करता हूं (नीचे कोड स्निपेट देखें)।

मैं यहां अपने PHP कोड के कारण होने वाले कभी भी समाप्त होने वाले POST अनुरोधों से बचने के लिए यहां नहीं कह रहा हूं। मैं फाइलों की सेवा करने का सबसे अच्छा तरीका रखना चाहता हूं।

सबसे पहले मेरी conf:

  • उबंटू सर्वर 14.04
  • अपाचे 2.4 mpm prefork साथ
  • php 5.5.9 (आधुनिक php)
  • हार्डवेयर: 128 जी रैम

मेरी mpm_prefork.conf फ़ाइल:

<IfModule mpm_prefork_module> 
     StartServers    512 
     MinSpareServers   512 
     MaxSpareServers   1024 
     ServerLimit    16000 # no problem with my server ram 
     MaxRequestWorkers  16000 
     MaxConnectionsPerChild 10000 
</IfModule> 

मेरी apache2.conf फ़ाइल:

... 
Timeout 300 
KeepAlive On 
MaxKeepAliveRequests 500 
KeepAliveTimeout 5 
... 

मेरे php।INI फ़ाइल:

max_execution_time = 7200 

मेरी अपाचे लॉग फाइल: कुछ भी नहीं मेरी समस्या

एक Munin ग्राफ पता चलता है कि जब इस मुद्दे को होता है के लिए दिलचस्प: enter image description here

मेरे अपाचे सर्वर स्थिति ऐसा लगता है: enter image description here

enter image description here

और अपने सर्वर वर्ग (कोड है कि समस्या पैदा कर रहा है):

class Server 
{ 
    /* the file is served from a remote url source */ 
    public function serveFileFromUrl() 
    { 
     if (empty($_POST)) { 
      return; 
     } 

     $url = $_POST['file_url']; 
     $mime = $_POST['mime']; 
     $name = sanitizeFileName($_POST['name']) . uniqid() . '.' . $mime; 
     $size = $_POST['size']; 

     if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) { 

      // for Internet Explorer 
      if ($mime == 'mp3') { 
       header('Content-Type: "audio/' . $mime . '"'); 
      } else { 
       header('Content-Type: "video/' . $mime . '"'); 
      } 
      header('Content-disposition: attachment; filename="' . $name . '"'); 
      header('Expires: 0'); 
      if ($size !== '') { 
       header('Content-Length: ' . $size); 
      } 
      header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
      header("Content-Transfer-Encoding: binary"); 
      header('Pragma: public'); 

     } else { 

      // not for internet Explorer 
      if ($mime == 'mp3') { 
       header('Content-Type: "audio/' . $mime . '"'); 
      } else { 
       header('Content-Type: "video/' . $mime . '"'); 
      } 
      header('Content-disposition: attachment; filename="' . $name . '"'); 
      header('Expires: 0'); 
      if ($size !== '') { 
       header('Content-Length: ' . $size); 
      } 
      header("Content-Transfer-Encoding: Binary"); 
      header('Pragma: no-cache'); 

     } 

     ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile) 
     flush();  // fix memory problems with readfile 
     readfile($url); 
     @ob_end_flush(); 
     exit(); 
    } 

    /* file is served from my filesystem */ 
    public function serveFileFromPath() 
    { 
     if (empty($_POST)) { 
      return; 
     } 

     $url = APP_PATH . '/download/' . $_POST['file_name']; 
     $mime = $_POST['mime']; 
     $name = sanitizeFileName($_POST['name']) . '-' . uniqid() . '.' . $mime; 
     $size = $_POST['size']; 

     if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) { 

      // for Internet Explorer 
      if ($mime == 'mp3') { 
       header('Content-Type: "audio/' . $mime . '"'); 
      } else { 
       header('Content-Type: "video/' . $mime . '"'); 
      } 
      header('Content-disposition: attachment; filename="' . $name . '"'); 
      header('Expires: 0'); 
      if ($size !== '') { 
       header('Content-Length: ' . $size); 
      } 
      header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
      header("Content-Transfer-Encoding: binary"); 
      header('Pragma: public'); 

     } else { 

      // not for internet Explorer 
      if ($mime == 'mp3') { 
       header('Content-Type: "audio/' . $mime . '"'); 
      } else { 
       header('Content-Type: "video/' . $mime . '"'); 
      } 
      header('Content-disposition: attachment; filename="' . $name . '"'); 
      header('Expires: 0'); 
      if ($size !== '') { 
       header('Content-Length: ' . $size); 
      } 
      header("Content-Transfer-Encoding: Binary"); 
      header('Pragma: no-cache'); 

     } 

     ob_end_clean(); // fix memory problems with readfile (http://heap.tumblr.com/post/119127049/a-note-about-phps-output-buffer-and-readfile) 
     flush();  // fix memory problems with readfile 
     readfile($url); 
     @ob_end_flush(); 
     exit(); 
    } 
} 

कोई एक समाधान कभी नहीं खत्म होने वाली पोस्ट अनुरोध से बचने के लिए किया गया है है? यदि मैं इस मुद्दे को हल कर सकता हूं तो php की तुलना में अन्य चीज़ों के माध्यम से फ़ाइलों को सेवा देना ठीक है।

कृपया कोई डुप्लिकेट, मैं इस सवाल का विशिष्ट :)

+2

एक आसान तरीका है कि कोड के 50% से छुटकारा पाने के एक http रीडायरेक्ट, उर्फ ​​हैडर स्थान के साथ serveFileFromUrl() भाग को बदलने के लिए किया जाएगा। यह किसी भी किस्मत के साथ आपकी समस्या को भी ठीक कर सकता है। – Calimero

+1

आपने अपना टाइमिलिमिट 0 पर सेट कर दिया है। टीआईएस निश्चित रूप से एक फिक्स नहीं है, लेकिन इसे 10 घंटों की तरह सेट करें, यह आपके सर्वर को जीवित रखेगा, भले ही कुछ ऐसा विफल हो जाए, और अब, यह संभवतः, आप जो करते हैं उसके साथ गड़बड़ नहीं करते हैं। एक स्क्रिप्ट लेते समय आपको दोगुना सेट करें। – Elentriel

+0

@Calimero अगर मैं केवल हेडर का उपयोग करता हूं स्थान, फ़ाइल (यह एक वीडियो फ़ाइल है) ब्राउज़र में खेला जाता है। मैं फ़ाइल को डाउनलोड करना चाहता हूं। – hedi

उत्तर

3

mod_xsendfile पीएचपी पहुंचाने फ़ाइलों के लिए एक अच्छा विकल्प है बनाने के लिए पर्याप्त कोड, conf टुकड़ा और चित्रों को शामिल किया है।

https://tn123.org/mod_xsendfile/

वरना आप बस अपने PHP स्क्रिप्ट के लिए एक धधकते जोड़ सकता है, तो यह हमेशा के लिए नहीं चल सकता।

http://php.net/manual/de/function.set-time-limit.php

+0

max_execution_time पर वर्णित readfile_chunked() फ़ंक्शन का उपयोग करके उन्हें ठीक कर सकता है max_execution_time पहले से ही 2 घंटे में सेट हो चुका है php.ini फ़ाइल। मैंने इसके साथ सवाल अपडेट किया। – hedi

+0

आपको अपने उपयोग के मामले में वास्तव में mod_xsendfile पर विचार करना चाहिए। इसके बारे में एक और पढ़ें: http://codeutopia.net/blog/2009/03/06/sending-files-better-apache-mod_xsendfile-and-php/ – user5542121

+0

मैं एक नज़र डालेगा, धन्यवाद। मैंने इसे 2 सप्ताह पहले असफल तरीके से आजमाया: यह 0kb फ़ाइलों की सेवा कर रहा था। – hedi

संबंधित मुद्दे