forgeplus/app/services/api_limit_service.rb

138 lines
3.4 KiB
Ruby

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