钉钉自定义机器人默认每分钟最多发送 20 条消息到同一个群,一旦超限会被限流 10 分钟。生产环境必须通过代码层做消息聚合或轮询策略来规避,严禁直接丢弃关键告警。
先说结论:单机器人单群每分钟限 20 条,超限封禁 10 分钟,错误码通常为 130101。
- 先定位:检查业务日志中是否有 errcode 130101 或 HTTP 429 状态码。
- 先做:代码层增加消息队列,将多条告警合并为一条 Markdown 发送。
- 再验证:观察日志中限流错误是否消失,消息延迟是否在容忍范围内。
核心限制与错误码
钉钉机器人 API 针对“一个机器人和一个群的组合”进行频率限制。以下是关键参数与错误码对照,便于排查:
| 限制项 | 阈值 | 后果 | 错误码/状态 |
|---|---|---|---|
| 发送频率 | 20 条/分钟 | 接口限流 10 分钟 | errcode: 130101 |
| 消息长度 | 4000 字符 | 发送失败 | errcode: 130106 |
| 并发限制 | 视服务器负载 | 请求超时 | HTTP 429/503 |
当接收到 130101 错误时,表示当前分钟配额已用完,必须立即停止发送并进入等待或降级流程。
代码实现:消息聚合示例
为避免频繁调用接口,建议在业务代码中维护一个缓冲队列。以下是一个简单的 Python 实现思路,演示如何攒批发送:
import time
import requests
import threading
from queue import Queue
# 配置 Webhook
WEBHOOK_URL = "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN"
# 消息队列
msg_queue = Queue()
def send_batch():
while True:
batch_msgs = []
# 策略:攒够 5 条 或 等待 5 秒
start_time = time.time()
while len(batch_msgs) < 5 and (time.time() - start_time) < 5:
try:
msg = msg_queue.get(timeout=1)
batch_msgs.append(msg)
except:
break
if batch_msgs:
# 合并消息内容
content = "## 告警汇总\n" + "\n".join(batch_msgs)
payload = {
"msgtype": "markdown",
"markdown": {"title": "告警汇总", "text": content}
}
try:
resp = requests.post(WEBHOOK_URL, json=payload)
result = resp.json()
if result.get("errcode") == 130101:
# 触发限流,将消息重新放回队列或写入持久化存储
for m in batch_msgs:
msg_queue.put(m)
time.sleep(60) # 强制等待
except Exception as e:
# 记录错误日志
print(f"Send failed: {e}")
# 启动发送线程
threading.Thread(target=send_batch, daemon=True).start()
# 业务调用示例
msg_queue.put("- CPU 使用率过高:95%")
msg_queue.put("- 内存不足:剩余 100MB")注意:生产环境建议使用 Redis 或数据库作为队列存储,防止进程重启导致消息丢失。
请求参数与安全配置
发送 POST 请求时,Content-Type 必须为 application/json,字符集编码设置为 UTF-8。若群机器人开启了“加签”安全设置,请求 URL 需携带 timestamp 和 sign 参数。
1. 基础 JSON payload 示例:
{
"msgtype": "markdown",
"markdown": {
"title": "故障告警",
"text": "## 故障告警\n- 服务:OrderService\n- 状态:DOWN\n- 时间:2023-10-27 10:00:00"
},
"at": {
"isAtAll": true
}
}2. 加签配置说明:
如果后台开启了加签,URL 格式如下:
https://oapi.dingtalk.com/robot/send?access_token=XXX×tamp=XXX&sign=XXX
sign 计算公式:使用 HMAC-SHA256 算法,将“timestamp + '\n' + 密钥”进行加密,再进行 URL Encode。
限流后的降级策略
捕获接口返回的错误码后,一旦发现限流(130101),严禁直接丢弃非关键消息,建议采取以下策略:
- 持久化缓存:将发送失败的消息写入本地日志、数据库或 Redis 队列。
- 指数退避:等待时间逐步增加(如 1 分钟、2 分钟、5 分钟)后重试。
- 关键告警通道分离:对于 P0 级故障,配置独立的机器人 Webhook 或切换至短信/电话通知渠道,避免被普通告警限流阻塞。
验证与排查
修改代码后,通过以下步骤验证优化效果:
- 日志监控: grep 业务日志中的"errcode"关键字,确认 130101 出现频率是否降为 0。
- 压力测试:在测试环境模拟高频告警(如 1 分钟 50 条),观察是否触发限流以及消息合并是否符合预期。
- 延迟检查:确认消息从产生到钉钉群接收的延迟是否在业务允许范围内(通常聚合会导致秒级延迟)。
常见坑
1. 消息长度超限:合并消息时注意总字符数不要超过 4000 字符,否则接口会直接报错。
2. Webhook 泄露:保管好 Webhook 地址,不要公布在外部代码仓库或前端代码中,泄露后有安全风险。
3. 安全设置不匹配:发起 POST 请求时,必须根据群机器人后台设置(关键词、加签、IP 白名单)配置对应参数,否则返回 401 错误。
4. 进程重启丢失:如果使用内存队列(如 Python list/Queue),服务重启会导致未发送消息丢失,生产环境务必使用持久化存储。
参考来源
- 钉钉开放平台 - 自定义机器人发送群消息 - https://open.dingtalk.com/document/orgapp/custom-robots-send-group-messages
- 钉钉开放平台 - 错误码对照表