使用 Redis 解决钉钉机器人报警频率限制

需求

因为服务化拆分之后,数据的最终一致性没有做好,导致业务生成很多脏数据。因此需要额外增加很多脚本,做数据检查监控,监控结果需要及时发送钉钉。正常情况下,每天的异常消息不会很多,但是每次因为新加脚本,需要扫所有历史数据,会很频繁地发送钉钉消息。

但是钉钉机器人发送频率限制是 20条/每分钟,如果超过限制,会返回 send too fast 错误信息,再发,就直接 302 并限制发送10分钟

简单方案

合并消息为一条大的消息, 但是消息不能太大,实际最多几千字好像,数据太大也不能发送。

临时方案

简单的方案还是不能解决初始化历史数据,大量发送消息的问题。因为时间问题,最初想到的临时方案,是每次发送结束 sleep 3 秒钟,这样绝对不会超出限制。但是有很大的问题

  • 导致正常运行时,发送后脚本效率变低

最终方案

由于 Redis 支持的类型丰富用法简单效率高 等特点, 且很多公司都会用到 Redis 无需额外安装。 解决思路是:

  1. 一个群最多申请六个机器人,把六个token保存在数组中
  2. 每次发送,依次查看每个token的 redis sorted set 集合中以最近一分钟 timestampscope 范围的数量
  3. 如果大于 18,查询下一个token,否则是可用的token

部分代码如下:

最后有一步特殊处理,如果 6 个 token 都不可用,将消息保存在一个 set 集合中,有效期 7 天,这样总比消息丢失强,不过这种应该很少出现了。因为 6 个机器人,最多一分钟就可以发送 6 * 18 = 108 条消息了,如果是单进程脚本,每次执行发送间隔只小到 ~ 50 ms, 已经基本能满足目前需要。

现在可以放心的把之前代码中,发送消息之后 sleep(3) 删除了