令牌桶算法在Redis中的实现
- 基本原理:令牌以固定速率生成并放入桶中,请求到达时尝试从桶中获取令牌,若桶中有足够令牌则请求通过,否则限流。
- 实现思路:
- 使用Redis的
INCR
命令实现令牌生成计数。例如,可以设置一个定时任务(如使用Linux的crontab
),每隔一定时间向Redis中某个键(例如token_count
)增加固定数量的令牌。
- 每次请求到达时,使用
WATCH
和MULTI
命令来保证操作的原子性。首先WATCH
令牌键,然后使用GET
获取当前令牌数量,判断是否足够。如果足够则使用DECR
减少令牌数量,最后EXEC
执行事务。示例代码(以Python为例):
import redis
import time
r = redis.Redis(host='localhost', port=6379, db = 0)
# 模拟定时生成令牌,每10秒生成10个令牌
def generate_tokens():
while True:
r.incrby('token_count', 10)
time.sleep(10)
# 尝试获取令牌
def try_get_token():
pipe = r.pipeline()
while True:
try:
pipe.watch('token_count')
token_count = int(pipe.get('token_count'))
if token_count <= 0:
pipe.unwatch()
return False
pipe.multi()
pipe.decr('token_count')
pipe.execute()
return True
except redis.WatchError:
continue
滑动窗口算法在Redis中的实现
- 基本原理:将时间划分为多个小的时间窗口,统计每个窗口内的请求次数。当请求到达时,判断当前窗口内请求次数是否超过阈值。滑动窗口会随着时间的推移不断滑动。
- 实现思路:
- 使用Redis的有序集合(Sorted Set)来记录请求的时间戳。例如,以当前时间的毫秒数作为有序集合的分数,每次请求到达时,将当前时间戳添加到有序集合中。
- 计算滑动窗口内的请求数量时,根据当前时间和窗口大小确定窗口的起始时间戳和结束时间戳,然后使用
ZRANGEBYSCORE
命令获取该窗口内的所有时间戳数量,以此判断是否超过限流阈值。示例代码(以Python为例):
import redis
import time
r = redis.Redis(host='localhost', port=6379, db = 0)
# 记录请求
def record_request():
current_time = int(time.time() * 1000)
r.zadd('request_timestamps', {current_time: current_time})
# 判断是否限流
def is_limited(window_size, limit):
current_time = int(time.time() * 1000)
start_time = current_time - window_size * 1000
count = r.zcount('request_timestamps', start_time, current_time)
return count >= limit
Redis熔断机制触发条件
- 高延迟:当Redis处理请求的平均响应时间超过某个预设的阈值时,可能触发熔断。例如,设置平均响应时间超过100毫秒就触发熔断。这可以通过记录每个请求的响应时间并计算平均值来监控。
- 高错误率:如果Redis返回错误(如网络错误、命令执行错误等)的请求比例超过一定阈值,比如错误请求比例达到20%,可以触发熔断。可以通过统计一定时间内错误请求的数量和总请求数量来计算错误率。
- 资源限制:当Redis服务器的某些资源(如内存使用达到90%以上、CPU使用率持续超过80%等)接近或达到限制时,也可能触发熔断机制,以避免系统崩溃,保证整体服务的可用性。