From 0ffb5f892da0a57a958148ae8c06a08c257e5436 Mon Sep 17 00:00:00 2001 From: xxq250 Date: Mon, 17 Jul 2023 09:34:43 +0800 Subject: [PATCH] =?UTF-8?q?api=E9=99=90=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/services/api_limit_service.rb | 137 ++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 app/services/api_limit_service.rb diff --git a/app/services/api_limit_service.rb b/app/services/api_limit_service.rb new file mode 100644 index 000000000..d22684962 --- /dev/null +++ b/app/services/api_limit_service.rb @@ -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