web-dev-qa-db-ja.com

リアルタイムフロントエンドダッシュボード、3秒ごとにAPIを呼び出し、CPU負荷を軽減

私はネットワークプロジェクトに取り組んでいます。ルーター(Mikrotikルーター、APIを提供する別のAPI要求を呼び出すサーバーへのAPI要求を呼び出すことにより、複数のルーターのリアルタイムステータス(CPU /メモリ使用量、アップ/ダウントラフィックなど)を表示するダッシュボードを作成しています。設定を行い、ステータスを取得します)。

問題:各リクエストをテストすると、VPSのCPU使用率が最大20%増加します。これは、ダッシュボードを表示してリクエストを行う1人のユーザーのみです。複数の顧客がいて、それぞれがダッシュボードを表示し、サーバーに複数の要求を行っている場合はどうなりますか?確実に下がるだろう?

これがバックエンドコードの一部です:

$routers = //Get all the routers belong to that users

foreach($routers as $router){

            $api = connectRouter();
            if($api === false){
                continue;
            }

            $api->write('/ip/hotspot/user/getall');
            $users = $api->read();


            $api->write('/ip/hotspot/active/getall');
            $actives = $api->read();

            $resources = $api->comm('/system/resource/print');
            $resources = $resources[0];


            $api->write('/interface/getall');
            $router->interfaces = $api->read();

} 

質問: CPU使用率を削減し、このサービスを複数の顧客に提供できるようにするには、どのようなオプションが必要ですか?

私が研究したものまで:

  1. Node.jsを試す必要がありますか?
  2. フロントエンドから呼び出す方法を変更します。APIを呼び出してすべてのルーターデータを一度に取得するのではなく、1つずつ取得するように変更しますか?

[〜#〜] note [〜#〜] 1.ルーターのこれらの値は毎秒変化します(ミリ秒でない場合)。できるだけリアルタイムで価値を得たい。したがって、キャッシュはここでは解決策ではないと思います。

  1. すべてのユーザーが独自のルーターのセットを持っています。ルーターを共有しません。したがって、ルータークエリの重複チェックを実行しても、メリットはないと私は思います。 (うん、同じログインユーザーが複数のデバイスまたはブラウザーのタブで表示しようとすると便利です。)しかし、私は複数のユーザー向けに最適化しようとしています。
3
cjmling

バックエンドのどこかにデータをキャッシュしたくない場合は、毎回一連の呼び出しを開始するのではなく、Uiがこれをリクエストできるようにしますか?.

次に、内部呼び出しを3秒ごとに1セットに減らすか、リフレッシュレートをいくらにしてもかまいません。

システム全体で呼び出しチェーンを使用することはテストに適しているため、キャッシュを使用するとスケールアップできます。

3
Ross Halliday

優れたオプションは、双方向通信です。そのためには、永続的な接続を保持できるサーバーが必要になるので、PHPは(ReactPHP/Ratchetのようなものでハックすることはできますが)不可能であり、Node.jsです。はるかに良いオプションになります。

現在の主な問題は、2人のユーザーが同じルーターにアクセスできる場合、両方のルーターの出力データが同じであっても、ルーターを2回クエリすることになります。そして、より多くのユーザーが接続するたびに、数値は高くなります。

あなたがそうすべきことは:

  • ルーターのクエリに使用されるNode.jsサーバーをセットアップします。
  • ユーザーが接続したら、ルーターリストを確認し、ルーターをルーターに追加します[〜#〜] set [〜#〜](セットに重複を含めることはできません。各ルーターは一度だけ存在します)、
  • クライアントとNode.jsサーバーの間の永続的な双方向接続を確立します(ソケットを使用)。
  • ルータプール内のすべてのルータにクエリを実行してデータを取得します。
  • ルーターからの応答を受信したら、フィードからデータを受信したばかりのルーターのクライアントを確認する/接続されたクライアントに新しいデータをプッシュする、
  • クライアントの接続が切断されたら、ルーターのルータープールを調べ、ルーターがいくつかのルーターを使用している唯一のクライアントである場合は、クエリプールから削除します。

これにより、同じルーターに複数回クエリを実行するのを防ぐことができます。

ルーターからクライアントにデータを供給する方法として、次のいずれを選択するか。

  1. すべてのルーターを照会し、サイクルが終了すると、すべてのルーターのデータをクライアントに送信します。
  2. または、各ルーターからデータを受信すると、クライアントにデータをフィードします。

自分のために工夫する必要があります。個人的には2番目のオプションを選択します。

2
Andy

最初に試したいのは、そのconnectRouter()行をループの外に移動することです。これにより、作業のオーバーヘッドが低くなります。その後、ジョブをデータコレクターと要求ハンドラーに分割します。データコレクターでは、定期的にクエリを実行し、リクエストハンドラーが収集できるように結果をどこかに配置します。何かのようなもの:

setupRoutersConnection();

while (true) {

    foreach ($routers as $key => $router) {
        // read from the router
        $dashboard.routers[$key] = $someRouterInfo;
    }
    usleep(200);
}

$dashboardは、データコレクタと要求ハンドラの間で共有するものです。

0
imel96