使用HttpClient从Google Cloud Storage读取文件时,从服务器接收响应并将其写入日志之间的时间差太大

时间:2018-08-25 15:37:33

标签: c# google-cloud-storage

我需要从GCS下载多个文件。为此,我使用了代码

public class GCSStorage 
{
    static HttpClient httpClient;
    static GoogleCredential credential = GoogleCredential.FromFile(ConfigurationManager.AppSettings["GCPCredentials"]);
    if (credential.IsCreateScopedRequired)
    {
        credential = credential.CreateScoped(new[]
        {
           "https://www.googleapis.com/auth/devstorage.read_only"

        });
        httpClient = new Google.Apis.Http.HttpClientFactory()
                        .CreateHttpClient(
                        new Google.Apis.Http.CreateHttpClientArgs()
                        {
                            ApplicationName = "",
                            GZipEnabled = true,
                            Initializers = { credential },
                        });
        httpClient.Timeout = new TimeSpan(0, 0, 5);
    }

    public string ReadObjectData(string bucketName, string location)
    {
        string responseBody = "";
        bool isFetched = false;
        try
        {
            Stopwatch sw = new Stopwatch();
            string pathcode = System.Web.HttpUtility.UrlEncode(location);
            UriBuilder uri = new UriBuilder(string.Format(googleStorageApi, bucketName, pathcode));
            sw.Start();
            var httpResponseMessage = httpClient.GetAsync(uri.Uri).Result;
            var t = sw.ElapsedMilliseconds;
            if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
            {
                responseBody = httpResponseMessage.Content.ReadAsStringAsync().Result;
                log.Info($"Read file from location : {location} in Get() time : {t} ms , ReadAsString time :  {sw.ElapsedMilliseconds - t} ms, Total time : {sw.ElapsedMilliseconds} ms");
            }
            isFetched = true;
        }
        catch (Exception ex)
        {
            throw ex;
        }
        return responseBody;
    }
}

并使用

将其称为多个文件
GCSStorage gcs = new GCSStorage();
ParallelOptions option = new ParallelOptions { MaxDegreeOfParallelism = options };
    Parallel.ForEach(myFiles, option, ri =>
    {
        text = gcs.ReadObjectData(bucket, ri); ;
    });

我正在将每个单独的文件花费的时间记录在ReadObjectData()中。当我使用MaxDegreeOfParallelism作为1下载文件时,每个文件的下载时间约为100-150ms。但是,当我将MaxDegreeOfParallelism更改为50时,时间在1-3秒之间变化。我正在下载一堆50个文件。

我不知道为什么会这样。谁能帮助我了解这种行为。

此外,我尝试使用Amazon S3进行相同操作。在这两种情况下,S3的下载时间恒定为50-100ms。

我使用提琴手分析了GCS响应。对于耗时(〜> 200ms)的请求,总体经过时间大约为100-200 ms,但是写入日志的时间要长得多。对于其他人来说,恰恰是在同一时间。 为什么某些请求的时间会有如此大的时差?

提琴手统计

Request Count:   1
Bytes Sent:      439        (headers:439; body:0)
Bytes Received:  7,759      (headers:609; body:7,150)

ACTUAL PERFORMANCE
--------------
ClientConnected:    18:03:35.137
ClientBeginRequest: 18:04:13.606
GotRequestHeaders:  18:04:13.606
ClientDoneRequest:  18:04:13.606
Determine Gateway:  0ms
DNS Lookup:         0ms
TCP/IP Connect: 0ms
HTTPS Handshake:    0ms
ServerConnected:    18:03:35.152
FiddlerBeginRequest:    18:04:13.606
ServerGotRequest:   18:04:13.606
ServerBeginResponse:    18:04:13.700
GotResponseHeaders: 18:04:13.700
ServerDoneResponse: 18:04:13.700
ClientBeginResponse:    18:04:13.700
ClientDoneResponse: 18:04:13.700

    Overall Elapsed:    0:00:00.093

日志文件

INFO  2018-08-25 18:04:13,606 41781ms GCSStorage ReadObjectData -  Get() time : 114 ms 
INFO  2018-08-25 18:04:14,512 42688ms GCSStorage ReadObjectData -  Get() time : 902 ms 

我可以看到

LogTime - ClientDoneResponse + Overall Elapsed is approximately equal to Total Time
18:04:14.512 - 18:04:13.700 + 0:00:00.093 = 905 ms

为什么从服务器接收到的响应并将其写入日志的时间差会如此之大?

1 个答案:

答案 0 :(得分:0)

在执行并行编程时,需要注意多个线程。首先,并行确实可以提高性能,但并不是说无限并行比顺序更好。这件事情是由很多原因导致的。一是您受到物理核心数量以及操作系统中超线程的限制。例如,如果您有8个核心,则使用8个线程可获得最佳性能,如果还激活了超线程,则可能只有16个线程才具有良好的性能。

在您的示例中,将线程数从1更改为50太多了。以第2、4、6、8、10步进行尝试,看看何时获得最佳性能(记录到目前为止的时间)。

那么该数字很可能是您的并行性的最佳数字。