如何处理线程池达到服务器连接限制
How to handle ThreadPool hitting the server connection limit
我可能会在这里问一个设计模式问题。
在Android,我正在使用线程池打开8个线程来下载一些文件。
try {
ExecutorService pool = Executors.newFixedThreadPool(8);
for (int i = 0; i < someList.size(); i++) {
pool.submit(new DownloadJsonTask(someList.get(i), context));
}
pool.shutdown();
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (Exception e) {
}
我注意到如果我使用一个线程一个一个地下载,那么我几乎不会下载失败,但是如果我使用8个线程,那么我有时会下载失败。我不是 server/network 人,所以我不知道详细信息,但我猜测服务器正在限制一台设备(或一个 IP 地址)尝试连接多个连接。
如果是这个原因,那么我该如何设计代码来克服这个问题呢?我已经实现在失败前尝试下载 3 次。它似乎确实修复了它 "for now"。但是,我知道我的代码并不健壮,它可能会在某一时刻失败。
我想,我不会是第一个遇到这个问题的人。我想知道关于这个问题的可靠解决方案。
我能想到的解决方案:
- 尝试至少下载 3 次才失败
- 一旦失败,则尝试随机休眠一段时间。这样失败的线程就不会同时醒来并再次失败。
- 如果服务器返回某种独特的消息,例如服务器忙,则重试无限(?)(大量)次。
我还没有实施以上可能的解决方案。我想先了解 common/best 解决方案,然后花时间实施它。
有什么想法吗?
这个问题是基于意见的。我正在分享我对此的看法。
理想情况下,如果您可以检查服务器日志并发现应该修复服务器端的问题,那么您绝对应该首先这样做。
除此之外,即使客户端和服务器能够多线程并处理并发,也总是会出现网络故障。也就是说,你应该在你的客户端有一个重试机制。
关于重试策略的一些设计要点
- 保持重试次数可配置,而不是将其固定为 3 次。(您可以在分析和测试时提出正确的尝试次数)
- 与其随机睡眠,不如试试 exponential backoff。
- 我们可以标记一条消息给用户,让我们自己在指数退避重试后重试,而不是无限次地重试。 (类似于 'Site under load. Please try after some time')。
- 查看为您重试的库。类似于 this.
- 网络带宽也可能是下载失败的原因。您可以监控网络速度和类型(WiFi、LTE、3G)等,并决定是否下载或安排稍后下载。
另一篇文章here。
希望这对您有所帮助。
我可能会在这里问一个设计模式问题。
在Android,我正在使用线程池打开8个线程来下载一些文件。
try {
ExecutorService pool = Executors.newFixedThreadPool(8);
for (int i = 0; i < someList.size(); i++) {
pool.submit(new DownloadJsonTask(someList.get(i), context));
}
pool.shutdown();
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
} catch (Exception e) {
}
我注意到如果我使用一个线程一个一个地下载,那么我几乎不会下载失败,但是如果我使用8个线程,那么我有时会下载失败。我不是 server/network 人,所以我不知道详细信息,但我猜测服务器正在限制一台设备(或一个 IP 地址)尝试连接多个连接。
如果是这个原因,那么我该如何设计代码来克服这个问题呢?我已经实现在失败前尝试下载 3 次。它似乎确实修复了它 "for now"。但是,我知道我的代码并不健壮,它可能会在某一时刻失败。
我想,我不会是第一个遇到这个问题的人。我想知道关于这个问题的可靠解决方案。
我能想到的解决方案:
- 尝试至少下载 3 次才失败
- 一旦失败,则尝试随机休眠一段时间。这样失败的线程就不会同时醒来并再次失败。
- 如果服务器返回某种独特的消息,例如服务器忙,则重试无限(?)(大量)次。
我还没有实施以上可能的解决方案。我想先了解 common/best 解决方案,然后花时间实施它。
有什么想法吗?
这个问题是基于意见的。我正在分享我对此的看法。
理想情况下,如果您可以检查服务器日志并发现应该修复服务器端的问题,那么您绝对应该首先这样做。
除此之外,即使客户端和服务器能够多线程并处理并发,也总是会出现网络故障。也就是说,你应该在你的客户端有一个重试机制。
关于重试策略的一些设计要点
- 保持重试次数可配置,而不是将其固定为 3 次。(您可以在分析和测试时提出正确的尝试次数)
- 与其随机睡眠,不如试试 exponential backoff。
- 我们可以标记一条消息给用户,让我们自己在指数退避重试后重试,而不是无限次地重试。 (类似于 'Site under load. Please try after some time')。
- 查看为您重试的库。类似于 this.
- 网络带宽也可能是下载失败的原因。您可以监控网络速度和类型(WiFi、LTE、3G)等,并决定是否下载或安排稍后下载。
另一篇文章here。
希望这对您有所帮助。