<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    jinfeng_wang

    G-G-S,D-D-U!

    BlogJava 首頁 新隨筆 聯(lián)系 聚合 管理
      400 Posts :: 0 Stories :: 296 Comments :: 0 Trackbacks
    http://www.tuicool.com/articles/ZvURvq2  


    摘要

    • 我們希望服務(wù)器能在請求流量的控制上有一定的自動控制能力;
    • 本文通過簡介令牌桶算法和討論算法的 redis 實現(xiàn)給出流量整形(traffic shaping)的示例,來介紹網(wǎng)絡(luò)流量整形。

    令牌桶算法

    • 令牌桶算法 (token bucket) 并不是網(wǎng)絡(luò)流量整形中的奇技淫巧,而是非常常用的算法,從百度百科上已經(jīng)可以對它有一個概括的了解。對此算法的深入讀者可自行查閱研究,這里我通俗化的來解釋一下這個算法。

    • 在令牌桶算法中,每一個訪客都擁有一個獨立的“令牌桶”,在這個“令牌桶”里放了一些“令牌”,訪客每次來訪都會消耗“令牌桶”中的“令牌”,如果“令牌桶”空了,將會對訪客做特殊處理(如拒絕其繼續(xù)訪問以達(dá)到限流的目的)。

    • 問題一:訪客來訪是一個持續(xù)的過程,如果最初的“令牌”數(shù)目固定,“令牌桶”中的令牌會慢慢被消耗殆盡,這樣正常的訪客也將無法訪問—-所以我們需要以一個恒定的速率來向“令牌桶”中添加一定數(shù)量的“令牌”, 這樣就可以讓訪客持續(xù)的訪問。

    • 問題二:我們以一個恒定速率向“令牌桶”中添加“令牌”, 那么如果訪客一直沒來訪他的“令牌桶”豈不會累積大量“令牌”么?—-所以,我們設(shè)定“令牌桶”中“令牌”的最大數(shù)量,“令牌桶”滿了就不需要再去添加了。這解決了“令牌”累積的問題,也使它更像一個“桶”。

    • 如此,“令牌桶算法”中的重要的參數(shù)有:1. 給“令牌桶”添加“令牌”的速率(如果訪客以這個速率消耗令牌,將一直不會被限流); 2. “令牌桶”的容量(如果消耗令牌的速率大于添加令牌的速率,將消耗桶中的存貨,如果消耗速率過大,令牌會被消耗殆盡,訪客將被限流)。注意:一般情況下“令牌桶”最初的狀態(tài)是滿的。

    Redis

    • 作為優(yōu)秀的內(nèi)存數(shù)據(jù)庫,redis 可以幫助我們在應(yīng)用層次快速響應(yīng)。本文不過多贅述 redis 的優(yōu)劣,你可以用 redis 做很多事情,在網(wǎng)絡(luò)流量整形方面,它是很好的實現(xiàn)方案, 下面我們來解析這樣一個方案。

    Show me the code

    • 說明:這是一段 Python 代碼,這段代碼來自 GitHub 用戶 justinfay 。為了使邏輯更清楚,我修改了代碼的部分內(nèi)容和注釋,以下是修改后的代碼,我們用這段代碼來看令牌桶算法的 redis 實現(xiàn)。
    import redis from redis import WatchError import time  RATE = 0.1 # 令牌桶的最大容量 DEFAULT = 100 # redis key 的過期時間 TIMEOUT = 60 * 60  r = redis.Redis()  def token_bucket(tokens, key):      pipe = r.pipeline()     while 1:         try:             pipe.watch('%s:available' % key)             pipe.watch('%s:ts' % key)              current_ts = time.time()              # 獲取令牌桶中剩余令牌             old_tokens = pipe.get('%s:available' % key)             if old_tokens is None:                 current_tokens = DEFAULT             else:                 old_ts = pipe.get('%s:ts' % key)                 # 通過時間戳計算這段時間內(nèi)應(yīng)該添加多少令牌,如果桶滿,令牌數(shù)取桶滿數(shù)。                 current_tokens = float(old_tokens) + min(                     (current_ts - float(old_ts)) * RATE,                     DEFAULT - float(old_tokens)                 )             # 判斷剩余令牌是否足夠             if 0 <= tokens <= current_tokens:                 current_tokens -= tokens                 consumes = True             else:                 consumes = False              # 以下動作為更新 redis 中key的值,并跳出循環(huán)返回結(jié)果。             pipe.multi()             pipe.set('%s:available' % key, current_tokens)             pipe.expire('%s:available' % key, TIMEOUT)             pipe.set('%s:ts' % key, current_ts)             pipe.expire('%s:ts' % key, TIMEOUT)             pipe.execute()             break         except WatchError:             continue         finally:             pipe.reset()     return consumes  if __name__ == "__main__":     tokens = 5     key = '192.168.1.1'     if token_bucket(tokens, key):         print 'haz tokens'     else:         print 'cant haz tokens'

    需要說的幾點

    1. 這段代碼在網(wǎng)絡(luò)流量整形策略中起到什么作用?

    • 對訪客的一次訪問,我們通過以上代碼可以來判斷此次訪問是否超過了我們的限制,通過返回的判斷結(jié)果,我們將對此次訪問選擇正確的處理策略,比如你可以拒絕消耗完令牌的訪客進(jìn)行訪問,從而控制他的訪問速率,從而達(dá)到網(wǎng)絡(luò)流量整形的目的。

    2. redis 在其中如何工作?

    • 對于每個獨立的訪客,redis 會為他建立兩個 key,一個 key 保存了剩余令牌的數(shù)量,另外一個 key 保存了最近一次訪問的時間戳。其中,最近一次訪問時間戳在新訪問到來時候用于計算時間間隔,從而計算在此時間間隔內(nèi)應(yīng)該向令牌桶中添加多少令牌,進(jìn)而獲得當(dāng)前令牌桶的剩余令牌數(shù)。

    3. redis pipe 起到什么作用?

    • 我們看到代碼中 while 循環(huán),執(zhí)行了 redis pipe 中的 watch 動作,這是對 redis 事務(wù) 的使用。 這使這里的算法能處理并發(fā)的來訪。在 redis 中,事務(wù)執(zhí)行是對 redis key 的一個加鎖的操作,一個事務(wù)沒有執(zhí)行完,別的動作將無法操作這個 key ,代碼中循環(huán)執(zhí)行 watch 動作,就是去檢查當(dāng)前 key 是否有未執(zhí)行完畢的事務(wù),只有所有事務(wù)都執(zhí)行的時候才可能進(jìn)入執(zhí)行體,完成令牌判斷或者消耗。 —— 這樣避免了并發(fā)的訪問在 set redis key 時候的混亂。

    4. 如何調(diào)參

    • 代碼中 RATE 和 DEFAULT 為主要參數(shù),分別代表每秒鐘消耗令牌的速率,和令牌桶的容量。通過調(diào)整這兩個參數(shù)來控制你想要的訪問速率。

    總結(jié)

    • 這是一個實用的方式來完成網(wǎng)絡(luò)流量整形,可以有效控制一些爆發(fā)式的流量訪問,使訪問更加平滑容易控制。
    posted on 2016-12-14 17:39 jinfeng_wang 閱讀(166) 評論(0)  編輯  收藏 所屬分類: 2016-REDIS
    主站蜘蛛池模板: 在线观看无码AV网站永久免费| 日本人的色道www免费一区| 国产精品亚洲不卡一区二区三区| 亚洲欧洲一区二区| 色老头综合免费视频| 在线看片无码永久免费视频| 国产亚洲人成网站在线观看不卡| 青草久久精品亚洲综合专区| 国产精品久久免费| 久久精品国产精品亚洲艾| 在线观看国产一区亚洲bd| 综合在线免费视频| 亚洲成AV人片在线观看无码| 特级毛片A级毛片100免费播放| 国产成人无码免费看视频软件| 亚洲av日韩av激情亚洲| eeuss影院www天堂免费| 日本无吗免费一二区| 亚洲一区动漫卡通在线播放| 免费人成毛片动漫在线播放| 亚洲日韩国产精品乱| 亚洲国产精品ⅴa在线观看| 国产精品1024永久免费视频| 亚洲国产高清在线| 中文字幕成人免费高清在线视频 | 国产精品黄页免费高清在线观看| 精品国产免费观看一区| 亚洲制服丝袜在线播放| 99热在线免费观看| 久久精品国产精品亚洲艾草网| a级成人免费毛片完整版| 亚洲AV无码不卡在线观看下载| 亚洲精品天堂成人片AV在线播放| 韩国免费一级成人毛片| 亚洲熟妇色自偷自拍另类| 亚洲a一级免费视频| 亚洲AV综合色区无码一区爱AV| 中文在线观看免费网站| 亚洲一区无码精品色| 牛牛在线精品观看免费正| 免费国产成人午夜私人影视|