| @@ -0,0 +1,137 @@ | |||
| class ApiLimitService < ApplicationService | |||
| Error = Class.new(StandardError) | |||
| def initialize() end | |||
| def call | |||
| end | |||
| # 时间窗口法 | |||
| def is_action_allowed?(user_id, action_key, period, max_count) | |||
| key = "#{user_id}:#{action_key}" | |||
| count = $redis_cache.multi do |multi| | |||
| multi.incr(key) | |||
| multi.expire(key, period) | |||
| end | |||
| count[0] <= max_count | |||
| end | |||
| # 漏桶法 | |||
| def is_action_allowed_bucket?(user_id, action_key, capacity, rate) | |||
| key = "#{user_id}:#{action_key}" | |||
| # now = (("%10.3f" % Time.now.to_f).to_f * 1000).to_i | |||
| now = Time.now.to_i | |||
| count = $redis_cache.multi do |multi| | |||
| multi.zadd(key, now, SecureRandom.uuid.gsub("-", "")) | |||
| multi.zremrangebyscore(key, 0, now - capacity) | |||
| multi.zcard(key) | |||
| multi.expire(key, (capacity / rate + 1).to_i) | |||
| end | |||
| # puts "count1==#{count}" | |||
| # puts "count2==#{count[2]}" | |||
| count[2] <= capacity | |||
| end | |||
| def is_action_allowed_aaa?(user_id, action_key, period, maxCount) | |||
| key = "#{user_id}:#{action_key}" | |||
| now = (("%10.3f" % Time.now.to_f).to_f * 1000).to_i | |||
| count = $redis_cache.multi do |multi| | |||
| # 添加命令 | |||
| multi.zadd(key, now, SecureRandom.uuid.gsub("-", "")) | |||
| # 清楚无用数据 | |||
| multi.zremrangebyscore(key, 0, now - period * 1000) | |||
| # 判断规定时间内请求数量 | |||
| multi.zcard(key) | |||
| # 重新设置过期时间 | |||
| multi.expire(key, period + 1) | |||
| end | |||
| # puts "count1==#{count}" | |||
| # puts "count2==#{count[2]}" | |||
| count[2] <= maxCount | |||
| end | |||
| def sdfsf | |||
| # 每秒钟漏斗的容量 | |||
| capacity = 10 | |||
| # 漏斗填充速度 | |||
| leak_rate = 0.3 | |||
| # 当前漏斗中的水量 | |||
| current_volume = 0 | |||
| # 上一次漏水的时间 | |||
| last_leak_time = Time.now.to_i | |||
| funnel_name = "tests" | |||
| # $redis_cache.hset(funnel_name, "volume", capacity) | |||
| $redis_cache.hset(funnel_name, "last_leak_time", Time.now.to_i) | |||
| # 构造事务命令 | |||
| # result = $redis_cache.multi do |pipe| | |||
| # # 把当前时间与上一次漏水时间的差值,作为漏斗流出水量 | |||
| # | |||
| # pipe.hget(funnel_name, "last_leak_time") | |||
| # | |||
| # pipe.hset(funnel_name, "last_leak_time", Time.now.to_i) | |||
| # | |||
| # pipe.hget(funnel_name, "volume") | |||
| # | |||
| # pipe.hget(funnel_name, "capacity") | |||
| # | |||
| # pipe.hget(funnel_name, "leak_rate") | |||
| # end | |||
| current_volume = $redis_cache.hget(funnel_name, "volume") | |||
| last_leak_time = $redis_cache.hget(funnel_name, "last_leak_time") | |||
| # 先漏水 | |||
| leaked_volume = (Time.now.to_i - last_leak_time.to_i) * leak_rate.to_f | |||
| current_volume = [current_volume.to_f + leaked_volume, capacity.to_f].sort.first | |||
| puts "current_volume====#{current_volume}" | |||
| # 判断是否可以通过请求 | |||
| if current_volume >= 1 | |||
| $redis_cache.hset(funnel_name, "volume", current_volume.to_i - 1) | |||
| # $redis_cache.hset(funnel_name, "last_leak_time", Time.now.to_i) | |||
| true | |||
| else | |||
| false | |||
| end | |||
| end | |||
| def done_test3 | |||
| 100.times.each do |t| | |||
| if t % 2== 0 | |||
| sleep(1) | |||
| end | |||
| puts "#{t}:res====#{sdfsf}" | |||
| end | |||
| end | |||
| def done_test | |||
| 100.times.each do |t| | |||
| if t % 10== 0 | |||
| sleep(5) | |||
| end | |||
| puts "#{t}:res====#{is_action_allowed_bucket?("123", "test2", 10, 0.2)}" | |||
| end | |||
| end | |||
| def done_test2 | |||
| 100.times.each do |t| | |||
| sleep(1) | |||
| puts "#{t}:res====#{is_action_allowed_aaa?("123", "test3", 10, 5)}" | |||
| end | |||
| end | |||
| end | |||