编写下载服务器。 第五部分:油门下载速度
在僵尸網(wǎng)絡(luò)時(shí)代,您可以租用幾百美元來(lái)運(yùn)行自己的分布式拒絕服務(wù)攻擊,擁有緊急開(kāi)關(guān)有選擇地關(guān)閉昂貴的功能或極大地降低性能是一個(gè)巨大的勝利。 在緩解問(wèn)題的同時(shí),您的應(yīng)用程序仍可運(yùn)行。 當(dāng)然,這種安全措施在高峰或工作時(shí)間也很有價(jià)值。 應(yīng)用于下載服務(wù)器的這種機(jī)制之一是動(dòng)態(tài)限制下載速度。 為了防止分布式拒絕服務(wù)攻擊和過(guò)高的云發(fā)票,請(qǐng)考慮內(nèi)置的下載限制,您可以在運(yùn)行時(shí)啟用并進(jìn)行調(diào)整。 這樣做的目的是限制全局或每個(gè)客戶端的最大下載速度(IP,Connection,Cookie,用戶代理?)。
我必須承認(rèn),我喜歡java.io設(shè)計(jì),其中包含許多簡(jiǎn)單的Input / OutputStream和Reader / Writer實(shí)現(xiàn),每個(gè)實(shí)現(xiàn)只承擔(dān)一項(xiàng)責(zé)任。 您要緩沖嗎? GZIPing? 字符編碼? 文件系統(tǒng)編寫(xiě)? 只需編寫(xiě)所需的類,它們始終可以相互配合。 好的,它仍然處于阻塞狀態(tài),但是它是在被動(dòng)式趕時(shí)髦的人出生之前設(shè)計(jì)的。 沒(méi)關(guān)系, java.io也遵循開(kāi)閉原則 :只需插入新的裝飾器,就可以簡(jiǎn)單地增強(qiáng)現(xiàn)有的I / O代碼而無(wú)需觸及內(nèi)置類。 因此,我為InputStream創(chuàng)建了一個(gè)簡(jiǎn)單的裝飾器,以減慢我們這一邊的資源讀取速度,以強(qiáng)制執(zhí)行給定的下載速度。 我正在使用我最喜歡的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打包在一起,這樣實(shí)際上會(huì)減慢讀取速度。 您可以為每個(gè)ThrottlingInputStream創(chuàng)建一個(gè)新的RateLimiter ,也可以為所有下載共享一個(gè)全局RateLimiter 。 當(dāng)然,有人可能會(huì)爭(zhēng)辯說(shuō),簡(jiǎn)單的sleep() ( RateLimiter在下面執(zhí)行的操作)會(huì)浪費(fèi)大量資源,但是讓我們保持此示例簡(jiǎn)單,避免非阻塞I / O。 現(xiàn)在我們可以輕松地將裝飾器插入:
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 –顯然,在現(xiàn)實(shí)生活中,您可能希望可配置此類編號(hào),最好在運(yùn)行時(shí)進(jìn)行配置。 順便說(shuō)一句,我們已經(jīng)討論了Content-Length標(biāo)頭的重要性。 如果您使用pv監(jiān)視下載進(jìn)度,它將正確估計(jì)剩余時(shí)間,這是一個(gè)不錯(cuò)的功能:
~ $ 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]作為一個(gè)額外的獎(jiǎng)勵(lì), pv證明了我們的節(jié)流作用(上一欄)。 現(xiàn)在,沒(méi)有Content-Length pv對(duì)于實(shí)際的進(jìn)展一無(wú)所知:
~ $ 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]我們看到數(shù)據(jù)正在流動(dòng),但是我們不知道還剩下多少。 因此, Content-Length是一個(gè)非常重要的標(biāo)頭。
編寫(xiě)下載服務(wù)器
- 第一部分:始終流式傳輸,永遠(yuǎn)不要完全保留在內(nèi)存中
- 第二部分:標(biāo)頭:Last-Modified,ETag和If-None-Match
- 第三部分:標(biāo)頭:內(nèi)容長(zhǎng)度和范圍
- 第四部分:有效地實(shí)現(xiàn)HEAD操作
- 第五部分:油門(mén)下載速度
- 第六部分:描述您發(fā)送的內(nèi)容(內(nèi)容類型等)
- 這些文章中開(kāi)發(fā)的示例應(yīng)用程序可在GitHub上找到。
翻譯自: https://www.javacodegeeks.com/2015/07/writing-a-download-server-part-v-throttle-download-speed.html
總結(jié)
以上是生活随笔為你收集整理的编写下载服务器。 第五部分:油门下载速度的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 进入linux命令行(进入linux命令
- 下一篇: 蓝光播放安卓下载(蓝光播放安卓)