背景
在系统中,接口异常或流量骤降可能影响业务的正常运行。为了及时发现并处理这些异常情况,我们实现了一个监测机制,若 1 分钟内无任何请求,则触发报警。该监测机制基于 Redis 存储请求时间戳,结合定时任务进行监测。
功能需求
- 每次接口被调用时,记录时间戳。
- 每 120 秒检查一次最后的请求时间。
- 若超过 1 分钟无请求,触发报警。
技术选型
- Golang:作为核心编程语言。
- Redis:用于存储请求的时间戳,提供快速读写支持。
- Goroutine & Ticker:实现定时任务以监测请求情况。
- 日志框架:使用
logger
输出日志,记录关键事件。
代码实现
1. 设置请求时间
该函数在每次请求到来时调用,记录当前时间戳至 Redis。
func SetRequestTime(key string) error {
if key == "" {
return fmt.Errorf("key is empty")
}
err := boot.Rdb.Set(ctx, key, time.Now().Unix(), 3600).Err()
if err != nil {
return err
}
return nil
}
解释:
- 使用
boot.Rdb.Set
将当前 Unix 时间戳写入 Redis。 - 设置过期时间为 3600 秒,防止数据堆积。
2. 获取最后请求时间
用于查询 Redis 中保存的最后请求时间戳。
func GetLastRequestTime(key string) (int64, error) {
if key == "" {
return 0, fmt.Errorf("key is empty")
}
result, err := boot.Rdb.Get(ctx, key).Result()
if err != nil || result == "" {
return 0, fmt.Errorf("key not found")
}
parseInt, err := strconv.ParseInt(result, 10, 64)
if err != nil {
return 0, err
}
return parseInt, nil
}
解释:
- 通过
boot.Rdb.Get
获取 Redis 中存储的时间戳。 - 若 Redis 中无数据或获取失败,则返回
key not found
错误。 - 使用
strconv.ParseInt
将字符串转换为整型时间戳。
3. 请求监测与报警
利用 Goroutine 启动定时任务,每 120 秒检查一次。
func MonitorRequests(key string) error {
logger.Logger.Sugar().Info("开始监控调用播放异常的情况")
ticker := time.NewTicker(120 * time.Second)
defer ticker.Stop()
for range ticker.C {
requestTime, err := GetLastRequestTime(key)
if err != nil {
logger.Logger.Sugar().Errorf("GetLastRequestTime err: %+v", err)
continue
}
unixTime := time.Since(time.Unix(requestTime, 0))
if unixTime > time.Minute {
logger.Logger.Sugar().Warnf("⚠️ 1 分钟内没有用户请求,触发报警!当前间隔时间:%s", unixTime)
}
}
}
示例使用
func HandleRequest() {
SetRequestTime("api_request_key")
// 其他业务逻辑
}
func main() {
go MonitorRequests("api_request_key") // 启动监测器
}
测试与验证
- 请求频繁时:确保 Redis 数据正确更新,且无报警触发。
- 请求暂停 1 分钟以上:观察是否触发报警日志输出。
- Redis 异常或数据丢失:验证日志中是否输出
key not found
报错。
优化建议
- 报警策略扩展:可增加邮件、短信、钉钉 Webhook 等报警方式。
- 动态周期设置:通过环境变量或配置文件调整检查频率。
- 高并发优化:若并发请求量较大,可优化 Redis 的数据结构,采用
SETEX
命令简化逻辑。
总结
该实现基于 Golang 的 Redis、Goroutine 与日志模块,构建了一个轻量、高效的接口请求监测与报警机制,适用于关键业务接口的异常监控。