发送SPDY请求导致“请求超时". iOS中的NSUrlSession错误 [英] Sending SPDY requests results in "The request timed out" errors with NSUrlSession in iOS

查看:419
本文介绍了发送SPDY请求导致“请求超时". iOS中的NSUrlSession错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My iOS app loads images from an nginx HTTP server. After I send 400+ such requests the networking 'gets stuck' and all subsequent HTTP requests result in "The request timed out" error. I can make the images load again only when I restart the app.

详细信息:

  1. 我正在使用NSURLSession.sharedSession().dataTaskWithURL向jpeg文件发送四百个HTTP GET请求.
  2. 请求按顺序发送,一个接一个.请求之间的间隔为10毫秒.
  3. 使用NSURLSessionDataTask对象的cancel()方法取消每个先前未完成的请求.
  1. I am using NSURLSession.sharedSession().dataTaskWithURL to send four hundred HTTP GET requests to jpeg files.
  2. Requests are sent sequentially, one after another. The interval between requests is 10 ms.
  3. Each previous unfinished request is cancelled with cancel() method of NSURLSessionDataTask object.

有趣的是:

  1. 我只能在HTTPS请求和服务器上启用SPDY时遇到此问题.
  2. 非安全的HTTP请求可以正常工作.
  3. 非SPDY HTTPS请求可以正常工作.我通过在nginx配置中的服务器端关闭SPDY进行了测试.
  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%.
  1. I can only have this issue with HTTPS requests and when SPDY is enabled on the server.
  2. Non-secure HTTP requests work fine.
  3. Non-SPDY HTTPS requests work fine. I tested it by turning SPDY off on the server side, in the nginx config.
  4. Problem appears both on iOS 8 and 9, on physical device and in the simulator. Both on Wi-Fi and LTE.
  5. When I look at nginx access logs, I can still see the 'stuck' requests coming in. Important nuance: the request log record appears at the exact moment when the iOS app is giving up on it after the time out period ends.
  6. I was hoping to analyze HTTP requests with Charles Proxy but the problem cures itself when requests go through Charles. That is - everything works with Charles, much like effect in quantum mechanics when the fact of looking influences the outcome.
  7. I was able to reproduce the issue when the iOS app connected to two different servers with vastly different nginx configurations. This probably means that the issue is not related to a particular nginx setup.
  8. I analyzed the app using "Activity Monitor" instrument. The number of threads it is using during the bulk HTTP requests jumps from 5 to 10. In comparison, when I send just a single HTTP requests the number of threads jumps to 8. CPU load rarely goes above 30%.

是什么原因引起的?谁能推荐其他方法或工具来对其进行分析和调试?

What can be the cause of the issue? Can anyone recommend other ways or tools for analysing and debugging it?

此演示应用程序会100%地为我重现该问题.

This demo app reproduces the issue 100% of the time for me.

https://github.com/exchangegroup/ImageLoadDemo

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

My nginx config: http://pastebin.com/pYYjdxfP

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

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

只有为每个单独的请求创建一个新的NSURLSession并使用finishTasksAndInvalidateinvalidateAndCancel清除上一个会话时,我才设法使请求保持工作状态.

I managed to keep requests working only if I create a new NSURLSession for each individual request and clear the previous session with finishTasksAndInvalidate or invalidateAndCancel.

// 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 ...

推荐答案

一种可能性是iOS开始发送请求,然后数据包丢失导致报头和请求主体无法完全交付.

One possibility is that iOS started sending the request, and then packet loss prevented the headers and request body from being fully delivered.

想到的另一种可能性是,您的服务器可能直到真正完成传递请求后才记录请求,这将使服务器日志中的时间戳与关闭连接的时间(而不是何时关闭)对齐.它被打开了. (IIRC,这就是Apache所做的;我没有使用过nginx,所以我不能说它的行为.)如果是这种情况,那么这只是一个简单的连接停顿.至于为什么停滞,我无法猜测.

Another possibility that comes to mind is that your server may not be logging the request until it actually finishes trying to deliver it, which would make the time stamps in the server logs line up with when the connection was closed, rather than when it was opened. (IIRC, that's what Apache does; I haven't worked with nginx, so I can't speak for its behavior.) If that's the case, then this is just a simple connection stall. As for why it is stalling, I couldn't guess.

该问题是否仅发生在HTTPS流量上?如果您可以使用HTTP复制它,则不需要Charles Proxy;只需使用OS X的"Internet共享"功能,并使用tcpdump或Wireshark捕获数据包,并在网桥接口上进行侦听.如果您无法使用HTTP进行复制,那么在验证服务器证书的同时,获取CRL或执行OCSP检查将是我的钱.

Does the problem occur exclusively for HTTPS traffic? If you can reproduce it with HTTP, you don't need Charles Proxy; just use OS X's "Internet Sharing" feature, and capture the packets with tcpdump or wireshark, listening on the bridge interface. If you can't reproduce it with HTTP, my money would be on a problem with fetching the CRLs or performing the OCSP check while validating the server's certificate.

您的应用是否由于大量异步分配给新队列而导致大量线程终止?因为那样很容易引起各种奇怪的不良行为.

Is your app ending up with a huge number of threads as a result of excessive async dispatching to new queues, by any chance? Because that could easily cause all sorts of odd misbehavior.

超时多长时间?如果太短,那么您的应用可能仅在遇到硬件性能限制的情况下运行,而仅在四秒钟内处理了400个请求的结果.

How long is the timeout? If it is too short, your app might simply be running up against performance limitations of the hardware while processing the results of 400 requests delivered in only four seconds.

此外,您是否要同时安排这些请求?因为我似乎想起曾经读过一个错误的知识,如果您同时在单个会话中启动太多任务,该错误会导致NSURLSession碰壁.您可能仅在会话中的任务数降至某个阈值以下后尝试添加任务,然后查看是否可以解决问题.

Also, are you trying to schedule these requests simultaneously? Because I seem to recall reading about a bug that causes NSURLSession to hit a brick wall if you start too many tasks in a single session at the same time. You might try adding tasks only after the number of tasks in a session drops below some threshold and see if that fixes the problem.

这篇关于发送SPDY请求导致“请求超时". iOS中的NSUrlSession错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆