Redis+Lua限制发送量及遇到的坑

2023-11-12

业务中需要限制每个账号每天发送短信数量,如果没有超过设置的发送量,则正常发送,否则返回失败。

解决思路:

  • 账号ID+yyyyMMdd组成redis的key,value为当天的发送量。
  • 在发送前获取账号ID+yyyyMMdd的值,如果没有超过发送量,则账号ID+yyyyMMdd对应的值+1,发送短信,如果账号ID+yyyyMMdd对应的值大于发送量,则返回失败。
  • 设置账号ID+yyyyMMdd的过期时间为1天。
  • 考虑并发问题,“查询账号ID+yyyyMMdd的值”和“账号ID+yyyyMMdd对应的值+1”需要同步执行。

综上考虑,决定采用redis+lua来解决上述问题。代码片段如下:

lua脚本 smslimit.lua

local key = KEYS[1]
local keyseconds = tonumber(ARGV[1])
local limitcount = tonumber(ARGV[2])

local val = redis.call('INCRBY', key, 1)

if val == 1 then
    redis.call('EXPIRE', key, keyseconds)
end

if val > limitcount then
    return '1'
end

return '0';
频率限制接口 DateLimitService.java
/**
 * @author conquer on 2021/7/5 5:04 下午
 */
public interface DateLimitService {

    /**
     * 是否超过发送限制
     *
     * @param accountId
     * @return
     */
    Boolean isSendExceedLimit(Integer accountId);
}

频率限制服务 DateLimitServiceImpl.java

@Service
@Slf4j
public class DateLimitServiceImpl implements DateLimitService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final DefaultRedisScript<String> SCRIPT = new DefaultRedisScript<>();

    public static final String LUA_RELATIVE_PATH = "lua/smslimit.lua";

    static {
        SCRIPT.setResultType(String.class);
        SCRIPT.setLocation(new ClassPathResource(LUA_RELATIVE_PATH));
    }


    /**
     * 账号是否超过今天发送量
     * 
     * @param accountId
     * @return
     */
    @Override
    public Boolean isSendExceedLimit(Integer accountId) {
        /**
         * List设置lua的KEYS
         */
        List<String> keyList = new ArrayList();
        String ttl = "";
        String limitCount = "";

        
        keyList.add("DAY_SEND_COUNT" + DateUtil.format(new Date(), "yyyyMMdd") + ":" + accountId);
        ttl = String.valueOf(24 * 60 * 60);

        // 一天最多发送1000条
        limitCount = String.valueOf(1000);
        

        String res = stringRedisTemplate.execute(SCRIPT, keyList, ttl, 1000);

        log.info("res: {}", res);

        // 比对结果为1表示,超出限制
        if ("1".equals(res)) {
            log.info("send limit, accountId: {}", accountId);
            return true;
        }
        return false;
    }
}

说一下踩到的坑:

刚开始我把ttl和limitCount两个字段直接放在keyList中,在lua脚本中使用KEYS[1]、KEYS[2]、KEYS[3] 取出ttl和limitCount字段,在测试环境(单机模式)运行正常,但是发布到线上(分片集群模式)后发现报错,提示key找不到。猜测可能是因为把参数放在keyList的原因,改完后测试发现没问题。

所以需要严格规范地把redis中的key放在keyList,参数放在stringRedisTemplate.execute()方法后面。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redis+Lua限制发送量及遇到的坑 的相关文章

  • Java将字符串解析为double

    如何解析字符串中的这个 Double 00034800 变成 Double 值 最后两位数字实际上是小数点 所以我正在寻找的结果是348 00 是否有这样的格式可以与十进制格式一起使用 Well String s 00034800 doub
  • Android:如何暂停和恢复可运行线程?

    我正在使用 postDelayed 可运行线程 当我按下按钮时 我需要暂停并恢复该线程 请任何人帮助我 这是我的主题 protected void animation music6 music4 postDelayed new Runnab
  • 在Windows Server 2003下如何在本地系统帐户下运行jvisualvm.exe?

    我在带有 Java 1 6 u 20 的 Windows Server 2003 下将 GlassFish 3 0 1 作为 Windows 服务运行 总体上我很满意 我希望能够在这个 JVM 上使用 VisualVM 并使用无法在 Tom
  • 使用 proguard 混淆文件名

    我正在使用 proguard 和 Android Studio 混淆我的 apk 当我反编译我的apk时 我可以看到很多文件 例如aaa java aab java ETC 但我项目中的所有文件都有原始名称 有没有办法混淆我的项目的文件名
  • 如何以编程方式使用包含多列的 where-in 子句执行 PostgreSQL 查询?

    我的查询是这样的 select from plat customs complex where code t code s in 01013090 10 01029010 90 它在 psql 控制台中运行良好 我的问题是如何在客户端代码中
  • 以相反的顺序打印任何集合中的项目?

    我在 使用 Java 进行数据结构和问题解决 一书中遇到以下问题 编写一个例程 使用 Collections API 以相反的顺序打印任何 Collection 中的项目 不要使用 ListIterator 我不会把它放在这里 因为我想让有
  • Java LostFocus 和 InputVerifier,按反向制表符顺序移动

    我有一个 GUI 应用程序 它使用 InputVerifier 在产生焦点之前检查文本字段的内容 这都是很正常的 然而 昨天发现了一个问题 这似乎是一个错误 但我在任何地方都找不到任何提及它的地方 在我将其报告为错误之前 我想我应该问 我在
  • 自定义列表字段点击事件

    我正在编写一个应用程序 其中我创建了用于显示列表视图的自定义列表字段 我的 CustomListField 包含连续的一个图像和文本 我正在通过单击列表字段行获取字段更改侦听器 但我也想将字段更改侦听器放在图像上 谁能告诉我我该怎么做 这是
  • 如何使用 Java 引用释放 Java Unsafe 内存?

    Java Unsafe 类允许您按如下方式为对象分配内存 但是使用此方法在完成后如何释放分配的内存 因为它不提供内存地址 Field f Unsafe class getDeclaredField theUnsafe Internal re
  • 如何使用 Java Apache POI 隐藏 Excel 工作表中以下未使用的行?

    我正在使用数据库中的数据填充模板 Excel 工作表 for Map
  • 为什么 jar 执行的通配符在 docker CMD 中不起作用?

    我有一个Dockerfile与以下CMD启动我的 Spring Boot 应用程序 FROM java 8 jre CMD java jar app file jar 当我尝试从创建的图像启动容器时 我得到 Error Unable to
  • 在光标所在行强制关闭!

    嘿 我正在尝试创建一个应用程序来查找存储在 SQlite 数据库中的 GPS 数据 但我面临一个问题 我构建了一个 DbAdapter 类来创建数据库 现在我尝试使用以下函数从另一个类获取所有数据上的光标 public Cursor fet
  • 如何更改 Swagger-ui URL 前缀?

    我正在使用 Springfox Swagger2 和 Spring boot 1 5 9 我可以通过此链接访问 swagger UI http localhost 8090 swagger ui html http localhost 80
  • 如何自定义舍入形式

    我的问题可能看起来很简单 但仍然无法得到有效的东西 我需要自定义 Math round 舍入格式或其他格式以使其工作如下 如果数字是 1 6 他应该四舍五入到 1 如果大于或等于 1 7 他应该四舍五入到 2 0 对于所有其他带有 6 的小
  • Java 8 Stream,获取头部和尾部

    Java 8 引入了Stream http download java net jdk8 docs api java util stream Stream html类似于 Scala 的类Stream http www scala lang
  • 如何向页面添加 HTML 页眉和页脚?

    如何使用 itext 从 html 源添加标题到 pdf 目前 我们已经扩展了 PdfPageEventHelper 并重写了这些方法 工作正常 但当我到达 2 个以上页面时 它会抛出 RuntimeWorkerException Over
  • 文本视图不显示全文

    我正在使用 TableLayout 和 TableRow 创建一个简单的布局 其中包含两个 TextView 这是代码的一部分
  • 即使禁用安全性,OAuth 令牌 API 也无法在 Elastic Search 中工作

    我是 Elastic search 新手 使用 Elastic search 版本 7 7 1 我想通过以下方式生成 OAuth 令牌弹性搜索文档 https www elastic co guide en elasticsearch re
  • 我所有的 java 应用程序现在都会抛出 java.awt.headlessException

    所以几天前我有几个工作Java应用程序使用Swing图书馆 JFrame尤其 他们都工作得很好 现在他们都抛出了这个异常 java awt headlessexception 我不知道是什么改变了也许我的Java版本不小心更新了 谢谢你尽你
  • 什么是 Java2D 处理程序线程?

    我创建了一个使用 Hibernate 的示例 java 应用程序 当我进行线程转储时 我观察到一个名为 Java2D Disposer 的奇怪线程 有人能告诉我该线程的功能吗 AWT 系统中的某些实体需要最终确定以释放资源 最突出的例子是j

随机推荐

  • vue项目启动后,js-base64依赖报错Cannot read properties of null (reading ‘replace’)

    cannot read properties of null reading replace 关于这种乱七八糟的问题 咱也不敢说 在哪也不敢问 项目运行之后 有一些警告 都是一些依赖版本的问题 平时也能直接给运行起来 这次就是项目可以运行起
  • rabbitmq+springboot实现幂等性操作

    文章目录 1 场景描述 1 1 场景1 1 2 场景2 2 原理 3 实战开发 3 1 建表 3 2 集成mybatis plus 3 3 集成RabbitMq 3 3 1 安装mq 3 3 2 springBoot集成mq 3 4 具体实
  • 阿里云服务器使用xshell连接

    阿里云服务器使用xshell连接 当购买了第一次阿里云服务器时 如何使用xshell连接 其实是非常简单的 1 登录阿里云控制台 1 是你的阿里云服务器所在地址 2 是公网IP 将来远程连接时需要使用 3 是设置远程连接的密码 用户名默认r
  • 在x86和arm编译libmodbus

    编译libmodbus 下载路径 1 编译准备 sudo apt get install libtool autogen sh 2 arm编译 autogen sh mkdir install configure ac cv func ma
  • 电压电流的驱动能力分析以及计算方法

    文章为笔者学习过程中看到的 感觉帮助较大 分享出来希望能帮助到大家 在电子电路中为什么有的地方电压会被拉低2 驱动能力是什么意思 如何提高驱动能力 在很多资料上看到说驱动能力不够是因为提供的电流太小 为什么不说电压呢 在很多限制的条件都是电
  • BIOS开启虚拟化技术

    什么是BIOS BIOS 是一个内置于个人计算机的程序 当您打开计算机时该程序启动操作系统 也称为系统固件 BIOS 是计算机硬件的一部分 不同于 Windows 怎么进入BIOS 电脑进入BIOS的方法各有不同 通常会在开机时 显示电脑l
  • atoi函数源代码

    atoi函数源代码 isspace int x if x x t x n x f x b x r return 1 else return 0 isdigit int x if x lt 9 x gt 0 return 1 else ret
  • CPU是如何读写内存的?

    如果你不知道CPU是如何读写内存的 那你应该好好看看这篇文章 如果你觉得这是一个非常简单的问题 那你更应该好好读读本文 这个问题绝没有你想象那么简单 一定要读完 闲话少说 让我们来看看CPU在读写内存时底层究竟发生了什么 1 谁来告诉CPU
  • Mybatis二级缓存应用场景和局限性

    二级缓存应用场景 对查询频率高 变化频率低的数据建议使用二级缓存 对于访问多的查询请求且用户对查询结果实时性要求不高 此时可采用mybatis二级缓存技术降低数据库访问量 提高访问速度 业务场景比如 耗时较高的统计分析sql 电话账单查询s
  • ChatGPT是否具有记忆能力?

    ChatGPT在某种程度上具有记忆能力 但它的记忆能力有限且不像人类的记忆那样全面和持久 以下是对ChatGPT的记忆能力的详细分析 1 上下文记忆 ChatGPT可以在对话过程中记住先前的对话历史 以便更好地理解和回应后续的问题 通过将上
  • 带你了解并实践monorepo和pnpm,绝对干货!熬夜总结!

    大厂技术 高级前端 Node进阶 点击上方 程序员成长指北 关注公众号 回复1 加入高级Node交流群 为什么使用monorepo 什么是monorepo 简单来说就是 将多个项目或包文件放到一个git仓库来管理 目前比较广泛应用的是yar
  • java面试笔试基本知识点总结

    1 正则表达式 正则表达式定义了字符串的模式 正则表达式可以用来搜索 编辑或处理文本 正则表达式并不仅限于某一种语言 但是在每种语言中有细微的差别 在编写处理字符串的程序时 经常会有查找符合某些复杂规则的字符串的需要 正则表达式就是用于描述
  • hikaricp druid比较_Spring Boot整合MybatisPlus和Druid

    在Java中 我比较ORM熟悉的只有Hibernate和Mybatis 其他的并未实践使用过 在这二者之间我更喜欢Mybatis 因为它精简 灵活 毕竟我是上年纪的程序员 喜欢自己写SQL 刚才有提到Mybatis 但是这里的重点是介绍My
  • 应用APK文件有效瘦身

    先说下前言 为什么要这样处理 随着项目的越来越多丰富功能 打包出来的apk体积日益变大 不说打包耗时 编译耗时 发布到应用市场 用户下载流量多 而且手机空间那么有限 用户不满意 咱们就要进行改变呗 没有体验 就没有用户 我先贴一张图 演示项
  • Python常用命令整理

    Anaconda常用命令 1 管理Conda 1 检查conda版本 conda version 2 升级当前版本conda conda update conda 2 管理 虚拟 环境 1 创建环境 创建一个名为python3的环境 指定P
  • Visual Studio 安装检测内存工具-Visual Leak Detetctor。(适用于VS2013、VS2015、VS2017、VS2019、VS2022版本)

    目录 前言 Visual Leak Detetctor 外部安装VLD 安装包 配置VLD 查看相关文件 将VLD配置到C 项目中 创建一个C 的空工程 配置头文件 配置lib库 测试Visual Leak Detetctor 前言 如果你
  • Got permission denied while trying to connect to the Docker daemon socket

    docker权限问题 需要将当前用户添加到docker组 sudo groupadd docker 添加docker用户组 sudo gpasswd a XXX docker 检测当前用户是否已经在docker用户组中 其中XXX为用户名
  • Mac 下 Arduino 开发环境搭建

    文章目录 Mac 下 Arduino 开发环境搭建 驱动 Arduino 安装 Arduino IDE 使用 Arduino IDE 准备跑路 VS Code 安装 VS Code 安装 Arduino 扩展 安装 C C 扩展 开始开发
  • 剑指Offer第二十七题:字符串的排列

    题目描述 输入一个字符串 按字典序打印出该字符串中字符的所有排列 例如输入字符串abc 则打印出由字符a b c所能排列出来的所有字符串abc acb bac bca cab和cba 思路 感觉是动态规划题 假设选第一个元素时 对于abc有
  • Redis+Lua限制发送量及遇到的坑

    业务中需要限制每个账号每天发送短信数量 如果没有超过设置的发送量 则正常发送 否则返回失败 解决思路 将账号ID yyyyMMdd组成redis的key value为当天的发送量 在发送前获取账号ID yyyyMMdd的值 如果没有超过发送