文章

learn - 项目架构演变-04(监控预警篇)

当我们程序开始在生产环境上运行,此时应该有个低成本的风险预警提醒功能。

learn - 项目架构演变-04(监控预警篇)

创作背景

每个项目开始有真正的客户使用后。不管是付费用户或免费用户,对我们来说,都应当为其提供高可用、高性能的服务。

有些团队已经有内部的完善的预警中台,只要与其对接即可。

这篇记录,主要为了给那些非独有预警中台,而产、运、研团队随时关注的一些事件或风险把控,几小时内快速支持上对风险的提醒。

目标

  • 低成本:有网络就行,免去垃圾短信/电话。
  • 快速:半天内搞定。
  • 频次可控:信息提醒不要狂轰滥炸。

可行性方案

一个简单的消息提醒组成

预警提醒

预警组成大致可分成:消息生产、消息存储、接收端。

我们这里采用了几种尽可能的低成本方案来及时的收到服务的一些资源瓶颈提醒(或异常时信息收集)。

消息存储我个人使用的是redis方案,因为托管的redis已经自身存在了提醒预警;另外是系统依赖这个分布式缓存,只是借用一下链接池和db空间即可完成该功能。

  1. 发送端(采用list方式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func (m *appMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			m.apiError(r)
		}()
    ...
  }
}

func (m *appMiddleware) apiError(r *http.Request) {
    ...
    icache.ListSrv.LPushSysErrApi(&cacheDto.ListSysErrApi{
			UserId:  userId,
			Path:    r.RequestURI,
			Msg:     msg,
			Code:    codeInt,
			Info:    info,
			PkgName: r.Context().Value(defines.HeaderXPkgName).(string),
			At:      time.Now().Unix(),
		})
}
  1. 筛选消息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func (l *SystemErrorLogic) SystemError() (resp *types.ResultResp) {
	...
	errMap := make(map[string][]*dto.ListSysErrApi)
	for {
		sysErr, err := icache.ListSrv.RPopSysErrApi()
		if err != nil || sysErr == nil || sysErr.Path == "" {
			break
		}
		md5Str := sysErr.Md5String()
		l.CntMap[md5Str] += 1
		errMap[sysErr.Path] = append(errMap[sysErr.Path], sysErr)
	}
  ...
	}
  1. 采用钉钉群通知
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func (l *SystemErrorLogic) SendMsg(errMap map[string][]*dto.ListSysErrApi) {
	if len(errMap) == 0 {
		return
	}
	...
	iouter.DingTalkSrv.SendMsg(&dingTalkConf, &outDto.DingTalkReq{
		MsgType: "markdown",
		Markdown: &outDto.DingTalkMK{
			Title: title,
			Text:  dingTalkMsg,
		},
		At: nil,
	})
}

结论点

  1. 注意消息体内容大小。
  2. 注意区分各自环境。
  3. 处理钉钉群的消息。
  4. 时间一长容易发生“狼来了”,可以把提醒内容增加各种符号,用于快速筛选。

##

本文由作者按照 CC BY 4.0 进行授权