mwc校准油门
在僵尸网络时代,您可以租用几百美元来运行自己的分布式拒绝服务攻击,拥有紧急开关来有选择地关闭昂贵的功能或严重降低性能是一个巨大的胜利。 在缓解问题的同时,您的应用程序仍可运行。 当然,这种安全措施在高峰或工作时间也很有价值。 应用于下载服务器的这种机制之一是动态限制下载速度。 为了防止分布式拒绝服务攻击和过高的云发票,请考虑内置的下载限制,您可以在运行时启用并进行调整。 这样做的目的是限制全局或每个客户端的最大下载速度(IP,Connection,Cookie,用户代理)。
 我必须承认,我喜欢java.io设计,其中包含许多简单的Input / OutputStream和Reader / Writer实现,每个实现只承担一项责任。 您要缓冲吗? GZIPing? 字符编码? 文件系统编写? 只需编写始终可相互配合的所需类。 好的,它仍然处于阻塞状态,但是它是在被动式赶时髦的人出生之前设计的。 没关系, java.io也遵循开闭原则 :只需插入新的装饰器,就可以简单地增强现有的I / O代码而无需接触内置类。 因此,我为InputStream创建了一个简单的装饰器,以减慢我们这一边的资源读取速度,以强制执行给定的下载速度。 我正在使用我最喜欢的RateLimiter类 : 
public class ThrottlingInputStream extends InputStream {private final InputStream target;private final RateLimiter maxBytesPerSecond;public ThrottlingInputStream(InputStream target, RateLimiter maxBytesPerSecond) {this.target = target;this.maxBytesPerSecond = maxBytesPerSecond;}@Overridepublic int read() throws IOException {maxBytesPerSecond.acquire(1);return target.read();}@Overridepublic int read(byte[] b) throws IOException {maxBytesPerSecond.acquire(b.length);return target.read(b);}@Overridepublic int read(byte[] b, int off, int len) throws IOException {maxBytesPerSecond.acquire(len);return target.read(b, off, len);}//less important below...@Overridepublic long skip(long n) throws IOException {return target.skip(n);}@Overridepublic int available() throws IOException {return target.available();}@Overridepublic synchronized void mark(int readlimit) {target.mark(readlimit);}@Overridepublic synchronized void reset() throws IOException {target.reset();}@Overridepublic boolean markSupported() {return target.markSupported();}@Overridepublic void close() throws IOException {target.close();}
} 任意InputStream可以与ThrottlingInputStream打包在一起,这样实际上会减慢读取速度。 您可以为每个ThrottlingInputStream创建一个新的RateLimiter ,也可以为所有下载共享一个全局RateLimiter 。 当然,有人可能会争辩说,简单的sleep() ( RateLimiter在下面执行的操作)会浪费大量资源,但是让我们保持此示例简单,避免非阻塞I / O。 现在我们可以轻松地将装饰器插入: 
private InputStreamResource buildResource(FilePointer filePointer) {final InputStream inputStream = filePointer.open();final RateLimiter throttler = RateLimiter.create(64 * FileUtils.ONE_KB);final ThrottlingInputStream throttlingInputStream = new ThrottlingInputStream(inputStream, throttler);return new InputStreamResource(throttlingInputStream);
} 上面的示例将下载速度限制为64 KiB / s –显然,在现实生活中,您希望可配置此类编号,最好在运行时进行配置。 顺便说一句,我们已经讨论了Content-Length标头的重要性。 如果您使用pv监视下载进度,它将正确估计剩余时间,这是一个不错的功能: 
~ $ curl localhost:8080/download/4a8883b6-ead6-4b9e-8979-85f9846cab4b | pv > /dev/null% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed0 71.2M    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0  16kB 0:00:01 [14,8kB/s]0 71.2M    0 40960    0     0  30097      0  0:41:21  0:00:01  0:41:20 30095  80kB 0:00:02 [  64kB/s]0 71.2M    0  104k    0     0  45110      0  0:27:35  0:00:02  0:27:33 45106 144kB 0:00:03 [  64kB/s]0 71.2M    0  168k    0     0  51192      0  0:24:18  0:00:03  0:24:15 51184 208kB 0:00:04 [  64kB/s]0 71.2M    0  232k    0     0  54475      0  0:22:51  0:00:04  0:22:47 54475 272kB 0:00:05 [63,9kB/s]0 71.2M    0  296k    0     0  56541      0  0:22:00  0:00:05  0:21:55 67476 336kB 0:00:06 [  64kB/s]0 71.2M    0  360k    0     0  57956      0  0:21:28  0:00:06  0:21:22 65536 400kB 0:00:07 [  64kB/s]0 71.2M    0  424k    0     0  58986      0  0:21:06  0:00:07  0:20:59 65536 464kB 0:00:08 [  64kB/s]0 71.2M    0  488k    0     0  59765      0  0:20:49  0:00:08  0:20:41 65536 528kB 0:00:09 [  64kB/s]0 71.2M    0  552k    0     0  60382      0  0:20:36  0:00:09  0:20:27 65536 592kB 0:00:10 [  64kB/s]0 71.2M    0  616k    0     0  60883      0  0:20:26  0:00:10  0:20:16 65536 656kB 0:00:11 [  64kB/s]0 71.2M    0  680k    0     0  61289      0  0:20:18  0:00:11  0:20:07 65536 720kB 0:00:12 [  64kB/s] 作为一个额外的奖励, pv证明了我们的节流作用(上一栏)。 现在,没有Content-Length pv对实际的进展一无所知: 
~ $ curl localhost:8080/download/4a8883b6-ead6-4b9e-8979-85f9846cab4b | pv > /dev/null% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100 16384    0 16384    0     0  21116      0 --:--:-- --:--:-- --:--:-- 21113  32kB 0:00:01 [  31kB/s]
100 81920    0 81920    0     0  46149      0 --:--:--  0:00:01 --:--:-- 46126  96kB 0:00:02 [  64kB/s]
100  144k    0  144k    0     0  53128      0 --:--:--  0:00:02 --:--:-- 53118 160kB 0:00:03 [  64kB/s]
100  208k    0  208k    0     0  56411      0 --:--:--  0:00:03 --:--:-- 56406 224kB 0:00:04 [  64kB/s]
100  272k    0  272k    0     0  58328      0 --:--:--  0:00:04 --:--:-- 58318 288kB 0:00:05 [  64kB/s]
100  336k    0  336k    0     0  59574      0 --:--:--  0:00:05 --:--:-- 65536 352kB 0:00:06 [  64kB/s]
100  400k    0  400k    0     0  60450      0 --:--:--  0:00:06 --:--:-- 65536 416kB 0:00:07 [  64kB/s]
100  464k    0  464k    0     0  61105      0 --:--:--  0:00:07 --:--:-- 65536 480kB 0:00:08 [  64kB/s]
100  528k    0  528k    0     0  61614      0 --:--:--  0:00:08 --:--:-- 65536 544kB 0:00:09 [  64kB/s]
100  592k    0  592k    0     0  62014      0 --:--:--  0:00:09 --:--:-- 65536 608kB 0:00:10 [  64kB/s]
100  656k    0  656k    0     0  62338      0 --:--:--  0:00:10 --:--:-- 65536 672kB 0:00:11 [  64kB/s]
100  720k    0  720k    0     0  62612      0 --:--:--  0:00:11 --:--:-- 65536 736kB 0:00:12 [  64kB/s] 我们看到数据正在流动,但是我们不知道还剩下多少。 因此, Content-Length是一个非常重要的标头。 
编写下载服务器
- 第一部分:始终流式传输,永远不要完全保留在内存中
- 第二部分:标头:Last-Modified,ETag和If-None-Match
- 第三部分:标头:内容长度和范围
-  第四部分:有效地执行HEAD操作
- 第五部分:油门下载速度
- 第六部分:描述您发送的内容(内容类型等)
- 这些文章中开发的示例应用程序可在GitHub上找到。
翻译自: https://www.javacodegeeks.com/2015/07/writing-a-download-server-part-v-throttle-download-speed.html
mwc校准油门