2017-02-14 56 views
2

Azureには、アイテムがキューに置かれたときに起動される関数アプリケーションがあります。これは次のようになります(大幅に簡略化):Azure関数の同時実行ジョブ数の制限queue

public static async Task Run(string myQueueItem, TraceWriter log) 
{ 
    using (var client = new HttpClient()) 
    { 
     client.BaseAddress = new Uri(Config.APIUri); 
     client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 

     StringContent httpContent = new StringContent(myQueueItem, Encoding.UTF8, "application/json"); 
     HttpResponseMessage response = await client.PostAsync("/api/devices/data", httpContent); 
     response.EnsureSuccessStatusCode(); 

     string json = await response.Content.ReadAsStringAsync(); 
     ApiResponse apiResponse = JsonConvert.DeserializeObject<ApiResponse>(json); 

     log.Info($"Activity data successfully sent to platform in {apiResponse.elapsed}ms. Tracking number: {apiResponse.tracking}"); 
    } 
} 

これはすべてうまく動作し、かなりうまく動作します。アイテムがキューに置かれるたびに、私たちは私たちの側のあるAPIにデータを送り、応答を記録します。クール。

「キューメッセージを生成するもの」に大きなスパイクがあり、多くのアイテムが一度にキューに置かれると問題が発生します。これは、1分に1,000〜1,500件前後で発生する傾向があります。 Functions.SendToLimeade:関数の実行中に例外:

2017-02-14T01:45:31.692 mscorlibエラー・ログには、このようなものを持っています。 f-SendToLimeade __- 1078179529:リクエストの送信中にエラー が発生しました。システム: リモートサーバーに接続できません。システム:各ソケットアドレス (プロトコル/ネットワークアドレス/ポート)の1つの使用が通常許可されます 123.123.123.123:443。

最初は、これは、Azure関数のアプリケーションでローカルソケットが不足していると考えました(illustrated here)。しかし、私はIPアドレスに気づいた。 IPアドレス123.123.123.123(この例ではもちろん変更)は、HttpClientが送信しているIPアドレスです。だから今私はそれが私たちのサーバがこれらの要求を処理するために使い果たされているのだろうかと思います。

いずれにしても、ここではスケーリングの問題が発生しています。私はそれを解決する最善の方法を見つけようとしています。

いくつかのアイデア:

  1. それがローカルソケットの制限だ場合、article aboveReq.ServicePoint.BindIPEndPointDelegateを使用してローカルポートの範囲を増加する例があります。これは有望ですが、本当にをスケールする必要があるときはどうしますか?私はこの問題が2年後に戻ってくることを望んでいません。
  2. リモートリミテッドの場合、Functionランタイムが一度に処理するメッセージの数を制御できるようです。ここでは、serviceBus.maxConcurrentCallsを1に設定でき、1つのメッセージだけを一度に処理できるという興味深い記事があります。たぶん私はこれを比較的低い数値に設定することができました。さて、ある時点で私たちのキューは処理できるよりも速くいっぱいになりますが、その時点での答えは私たちの最後にサーバーを追加することです。
  3. 複数のAzure関数apps?複数のAzure関数アプリケーションがあり、それらがすべて同じキューでトリガーされるとどうなりますか? Azureは機能アプリ間で作業を分割するのに十分なほどスマートなのですか?私はキューを処理している軍隊を持つことができますが、必要に応じて拡大縮小できますか?
  4. 私はまたキープアライブを見つけました。待ち行列のメッセージが氾濫しているので、私のソケットを何とか開いたままにしておくことができれば、おそらく大きな助けになるかもしれません。これは可能なのでしょうか、これをどうやってやるのかについてのヒントはありますか?

このようなシステムに推奨される(スケーラブルな)デザインについての洞察は非常に高く評価されます。

答えて

1

私はこれのための解決策を考え出したと思います。私は過去にこれらの変更を実行していた 3時間 6時間、私はゼロソケットエラーがあった。私は大量のバッチでこれらのエラーを30分ごとに取得する前に。

まず、HttpClientを管理するための新しいクラスを追加しました。

public static class Connection 
{ 
    public static HttpClient Client { get; private set; } 

    static Connection() 
    { 
     Client = new HttpClient(); 

     Client.BaseAddress = new Uri(Config.APIUri); 
     Client.DefaultRequestHeaders.Add("Connection", "Keep-Alive"); 
     Client.DefaultRequestHeaders.Add("Keep-Alive", "timeout=600"); 
     Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); 
    } 
} 

は今、私たちは関数を呼び出すたびに使用HttpClientの静的インスタンスを持っています。私の研究では、HttpClientインスタンスを可能な限り長く保つことが強く推奨されています。すべてがスレッドセーフであり、HttpClientは要求をキューに入れ、同じホストへの要求を最適化します。私はKeep-Aliveヘッダーも設定しています(これはデフォルトですが、私は暗黙のうちに考えています)。私の機能で

、私は静的のHttpClientインスタンスをつかむように:

var client = Connection.Client; 
StringContent httpContent = new StringContent(myQueueItem, Encoding.UTF8, "application/json"); 
HttpResponseMessage response = await client.PostAsync("/api/devices/data", httpContent); 
response.EnsureSuccessStatusCode(); 

私は本当に(私たちに依頼する必要がありますソケットレベルで何が起こっているかのいずれかでの詳細な分析を行っていませんロードバランサでこのトラフィックを見ることができるかどうかはIT担当者に分かります)、キュー項目が処理されるにつれて、単一のソケットをサーバーに開いたままにして、HTTPコールをたくさん作成することを望んでいます。とにかく、それが何をしていても動作しているようです。たぶん誰かが改善する方法についていくつかの考えを持っています。

1

専用Webアプリケーションで機能の代わりに消費計画を使用すると、3つ以上の機能がそのまま使用できます。関数は大きなメッセージキューを検出し、キュー長が安定するまでインスタンスを追加します。

maxConcurrentCallsはインスタンスごとに適用されるため、インスタンスごとの同時実行を制限できます。基本的に、処理率はです。

グローバルスループットを制御する唯一の方法は、選択したサイズの専用ウェブアプリで関数を使用することです。各アプリケーションは、キューをポーリングし、必要に応じて作業を取得します。

ベストスケーリングソリューションは、123.123.123.123のロードバランシングを改善し、キューの負荷を満たすためにスケーリングアップ/ダウン機能からの任意の数の要求を処理できるようにします。

キープアライブafaikは永続的な接続には便利ですが、関数の実行は永続的な接続としては見えません。将来的には、関数に「独自のバインディングを持たせる」ことを追加しようとしています。これは、好きな場合に接続プーリングを実装できるようにします。

+0

は今のところ、それが見えます。だから、私は新しい機能のアプリケーションを追加することについての部分は必要ではないと思います。それはすでにこれを行います。ソケットエラーメッセージがAzureのローカルインスタンスがソケットから外れているか、ここのサーバーがソケットから外れているかどうかはまだ分かりません。 –

+0

私自身の答えも以下に加えました。これは今まで私たちのために働いているようです! –

+0

この類似の質問/回答はまた興味があるかもしれません:https://stackoverflow.com/questions/40094041/throttling-azure-storage-queue-processing-in-azure-function-app – Alex

0

私は質問がずっと前に答え​​られたことを知っていますが、マイクロソフトではあなたが使用していたアンチパターンを文書化しています。すでにスケーリングを処理するために(新レリックによる)4台の別のホストを使用しているよう

Improper Instantiation antipattern

関連する問題