我目前正在开发一个需要高吞吐量的 Service Fabric 微服务。
我想知道为什么我无法在我的工作站上使用环回实现每秒超过 500 条 1KB 消息。
我删除了所有业务逻辑并附加了一个性能分析器,只是为了测量端到端的性能。
似乎大约 96% 的时间用于解决客户端问题,而只有大约 2% 的时间用于处理实际的 Http 请求。
我在一个紧密的循环中调用“发送”进行测试:
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.005 毫秒,为 InvokeWithRetry 增加 0.5 毫秒的开销是巨大的!
这是一个 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 添加了一些我不想从客户那里错过的好东西。但它是否需要在每次调用时解析分区?