現在、高いスループットが必要な Service Fabric マイクロサービスに取り組んでいます。
ワークステーションでループバックを使用して 1 KB のメッセージを毎秒 500 件以上処理できないのはなぜだろうと思いました。
エンド ツー エンドのパフォーマンスを測定するためだけに、すべてのビジネス ロジックを削除し、パフォーマンス プロファイラーを追加しました。
時間の ~96% がクライアントの解決に費やされ、実際の HTTP 要求の実行には ~2% しか費やされていないようです。
テストのためにタイトループで「送信」を呼び出しています。
private HttpCommunicationClientFactory factory = new HttpCommunicationClientFactory();
public async Task Send()
{
var client = new ServicePartitionClient<HttpCommunicationClient>(
factory,
new Uri("fabric:/MyApp/MyService"));
await client.InvokeWithRetryAsync(c => c.HttpClient.GetAsync(c.Url + "/test"));
}
これに関するアイデアはありますか?ドキュメントによると、サービスを呼び出す方法は Service Fabric のベスト プラクティスのようです。
更新: ServicePartioningClient をキャッシュするとパフォーマンスが向上しますが、パーティション化されたサービスを使用すると、特定の PartitionKey のパーティションがわからないため、クライアントをキャッシュできません。
更新 2 : 最初の質問に完全な詳細が含まれていなかったことをお詫びします。ソケットベースの通信を最初に実装したときに、InvokeWithRetry のオーバーヘッドが非常に大きいことに気付きました。
http リクエストを使用している場合は、それほど気にすることはありません。http リクエストには既に 1 ミリ秒程度かかるため、InvokeWithRetry に 0.5 ミリ秒を追加してもそれほど目立ちません。
しかし、私たちのケースで ~ 0.005ms かかる raw ソケットを使用すると、InvokeWithRetry に 0.5ms のオーバーヘッドが追加されます。
これは http の例です。InvokeAndRetry を使用すると、3 倍の時間がかかります。
public async Task RunTest()
{
var factory = new HttpCommunicationClientFactory();
var uri = new Uri("fabric:/MyApp/MyService");
var count = 10000;
// Example 1: ~6000ms
for (var i = 0; i < count; i++)
{
var pClient1 = new ServicePartitionClient<HttpCommunicationClient>(factory, uri, new ServicePartitionKey(1));
await pClient1.InvokeWithRetryAsync(c => c.HttpClient.GetAsync(c.Url));
}
// Example 2: ~1800ms
var pClient2 = new ServicePartitionClient<HttpCommunicationClient>(factory, uri, new ServicePartitionKey(1));
HttpCommunicationClient resolvedClient = null;
await pClient2.InvokeWithRetryAsync(
c =>
{
resolvedClient = c;
return Task.FromResult(true);
});
for (var i = 0; i < count; i++)
{
await resolvedClient.HttpClient.GetAsync(resolvedClient.Url);
}
}
InvokeWithRetry がクライアントから逃したくない素晴らしいものを追加することは承知しています。しかし、すべての呼び出しでパーティションを解決する必要がありますか?