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