138 lines
3.4 KiB
Ruby
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
|