web-dev-qa-db-ja.com

Socket.IOを使用してデータを送信できる頻度はどれくらいですか?

サーバーからクライアントに少量のデータ(ソケットごとに3つの整数値)を頻繁に送信する必要があるWebアプリケーションを作成していますが、 Socketを使用してクライアントを更新する最大頻度があるかどうかを確認したいと思いました。 .IO

私は少なくとも50のソケット接続を達成し、毎秒20の更新を送信することを望んでいました。理想的な数は200ソケット接続で、1秒あたり50の更新を送信します。

質問:Socket.IOを使用して新しいデータを送信できる頻度に制限はありますか?

注:これはサーバーとクライアントの接続の速度の問題にもなることを認識しているため、必要な接続の速度に関する情報をいただければ幸いです。送信される各データパケットが約500バイトの場合、1 MB/sの接続で100の接続に対して1秒間に20の更新を送信できると計算しました。

8
Paul Warnick

これは、システム、ネットワーク、およびコードに依存する質問です。

これは私が以前に同様のプレーンsocket.ioテストに使用した小さなテストハーネスです。あなたの質問に合うようにいくつかのビットを接続しました。

サーバ

const io = require('socket.io')(8082)
const connections = []

io.on('connection', function(socket){

  connections.Push(socket);
  const slog = (msg, ...args) => console.log('%s %s '+msg, Date.now(), socket.id, ...args)
  slog('Client connected. Total: %s', connections.length)

  socket.on('disconnect', function(data){
    connections.splice(connections.indexOf(socket), 1);
    slog('Client disconnected. Total: %s', connections.length)
  })

  socket.on('single', function(data){
    socket.emit('single',[ 0, now, now, now ])
  })

  socket.on('start', function(data = {}){
    slog('Start stream', data)
    sendBatch(1, data.count, data.delay)
  })

  socket.on('start dump', function(data = {}){
    slog('Start dump', data)
    sendBatch(1, data.count)
  })

  function sendBatch(i, max, delay){
    if ( i > max ) return slog('Done batch %s %s', max, delay)
    socket.emit('batch',[ i, now, now, now ])
    if (delay) {
      setTimeout(()=> sendBatch(i++, max, delay), delay)
    } else {
      setImmediate(()=> sendBatch(i++, max))
    }
  }

})

クライアント

const io = require('socket.io-client')
const socket = io('http://localhost:8082', {transports: ['websocket']})

socket.on('connect_error', err => console.error('Socket connect error:', err))
socket.on('connect_timeout', err => console.error('Socket connect timeout:', err))
socket.on('reconnect', err => console.error('Socket reconnect:', err))
socket.on('reconnect_attempt', err => console.error('Socket reconnect attempt:', err))
socket.on('reconnecting', err => console.error('Socket reconnecting', err))
socket.on('reconnect_error', err => console.error('Socket reconnect error:', err))
socket.on('reconnect_failed', err => console.error('Socket reconnect failed:', err))

function batch(n){
  socket.on('batch', function(data){
    if ( data[0] >= n ) {
      let end = Date.now()
      let persec = n / (( end - start ) / 1000)
      console.log('Took %s ms for %s at %s/s', end - start, n, persec.toFixed(1))
      return socket.close()
    }
  })
}

function startDump(count = 500000){
  socket.emit('start dump', { count: count })
  console.log('Start dump', count)
  batch(count)
}
function startStream(count = 50, delay = 1000){
  socket.emit('start', { count: count, delay: delay })
  console.log('Start stream', count, delay)
  batch(count)
}

function pingIt(i, max = 50){
  socket.on('single', function(data){
    console.log('Got a single with:', data)
    if (i >= max) {
      let end = Date.now()
      let persec = i / (end - start) * 1000
      console.log('Took %s ms %s/s', end - start, persec.toFixed(2))
      return socket.close()
    }
    socket.emit('single', i+=1)
  })
  socket.emit('single', i)
}

let start = Date.now()

//console.log('args command: %s  count: %s  delay: %s',process.argv[2], process.argv[3], process.argv[4])
switch(process.argv[2]){
  case 'ping':   pingIt(0, process.argv[3]); break
  case 'stream': startStream(process.argv[3], process.argv[4]); break
  case 'dump':   startDump(process.argv[3]); break
  default:       console.log('ping stream dump'); socket.close()
}

要求/応答の往復をテストするには

 node socketio-client.js ping 4

スループットをテストするには、サーバーが可能な限り高速にメッセージをダンプします。

 node socketio-client.js dump 100000

1秒あたり約50メッセージである、それぞれの間に18ミリ秒の遅延がある1000メッセージのストリームをテストします。

 node socketio-client.js stream 1000 18

私の開発マシンでは、2 GHz CPUのペイロード(カウンター+ 3タイムスタンプ)として4つの整数を使用して、1秒あたり約40000メッセージを単一のローカルホストクライアントにダンプできます。サーバーとクライアントの両方のnodeプロセスは、それぞれCPUコアの95〜100%を使用します。したがって、純粋なスループットは問題ないように見えます。

サーバープロセスの55%のCPU使用率で、100個のローカルクライアントに毎秒100個のメッセージを送信できます。

開発マシンの単一のnodeプロセスから、100クライアントに対して1秒あたり130〜140を超えるメッセージを取得できません。

新しい高周波IntelSkylake CPUサーバーは、これらの数値をローカルで破壊する可能性があります。おそらく不安定なネットワーク接続を追加すると、すぐに元に戻ります。ローカルネットワークの遅延以外のものは、おそらく、このような高いメッセージレートで得られると思われるものを台無しにするでしょう。遅いものでの遅延ジッターは、クライアント側のメッセージの「フレームレート」に大混乱をもたらします。メッセージにタイムスタンプを付け、クライアントで追跡する必要があるでしょう。

問題が発生した場合は、 ws のような低レベルのWebSocketライブラリもあります。これには、より多くの実装が必要ですが、ソケット接続をより細かく制御でき、おそらくより多くのパフォーマンスを求めることができます。それらのうち。

接続が多ければ多いほど、残りのコードとソケットコードとの競合が多くなります。スムーズに保つために、おそらく 複数のノード を使用する必要があります。 クラスターはアプリを複数のNode.jsプロセスに分割できます 。 IPCを管理するには、Redis、 ZeroMQ または Nanomsg のようなものが必要になる場合があります。 Node 9は SharedArrayBuffer および Atomics をサポートしますが、Nodeはまだ使用されていません)のV8彼らと労働者。

11
Matt

Socket.IOを使用してデータを送信できる頻度はどれくらいですか?

Socket.IOを使用して新しいデータを送信できる頻度に制限はありますか?

コード化された制限はありません。それは、両端でメッセージを処理する能力とそれらを配信するための帯域幅にのみ依存します。実行しているハードウェア、ネットワーク、およびOSに関する独自の制限を本当に知りたい場合は、代表的なサイズの高速ファイアパケットを送信するテストを考案し、1秒間に送信できるパケット数を確認する必要があります。すべてが宛先に到達し、どちらの端にもエラーは見られません。

理想的な数は200ソケット接続で、1秒あたり50の更新を送信します。

サーバーは1秒あたり10,000通のメッセージを送信できる必要があり、各クライアントは1秒あたり50通の着信メッセージを処理できる必要があります。これはすべて、適切なハードウェアと適切なネットワーク接続で理論的に可能です。

しかし、1秒あたり50回の更新は、おそらく不必要で非効率的であるように思われます。エンドユーザーは、20ミリ秒ごとに何らかの変化を認識することはありません。これは、1秒あたり50回の更新になります。したがって、各クライアントへの更新を1秒あたり10回程度にバッチ処理する方がはるかに効率的です。

送信される各データパケットが約500バイトの場合、1 MB/sの接続で100接続に対して1秒間に20の更新を送信できると計算しました。

このタイプの計算は、大きなデータブロックを送信する場合にのみ機能します。多くの小さなメッセージの場合、TCPパケットのオーバーヘッドと、多くの小さなメッセージのwebSocket/socket.ioオーバーヘッドが、全体的な帯域幅消費の測定可能な割合になり始め、 TCPは信頼できるプロトコルであるため、配信を確認するためにACKが前後に流れることもあります。パケットが小さい場合は、全体的な帯域幅の問題はおそらくないでしょう。問題はさらに大きくなります。たくさんの小さなパケットを処理し、それを行うためのオーバーヘッドがあります。

更新を1秒あたりの更新数を少なくすることができれば、スケーラビリティが大幅に向上します。

6
jfriend00