2011-12-31 61 views
12

Tôi đã viết một số mã bằng PHP trả về nội dung html từ các miền .edu. Giới thiệu ngắn gọn được cung cấp tại đây: Errors regarding Web Crawler in PHPGiải quyết lỗi "Máy chủ MySQL đã biến mất"

Trình thu thập thông tin hoạt động tốt khi số lượng liên kết thu thập thông tin nhỏ (khoảng 40 URL) nhưng tôi nhận được lỗi "Máy chủ MySQL đã biến mất" sau số này.

Tôi đang lưu trữ nội dung html dưới dạng văn bản dài trong bảng MySQL và tôi không nhận được lý do lỗi xuất hiện sau ít nhất 40-50 lần chèn.

Bất kỳ trợ giúp nào về vấn đề này đều được đánh giá cao.

Xin lưu ý rằng tôi đã thay đổi wait_timeout và max_allowed_packet để đáp ứng các truy vấn của tôi và mã php và bây giờ tôi không biết phải làm gì. Xin hãy giúp tôi trong vấn đề này.

Trả lời

10

Bạn có thể có xu hướng xử lý vấn đề này bằng cách "ping" máy chủ mysql trước truy vấn. Đây là một ý tưởng tồi. Để biết thêm về lý do tại sao, hãy xem bài đăng SO này: Should I ping mysql server before each query?

Cách tốt nhất để xử lý vấn đề là bằng cách bao gồm các truy vấn bên trong try/catch chặn mọi ngoại lệ cơ sở dữ liệu để bạn có thể xử lý chúng một cách thích hợp. Điều này đặc biệt quan trọng trong các kịch bản lệnh chạy và/hoặc kiểu daemon dài. Vì vậy, đây là ví dụ rất cơ bản bằng cách sử dụng "trình quản lý kết nối" để kiểm soát quyền truy cập vào các kết nối DB:

class DbPool { 

    private $connections = array(); 

    function addConnection($id, $dsn) { 
     $this->connections[$id] = array(
      'dsn' => $dsn, 
      'conn' => null 
     ); 
    } 

    function getConnection($id) { 
     if (!isset($this->connections[$id])) { 
      throw new Exception('Invalid DB connection requested'); 
     } elseif (isset($this->connections[$id]['conn'])) { 
      return $this->connections[$id]['conn']; 
     } else { 
      try { 
       // for mysql you need to supply user/pass as well 
       $conn = new PDO($dsn); 

       // Tell PDO to throw an exception on error 
       // (like "MySQL server has gone away") 
       $conn->setAttribute(
        PDO::ATTR_ERRMODE, 
        PDO::ERRMODE_EXCEPTION 
       ); 
       $this->connections[$id]['conn'] = $conn; 

       return $conn; 
      } catch (PDOException $e) { 
       return false; 
      } 
     } 
    } 

    function close($id) { 
     if (!isset($this->connections[$id])) { 
      throw new Exception('Invalid DB connection requested'); 
     } 
     $this->connections[$id]['conn'] = null; 
    } 


} 


class Crawler { 

    private $dbPool; 

    function __construct(DbPool $dbPool) { 
     $this->dbPool = $dbPool; 
    } 

    function crawl() { 
     // craw and store data in $crawledData variable 
     $this->save($crawledData); 
    } 

    function saveData($crawledData) { 
     if (!$conn = $this->dbPool->getConnection('write_conn') { 
      // doh! couldn't retrieve DB connection ... handle it 
     } else { 
      try { 
       // perform query on the $conn database connection 
      } catch (Exception $e) { 
       $msg = $e->getMessage(); 
       if (strstr($msg, 'MySQL server has gone away') { 
        $this->dbPool->close('write_conn'); 
        $this->saveData($val); 
       } else { 
        // some other error occurred 
       } 
      } 
     } 
    } 
} 
+0

DbException đã có trong php ?? – Rafay

+2

Không, đây là lớp Ngoại lệ bạn sẽ chỉ định chính mình và ném từ bên trong hàm 'saveData()'. Tôi đã cập nhật hàm 'saveData' và thêm một lớp DbException tùy chỉnh vào câu trả lời của tôi để phản ánh điều này ... – rdlowrey

3

Tôi có another answer đề cập đến những gì tôi nghĩ là một vấn đề tương tự và sẽ yêu cầu câu trả lời tương tự. Về cơ bản, bạn có thể sử dụng chức năng mysql_ping() để kiểm tra kết nối trước khi chèn. Trước khi MySQL 5.0.14, mysql_ping() sẽ tự động kết nối lại máy chủ, nhưng bây giờ bạn phải xây dựng logic kết nối lại của riêng bạn. Điều gì đó tương tự như vậy sẽ phù hợp với bạn:

function check_dbconn($connection) { 
    if (!mysql_ping($connection)) { 
     mysql_close($connection); 
     $connection = mysql_connect('server', 'username', 'password'); 
     mysql_select_db('db',$connection); 
    } 
    return $connection; 
} 

foreach($array as $value) { 
    $dbconn = check_dbconn($dbconn); 
    $sql="insert into collected values('".$value."')"; 
    $res=mysql_query($sql, $dbconn); 
    //then some extra code. 
} 
+1

Pinging không phải là một chiến lược tốt trong trường hợp này ... để biết thêm về lý do tại sao, hãy kiểm tra bài đăng SO này: [Tôi có nên ping máy chủ mysql trước mỗi truy vấn không?] (Http: // stackoverflow.com/questions/3103969/should-i-ping-mysql-server-trước-mỗi-truy vấn) – rdlowrey

0

Bạn đang mở một kết nối DB và sử dụng lại nó? Có thể là một thời gian chờ đơn giản của nó? Bạn có thể được phục vụ tốt hơn bằng cách mở một kết nối DB mới cho mỗi hoạt động đọc/ghi của bạn (liên hệ với IE .edu, nhận văn bản, mở DB, viết văn bản, đóng db, lặp lại).

Bạn cũng sử dụng tay cầm như thế nào? Có thể nó đã bị lỗi và đã 'biến mất' vì lý do đó?

+0

Tôi có nên mở một kết nối mới cho mỗi truy vấn và sau đó đóng nó sau khi thực hiện truy vấn đó không ?? Và lặp lại các thủ tục cho tất cả các truy vấn ?? – Rafay

+4

Để ghi lại, mở một kết nối mới cho mỗi truy vấn là không hiệu quả khủng khiếp ... – rdlowrey

+0

Điều đáng nói là nếu một chuỗi bị giết trên db (với 'KILL [thread id]') thì bạn sẽ nhận được "server biến mất "lỗi quá. –

0

Vâng Đây là những gì tôi đang làm bây giờ dựa trên gợi ý của rdlowrey và tôi đoán điều này cũng đúng.

public function url_db_html($sourceLink = NULL, $source) { 
    $source = mysql_real_escape_string($source); 

    $query = "INSERT INTO html (id, sourceLink, sourceCode) 
      VALUES (NULL,('$sourceLink') , ('$source'))"; 

    try { 
     if(mysql_query($query, $this->connection)==FALSE) { 
      $msg = mysql_errno($this->connection) . ": " . mysql_error($this->connection); 
      throw new DbException($msg); 
     }   
    } catch (DbException $e) { 
     echo "<br><br>Catched!!!<br><br>"; 
     if(strstr($e->getMessage(), 'MySQL server has gone away')) { 
      $this->connection = mysql_connect("localhost", "root", ""); 
      mysql_select_db("crawler1", $this->connection); 
     } 
    } 
} 

Vì vậy, khi truy vấn không thực thi được, tập lệnh sẽ bỏ qua nhưng sẽ đảm bảo kết nối được thiết lập lại.

Tuy nhiên, trình thu thập dữ liệu web của tôi bị lỗi khi gặp phải các tệp như .jpg, .bmp, .pdf, v.v. Có cách nào để bỏ qua các url đó có chứa các tiện ích mở rộng này hay không. Tôi đang sử dụng preg_match và đã cho pdf và doc để phù hợp. Tuy nhiên, tôi muốn các chức năng để bỏ qua tất cả các liên kết có chứa phần mở rộng như mp3, pdf, vv Điều này có thể ??

+0

Nếu kết nối db của bạn là đóng nó sẽ là từ 1 trong 2 lý do: 1) mã của bạn là đóng nó. 2) Hệ thống của bạn có một số vấn đề lớn. Tôi chưa bao giờ thấy chiến lược kết nối lại này được sử dụng như tôi chưa bao giờ thấy một tình huống mà nó cần được yêu cầu. Thay vì kết nối lại trong khối catch của bạn, hãy thử đăng nhập các chi tiết ngoại lệ và gỡ lỗi vấn đề từ đó. –

2

Tôi đang đối mặt với "Máy chủ Mysql đã biến mất" lỗi khi sử dụng Mysql connector 5.X, thay thế dll sang phiên bản cuối cùng đã giải quyết được sự cố.

Các vấn đề liên quan