十三、Redis进阶-实现访问频率限制

作者: 温新

分类: 【Redis】

阅读: 2380

时间: 2020-09-02 13:43:36

需求:限制每分钟每个用户最多只能访问100个页面

解决思路

1)为用户取一个有意义的String键名,用户每次访问使用incr命令递增该键的值

2)递增后值为1(第一次访问),则为该键设置过期时间60秒

3)该键值超过100,则进行限制

实现方式一 Sting

伪代码实现

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 判断该键是否存在,存在返回1,不存在返回0</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(130, 170, 255)">$isKeyExists</span> <span style="box-sizing: border-box;color: rgb(137, 221, 255)">=</span> exists rate.limiting:<span style="box-sizing: border-box;color: rgb(130, 170, 255)">$userId</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(199, 146, 234)">if</span> <span style="box-sizing: border-box;color: rgb(130, 170, 255)">$isKeyExists</span> is  <span style="box-sizing: border-box;color: rgb(255, 83, 112)">1</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(130, 170, 255)">$times</span> <span style="box-sizing: border-box;color: rgb(137, 221, 255)">=</span> incr rate.limiting:<span style="box-sizing: border-box;color: rgb(130, 170, 255)">$userId</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 判断用户访问是否超过限制</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">if</span> times > <span style="box-sizing: border-box;color: rgb(255, 83, 112)">100</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">  <span style="box-sizing: border-box;color: rgb(255, 203, 107)">echo</span> 频繁访问,请稍后再试</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">  <span style="box-sizing: border-box;color: rgb(199, 146, 234)">exit</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(199, 146, 234)">else</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> multi</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> incr rate.limiting:<span style="box-sizing: border-box;color: rgb(130, 170, 255)">$userId</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> expire <span style="box-sizing: border-box;color: rgb(130, 170, 255)">$keyName</span> <span style="box-sizing: border-box;color: rgb(255, 83, 112)">60</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> exec</span>

实现方式二 List

方式一存在的问题,如果一个用户在第一分钟的最后一秒访问了99次,在下一分钟的第一秒访问了100次,相当于在两秒访问了199次, 与一分钟内最多只能访问100次相比还是差距比较大,尽管这种情况比较极端,但是依然存在。如果要实现粒度更小的控制方式,精确的保证每分钟最多访问100次,就需要使用第二种方案。

如果键中的元素超过100个,就判断时间最早的元素距离现在的时间是否小于1分钟,如果是,则表示用户最近1分钟的访问次数超过100次,如果不是就将当前时间加入列表中,同时把最早的元素删除。

伪代码实现

<span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 获取列表长度</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(130, 170, 255)">$limitLength</span> <span style="box-sizing: border-box;color: rgb(137, 221, 255)">=</span> llen rate.limting:<span style="box-sizing: border-box;color: rgb(130, 170, 255)">$userId</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 判断是否超过限制</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(199, 146, 234)">if</span> <span style="box-sizing: border-box;color: rgb(130, 170, 255)">$limitLength</span> < <span style="box-sizing: border-box;color: rgb(255, 83, 112)">100</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> lpush rate.limiting:<span style="box-sizing: border-box;color: rgb(130, 170, 255)">$userId</span> now()</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"><span style="box-sizing: border-box;color: rgb(199, 146, 234)">else</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 获取最后一个元素</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(130, 170, 255)">$time</span> <span style="box-sizing: border-box;color: rgb(137, 221, 255)">=</span> lindex rate.limiting:<span style="box-sizing: border-box;color: rgb(130, 170, 255)">$userId</span> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">-1</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">if</span> now() <span style="box-sizing: border-box;color: rgb(199, 146, 234)">-</span> <span style="box-sizing: border-box;color: rgb(130, 170, 255)">$time</span> < <span style="box-sizing: border-box;color: rgb(255, 83, 112)">60</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">  <span style="box-sizing: border-box;color: rgb(255, 203, 107)">echo</span> 频繁访问,请稍后再试</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px"> <span style="box-sizing: border-box;color: rgb(199, 146, 234)">else</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">  lpush rate.limiting:<span style="box-sizing: border-box;color: rgb(130, 170, 255)">$userId</span> now()</span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">  <span style="box-sizing: border-box;color: rgb(103, 110, 149)"># 删除0~99以外的元素</span></span><br></br><span style="box-sizing: border-box;padding-right: 0.1px">  ltrim rate.limiting:<span style="box-sizing: border-box;color: rgb(130, 170, 255)">$userId</span> <span style="box-sizing: border-box;color: rgb(255, 83, 112)">0</span> <span style="box-sizing: border-box;color: rgb(255, 83, 112)">99</span></span>


我是夕阳何处寻,期待和优秀的你一起同行!

小白

2020年09月02日

请登录后再评论