2016-12-23 26 views
5

Tôi có một mảng với máy chủ đối tượng như thế này:PHP chạy nhiều kịch bản kiêm

Array 
(
    [0](
       (
        [id] => 1 
        [version] => 1 
        [server_addr] => 192.168.5.210 
        [server_name] => server1 
       ) 
     ) 
    [1](
       (
        [id] => 2 
        [server_addr] => 192.168.5.211 
        [server_name] => server2 
       ) 
     ) 
) 

Bằng cách chạy mã dưới đây, tôi có thể để có được những kết quả mong muốn

foreach ($model as $server) { 
     $cpu_usage = shell_exec('sudo path/to/total_cpu_usage.sh '.$server->server_addr); 
     $memory_usage = shell_exec('sudo path/to/total_memory_usage.sh '.$server->server_addr); 
     $disk_space = shell_exec('sudo path/to/disk_space.sh '.$server->server_addr); 
     $inode_space = shell_exec('sudo path/to/inode_space.sh '.$server->server_addr); 
     $network = shell_exec('sudo path/to/network.sh '.$server->server_addr); 
     exec('sudo path/to/process.sh '.$server->server_addr, $processString); 
     $processArray = array(); 
     foreach ($processString as $i) { 
      $row = explode(" ", preg_replace('/\s+/', ' ', $i)); 
      array_push($processArray,$row); 
     } 
     $datetime = shell_exec('sudo path/to/datetime.sh '.$server->server_addr); 
     echo $cpu_usage; 
     echo $mem_usage; 
     echo $disk_space; 
     ...... 
} 

kịch bản của tôi là tương tự như:

#!/bin/bash 
if [ "$1" == "" ] 
then 
     echo "To start monitor, please provide the server ip:" 
     read IP 
else 
     IP=$1 
fi 

ssh [email protected]$IP "date" 

Nhưng toàn bộ quá trình mất 10 giây cho 5 máy chủ so với 1 máy chủ cho ít hơn hơn 2 giây. Tại sao vậy? Có cách nào để giảm bớt thời gian không? Đoán của tôi là lệnh exec đang đợi đầu ra được gán cho biến trước khi chuyển sang vòng lặp tiếp theo? Tôi đã cố gắng để google một chút nhưng hầu hết các câu trả lời cho mà không trả lại bất kỳ đầu ra ở tất cả ... Tôi cần đầu ra mặc dù

+0

start_time = 2016-12-23T17: 42: 50, end_time = 2016-12-23T17: 43: 01. khoảng 11 giây cho 5 vòng lặp, vòng lặp đầu tiên kết thúc tại 42:51 vì vậy khoảng 1 ++ giây –

Trả lời

6

Bạn có thể chạy đồng thời tập lệnh của mình với popen() và lấy kết quả sau bằng fread().

//execute 
foreach ($model as $server) { 
    $server->handles = [ 
     popen('sudo path/to/total_cpu_usage.sh '.$server->server_addr, 'r'), 
     popen('sudo path/to/total_memory_usage.sh '.$server->server_addr, 'r'), 
     popen('sudo path/to/disk_space.sh '.$server->server_addr, 'r'), 
     popen('sudo path/to/inode_space.sh '.$server->server_addr, 'r'), 
     popen('sudo path/to/network.sh '.$server->server_addr, 'r'), 
    ]; 
} 

//grab and store the output, then close the handles 
foreach ($model as $server) { 
    $server->cpu_usage = fread($server->handles[0], 4096); 
    $server->mem_usage = fread($server->handles[1], 4096); 
    $server->disk_space = fread($server->handles[2], 4096); 
    $server->inode_space = fread($server->handles[3], 4096); 
    $server->network = fread($server->handles[4], 4096); 

    foreach($server->handles as $h) pclose($h); 
} 

//print everything 
print_r($model); 

Tôi đã thử nghiệm một mã tương tự để thực hiện 5 kịch bản mà ngủ trong 2 giây và toàn bộ điều chỉ mất 2.12 giây thay vì 10,49 giây với shell_exec().

Cập nhật 1: Lớn nhờ Markus AO để chỉ ra một tiềm năng tối ưu hóa.

Cập nhật 2: Đã sửa đổi mã để xóa khả năng ghi đè. Kết quả hiện đang ở bên trong $model.

Điều này cũng có thể cho biết máy chủ nào đã từ chối kết nối, trong trường hợp vấn đề về sshd đang ảnh hưởng đến bạn.

+0

tôi nhận ra rằng nó vẫn không chạy đồng thời mặc dù. nhưng nó nhanh hơn một chút –

+0

Đây là một cách tiếp cận gọn gàng và đơn giản. Bạn có thể tăng tốc nó thêm một chút nếu bạn chia nó thành hai vòng, cái đầu tiên chỉ đơn giản là mở tất cả các chốt (ví dụ như '$ handles [$ server]') làm cho các cuộc gọi chạy trên nền, và thứ hai một người đọc tất cả các câu trả lời và đóng chốt. Chỉ để chúng tôi nhận được tất cả các yêu cầu crunching trước khi mong đợi (và có thể chờ đợi) cho bất cứ điều gì. Tôi tưởng tượng rằng sẽ đủ đồng thời! –

+0

Được rồi Tôi sẽ thử khi tôi đến văn phòng, cảm ơn sự giúp đỡ của bạn –

0

Tôi không biết làm thế nào để làm cho logic của bạn nhanh hơn nhưng tôi có thể cho bạn biết làm thế nào tôi sử dụng để theo dõi thời gian chạy khi tôi có tập lệnh. Khi bắt đầu tập lệnh, hãy đặt một số var $start = date('c'); và cuối cùng chỉ cần đơn giản echo ' start='.$start; echo ' end='.date(c);

0

Có đúng: tập lệnh PHP của bạn đang đợi từng câu trả lời trước khi chuyển tiếp.

Tôi đoán bạn đang hy vọng sẽ chạy các yêu cầu đến tất cả các máy chủ cùng một lúc, thay vì chờ đợi mỗi máy chủ phản hồi. Trong trường hợp đó, giả sử bạn đang chạy phiên bản PHP an toàn cho luồng, hãy xem xét pthreads. Một tùy chọn là sử dụng cURL multi-exec để thực hiện các yêu cầu không đồng bộ. Sau đó, cũng có pcntl_fork có thể giúp bạn. Ngoài ra, hãy xem this & this luồng cho các phương pháp tiếp cận luồng/async có thể có.

Ngoài ra, hãy kiểm tra và đo điểm chuẩn các kịch bản lệnh vỏ để xem vị trí tắc nghẽn là gì và liệu bạn có thể tăng tốc chúng hay không. Điều đó có thể dễ dàng hơn các thiết lập thread/async trong PHP. Nếu bạn có vấn đề với độ trễ mạng, sau đó viết một tập lệnh shell aggregator thực hiện các kịch bản lệnh khác và trả về kết quả trong một yêu cầu, và chỉ gọi nó trong kịch bản lệnh PHP của bạn.

+0

làm cách nào để triển khai thực hiện multi-exec cURL? –

+0

@LIMSY bạn muốn thực hiện cuộc gọi SSH qua cURL tới (các) máy chủ của bạn, trước tiên mở một đường hầm bằng các hàm 'ssh_ *' của PHP, sau đó khởi tạo multi-cURL và thêm mỗi yêu cầu làm xử lý. Những điều cơ bản của cURL đa init/exec là ở đây: http://php.net/manual/en/function.curl-multi-init.php và http://php.net/manual/en/function.curl-multi -exec.php ... và ví dụ sử dụng SSH tại đây: http://stackoverflow.com/questions/22765956/php-ssh2-tunnel-using-proxy-socks-throw-ssh-server ... cái này (khá phức tạp) cách tiếp cận các cuộc gọi song song sẽ chỉ có ý nghĩa nếu bạn đang kết nối trực tiếp với các máy chủ từ xa. –

+0

Và với điều đó tôi nên thêm rằng tôi đã không chơi xung quanh với một cURL/SSH combo bản thân mình, cũng không có vẻ là rất nhiều thông tin trực tuyến. Nếu bạn đi xuống con đường đó, chuẩn bị cho một chút công bằng của hack-xung quanh. Một tùy chọn khác cho cURL, có lẽ là cách dễ dàng hơn, sẽ là thiết lập một API cơ bản trả về dữ liệu cần thiết qua HTTP và thay vào đó thực hiện nhiều cuộc gọi đến đó. –

0

Tất cả những gì bạn cần làm là thêm > /dev/null & vào cuối Linux, bạn sẽ không nhận được kết quả, nhưng nó sẽ chạy dưới dạng nền (không đồng bộ).

shell_exec('sudo path/to/datetime.sh '.$server->server_addr.' > /dev/null &'); 

cũng thấy Bối cảnh này quá trình kịch bản từ GitHub của tôi, (nó có cửa sổ quá trình nền tương thích)

https://github.com/ArtisticPhoenix/MISC/blob/master/BgProcess.php

Cheers!

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