4

TL; DR-大量の同時リクエストで高スループットを可能にするglobalAgentを構成する際のベストプラクティスはありますか?

これが私たちの問題です:

私の知る限り、Nodeの接続プールはhttpモジュールによって管理されています。このモジュールは、Nodeプロセスに対してグローバルなglobalAgentオブジェクトにリクエストをキューに入れます。任意の時点でglobalAgentキューからプルされる要求の数は、開いているソケット接続の数によって決まります。これは、globalAgentのmaxSocketsプロパティ(デフォルトは5)によって決まります。

「キープアライブ」接続を使用する場合、リクエストが解決されるとすぐに、リクエストを処理した接続が使用可能になり、globalAgentのキュー内の次のリクエストを処理できるようになると思います。

ただし、代わりに、最大数までの各接続は、追加のキューに入れられた要求が処理される前に解決されるように見えます。

コンポーネント間のネットワークトラフィックを監視すると、maxSocketsが10の場合、10個のリクエストが正常に解決されることがわかります。次に、3〜5秒の一時停止(おそらく新しいtcp接続が確立されている間)があり、さらに10個の要求が解決され、次に別の一時停止などが行われます。

これは間違っているようです。ノードは、大量の同時リクエストの処理に優れているはずです。したがって、使用可能なソケット接続が1000であっても、1-999が解決されるまで要求1000を処理できない場合は、ボトルネックが発生します。しかし、私は私たちが間違って何をしているのか理解できません。

アップデート

リクエストの作成方法の例を次に示します。ただし、この動作は、広く使用されているサードパーティのライブラリによってリクエストが開始された場合を含め、ノードプロセスがhttpリクエストを作成するたびに発生することに注意してください。それが私たちの実装に固有のものではないと思います。それにもかかわらず...

class Client
  constructor: (@endpoint, @options = {}) ->
    @endpoint = @_cleanEndpoint(@endpoint)
    throw new Error("Endpoint required") unless @endpoint && @endpoint.length > 0

    _.defaults @options,
        maxCacheItems: 1000
        maxTokenCache: 60 * 10
        clientId : null
        bearerToken: null # If present will be added to the request header
        headers: {}
    @cache = {}

    @cards  = new CardMethods @
    @lifeStreams = new LifeStreamMethods @
    @actions = new ActionsMethods @

  _cleanEndpoint: (endpoint) =>
    return null unless endpoint
    endpoint.replace /\/+$/, ""


  _handleResult: (res, bodyBeforeJson, callback) =>
      return callback new Error("Forbidden") if res.statusCode is 401 or res.statusCode is 403

      body = null

      if bodyBeforeJson and bodyBeforeJson.length > 0
        try
          body = JSON.parse(bodyBeforeJson)
        catch e
          return callback( new Error("Invalid Body Content"), bodyBeforeJson, res.statusCode)

      return callback(new Error(if body then body.message else "Request failed.")) unless res.statusCode >= 200 && res.statusCode < 300
      callback null, body, res.statusCode

  _reqWithData: (method, path, params, data, headers = {}, actor, callback) =>
    headers['Content-Type'] = 'application/json' if data
    headers['Accept'] = 'application/json'
    headers['authorization'] = "Bearer #{@options.bearerToken}" if @options.bearerToken
    headers['X-ClientId'] = @options.clientId if @options.clientId

    # Use method override (AWS ELB problems) unless told not to do so
    if (not config.get('clients:useRealHTTPMethods')) and method not in ['POST', 'PUT']
      headers['x-http-method-override'] = method
      method = 'POST'

    _.extend headers, @options.headers

    uri = "#{@endpoint}#{path}"
    #console.log "making #{method} request to #{uri} with headers", headers
    request
      uri: uri
      headers: headers
      body: if data then JSON.stringify data else null
      method: method
      timeout: 30*60*1000   
     , (err, res, body) =>
       if err
         err.status =  if res && res.statusCode then res.statusCode else 503
         return callback(err)

       @_handleResult res, body, callback
4

1 に答える 1

1

正直なところ、coffeescript は私の得意分野ではないので、コードについてコメントすることはできません。

ただし、いくつかの考えを述べることができます。私たちが取り組んでいることでは、nano を使用して cloudant に接続し、マイクロ AWS インスタンスから cloudant への最大 200 リクエスト/秒を確認しています。そうです、ノードはそれに対応する必要があります。

request https://github.com/mikeal/requestをまだ使用していない場合は、使用してみてください。(私はそれが違いを生むとは思いませんが、nano が使用するものであるため、試してみる価値があります)。

これらは私が調べる分野です:

  1. サーバーは複数のリクエストをうまく処理できず、それを抑制します。サーバーに対してパフォーマンス テストを実行しましたか? なんらかの理由で負荷を処理できない場合、またはリクエストが os で調整されている場合、クライアントが何をするかは問題ではありません。

  2. クライアントコードには、サーバーから返された応答をノードが処理するのを妨げる長時間実行される機能がどこかにあります。おそらく、1 つの特定の応答が原因で、応答コールバックが長くかかりすぎている可能性があります。

エンドポイントはすべて異なるサーバー/ホストですか?

于 2012-12-14T23:52:16.377 に答える