2017-12-10 10 views
0

レートリミッタの仕組みを理解しようとしていました。ロックなしでJavaとRedisを使用するレートリミッタ

問題文は次のとおりです。IPアドレスあたり毎秒10の要求

SOLN:私はブログで見ることができるは次のとおりです。今、私は削除古いキーに無視していますのよう

public void makeApiCall(String ip){ 
    Long currentTime=Timestamp timestamp = System.currentTimeMillis(); 

    String key=ip+":"+currentTime; 

    Integer count=redisClient.get(key); 

    if(count!=null && count > 10){ 
     throw LimitExceededException(); 
    } 
    else{ 
     redisClient.incr(key,1); 
     callApi(); 
    } 
} 

。 これがどのように機能するのか理解できません。 上記の私のコードによれば、1秒でマルチスレッド環境で10以上のAPI呼び出しを行うことになります。これは、redisClient.get(キー)をcallApi()コードに同期化することによってのみ解決できます。

私は

https://redis.io/commands/incrからこのコードを取ってきました。

上記のコードを変更することで、誰でも私がこれらのシナリオでredisを使用する正しい方法を理解するのを手伝ってもらえますか?

現在9第二の要求は5つの新しい要求が来served.now並行している中で、これらの5つのスレッドのいずれかが、スレッドごとに「他」block.Soを実行する前に、すべてのこれらの新しいスレッドが(キー)redisClient.getを呼び出すと仮定カウントは9になります。そうでない場合はブロックが実行され、incrが5回呼び出され、スレッドごとにapiが呼び出されます。

+0

上記で提供したコード(EXPIREはありません)は、1ミリ秒で 'callApi()'呼び出しを10個に制限します。あなたの質問は何ですか? –

+0

私は更新された質問があります。 – Nishat

答えて

1

実際、このコードは競合状態(および有効期限を切ってしまったためにメモリが肥大化する)に対して実際に脆弱です。これを解決するには基本的に2つの方法があります:MULTI/EXEC transaction with a WATCH、またはEVALLuaスクリプトです。

あなたのJavaクライアントとしてJedisを使用していると仮定すると、次のようなものは、取引にトリックを行う必要があります。

public void makeApiCall(String ip){ 
    Long currentTime=Timestamp timestamp = System.currentTimeMillis(); 

    String key=ip+":"+currentTime; 

    redisClient.watch(key); 
    Integer count=redisClient.get(key); 

    if(count!=null && count > 10){ 
     throw LimitExceededException(); 
    } 
    else{ 
     Transaction t = redisClient.multi(); 
     t.incr(key,1); 
     List<Object> resp = t.exec(); 
     if(resp != null){ 
      callApi(); 
     } 
    } 
} 

Luaは別の問題ですが、基本的に次のスクリプトを全体のキーを提供仮定します名前(IP + TS)、それはかなり限り、あなたのコードは、[OK]を得ることにcallApiにアップし、次のように同じことを行います。

local count = redis.call('GET', KEYS[1]) 
if count and tonumber(count) > 10 then 
    return redis.error('count exceeded') 
else 
    redis.call('INCR', KEYS[1]) 
    redis.call('EXPIRE', KEYS[1], 10) 
    return 'OK' 
end 

注意のLuaであなたが変更を監視する必要がないこと、スクリプト全体がアトミックなので

最後に、ドキュメントで参照したカウンタパターンにWATCHというものがありませんでした。私はそれを修正するためにPRを提出しました(https://github.com/antirez/redis-doc/pull/888)。

関連する問題