发送SPDY请求会导致iOS中的NSUrlSession出现“请求超时”错误

时间:2015-09-10 04:45:45

标签: ios swift nginx nsurlsession

我的iOS应用从nginx HTTP服务器加载图片。发送400多个此类请求后,网络“卡住”,所有后续HTTP请求都会导致“请求超时”错误。只有在我重新启动应用程序时,我才能再次加载图像。

详细信息:

  1. 我正在使用NSURLSession.sharedSession().dataTaskWithURL向jpeg文件发送400个HTTP GET请求。
  2. 请求是一个接一个地顺序发送的。请求之间的间隔为10毫秒。
  3. 使用cancel()对象的NSURLSessionDataTask方法取消之前的每个未完成请求。
  4. 有趣的是:

    1. 我只能在HTTPS请求和服务器上启用SPDY时遇到此问题。
    2. 非安全HTTP请求正常工作。
    3. 非SPDY HTTPS请求正常工作。我通过在服务器端关闭SPDY来测试它,在nginx配置中。
    4. 问题出现在iOS 8和9上,物理设备和模拟器中。无论是Wi-Fi还是LTE。
    5. 当我查看nginx访问日志时,我仍然可以看到“卡住”请求进入。重要的细微差别:请求日志记录出现在iOS应用程序在超时期限结束后放弃的确切时刻
    6. 我希望用Charles Proxy来分析HTTP请求,但是当请求通过Charles时,问题会自行解决。也就是说 - 一切都与查尔斯一起工作,就像量子力学中的效果一样,当看起来影响结果时。
    7. 当iOS应用程序连接到具有截然不同的nginx配置的两个不同服务器时,我能够重现该问题。这可能意味着该问题与特定的nginx设置无关。
    8. 我使用“活动监视器”工具分析了应用程序。它在批量HTTP请求期间使用的线程数从5跳到10.相比之下,当我只发送一个HTTP请求时,线程数跳转到8. CPU负载很少超过30%。
    9. 问题的原因是什么?任何人都可以推荐其他方法或工具来分析和调试它吗?

      使用计划工具进行分析

      enter image description here

      演示应用

      这个演示应用程序100%的时间为我重现了这个问题。

      https://github.com/exchangegroup/ImageLoadDemo

      版本和设置

      我的nginx配置:http://pastebin.com/pYYjdxfP

      OS X :10.10.4(14E46), iOS :8和9, Xcode :7.0(7A218), nginx :1.9.4

      不理想的解决方法

      只有在为每个请求创建新的NSURLSession并使用finishTasksAndInvalidateinvalidateAndCancel清除上一个会话时,我才设法保持请求有效。

      // Request 1
      
      let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()     
      let session = NSURLSession(configuration: configuration)
      session.dataTaskWithURL ...
      
      // Request 2
      
      // clear the previous request
      session.finishTasksAndInvalidate()
      let session2 = NSURLSession(configuration: configuration)
      session2.dataTaskWithURL ...
      

1 个答案:

答案 0 :(得分:1)

一种可能性是iOS开始发送请求,然后数据包丢失阻止了标头和请求主体完全交付。

另一种可能的想法是,您的服务器可能没有记录请求,直到它实际完成尝试传递它,这会使服务器日志中的时间戳与连接关闭时的时间戳对齐,而不是在它被打开了。 (IIRC,这就是Apache所做的;我还没有和nginx一起工作,所以我不能说它的行为。)如果是这样,那么这只是一个简单的连接失速。至于它为何停滞不前,我无法猜测。

问题是否仅针对HTTPS流量发生?如果你可以用HTTP重现它,你就不需要Charles Proxy;只需使用OS X"互联网共享"功能,并使用tcpdump或wireshark捕获数据包,在网桥接口上侦听。如果您无法使用HTTP重现它,那么在验证服务器证书时,我的钱将会出现获取CRL或执行OCSP检查的问题。

由于过度异步调度到新队列,您的应用程序是否会以大量线程结束?因为这很容易引起各种奇怪的不端行为。

超时有多长?如果它太短,您的应用程序可能只是在遇到硬件的性能限制时运行,同时处理仅在四秒内发送的400个请求的结果。

另外,您是否尝试同时安排这些请求?因为我似乎记得如果你在同一时间在一个会话中启动太多任务,那么就会读到一个导致NSURLSession碰到砖墙的错误。您可以尝试仅在会话中的任务数量低于某个阈值后添加任务,并查看是否可以解决问题。