发送短信(四):使用Redis限制发送频率和日发送次数
在前几篇文章中, 我们介绍了限制发送短信频率, 限制日发送次数等功能. 但是后来z-oneC说用Redis实现会更简单. 于是这几天我大致学了一下Redis, 然后使用Redis重新实现了一次. 当然由于刚接触Redis, 或许有些地方并不合适, 还请您在留言区留言, BK在这里先谢过了.
其实使用Redis确实挺简单, 至少没有过于复杂的概念, 庞大的命令集. 基本上入门挺快的. 剩下的就是创造力和经验了. 这里我们使用Redis来完成前两篇:《发送短信–限制发送频率》、《发送短信–限制日发送次数》完成的功能.
当然, 如果读者并没有学过Redis, 可以参见《The Little Redis Book》快速入门,这本”书”基本上半个上午就可以看完.
思路
这里我们就是简单用Redis限制”访问”频率:
- 首先根据用户手机号/IP拼凑出一个字符串的关键字.
- 然后判断该字符串的值是否为空.
- 如果为空, 则设置该字符串的值为1, 并设置生存时间. 并允许”访问”.
- 如果不为空, 则将值加一, 然后判断值是否超过使用期限时间内的最大”访问”次数
- 如果没有超过, 则允许”访问”
- 否则拒绝”访问”
编写脚本
注: 该脚本摘自《Redis入门指南》
1 | --[[ |
该脚本也比较直观:
- 首先将指定的键加一. 由于Redis的特性, 如果指定的键并不存在, 则默认为0, 并加一. 这一步相当于判断指定的键是否存在, 如果不存在, 则置指定的键为1; 否则加一
- 接着判断是否是第一次访问, 如果是, 则设置生存时间
- 最后判断是否超过了访问频率, 如果超过了访问频率, 则返回0; 否则返回1
使用Jedis调用脚本
在Redis的官网上有许多Redis的Java客户端的库. 这里我们使用Jedis.
我们来看看代码. 该程序中的ClassPathResource
和FileCopyUtils
类为Spring中的类, 因此这里的示例程序依赖于Spring
1 | public class RateLimit { |
这里的init
方法的作用就是将刚才我们写的脚本读取到script
变量中, 以便以后使用.
isExceedRate
方法将关键字和参数(过期时间和发送次数)分别封装到List
里, 之后使用Jedis调用脚本. 获取返回值, 判断频率是否过高.
使用示例
下面我们使用上面的代码完成限制发送频率的功能(部分接口和类的声明请参见《[发送短信–限制发送频率][sms2]》). 限制日发送次数的代码基本相同, 这里就不贴了, 请下载源码查看.
1 | public class FrequencyFilter implements SmsFilter { |
到这里我们的主要代码就完成了, 可以看出使用Redis后代码确实非常的简单.
由于我现在还不会性能测试, 所以只是简单的使用for
循环测试了一下性能, 虽然可能不是很准确, 但是也有一定的可信度. 在限制发送频率时, 使用ConcurrentMap
的性能更高, 貌似比例还不小, 只是由于基数并不大, 所以并没有多费多少时间(十万条记录只多花费了十五秒).
但是在限制日发送次数时, 剩下了n多时间. 综合来看, 还是只使用Redis更省时省事.
而且, 个人猜测, 在扩展到集群时, 使用Redis应该会简单些.