【1】基本理论
开闭原则的英文全称是 Open Closed Principle,简写为 OCP。即添加一个新的功能应该是,在已有代码基础上扩展代码(新增模块、类、方法等),而非修改已有代码(修改模块、类、方法等)。
【2】功能描述
假设现在有一个API接口监控告警的需求:可以根据接口配置不同的监控维度(Tps,错误数),然后发送告警通知。后续如果要新增新的维度(eg:超时监控),可以平行扩展代码,以较小代价完成代码修改。
【3】设计思路
监控告警的主要功能是查询对应API接口的告警规则,按照各个维度依次判断是否超过告警阈值,然后发送告警。我们可以抽象一个告警处理器接口AlertHandler,包含Check(info *ApiInfo)方法去判断当前apiinfo是否需要触发告警,让不同的告警规则去实现这个接口(eg:TPS告警处理-TpsAlertHandler,错误告警处理-ErrAlertHandler),然后将所有实现的告警规则实例放在告警处理器链表中(类似于责任链模式),遍历每个实例进行告警处理。
当我们需要添加新的告警维度的时候,比如超时数达到阈值告警,只需要做三处改动:
(1)当前ApiInfo中添加超时统计字段和对应调用方传参;
(2)添加新的TimeoutAlertHander类;
(3)将TimeoutAlertHander类添加到告警处理器责任链中;
这样按照定义的接口扩展点,平行扩展功能,不仅对原有代码结构影响较小,而且不会影响原有的告警功能。
【4】Demo实战
(说明:带//add的注释 对应代码行为新增超时告警功能对代码的修改)
package main
import "fmt"
//Api数据指标 ApiInfo <public数据结构>
// Api数据指标
type ApiInfo struct {
Api string
RequestCnt int64
ErrCnt int64
DurOfSecs int64
TimeoutCnt int64 //add
}
//告警处理器群 Alertx
// 告警处理器接口
type AlertHandler interface {
Check(info *ApiInfo)
}
// 告警处理器责任链
type Alertx struct {
alertHandlersList []AlertHandler // 注册存储不同告警功能模块
}
func NewAlertx() *Alertx {
return &Alertx{
alertHandlersList: make([]AlertHandler, 0),
}
}
//添加告警处理器
func (a *Alertx) AddHandler(aHandler AlertHandler) {
a.alertHandlersList = append(a.alertHandlersList, aHandler)
}
//遍历责任链
func (a *Alertx) CheckAll(aInfo *ApiInfo) {
for _, handler := range a.alertHandlersList {
handler.Check(aInfo)
}
}
// 报警规则
const (
DEFAULT_RULE_MAXTIPS = 99999
DEFAULT_RULE_ERRCOUNT = 99999
DEFAULT_RULE_TIMEOUTCOUNT = 99999
)
type RuleData struct {
maxTps int64
maxErrorCount int64
maxTimeOutCount int64 //add
}
type AlertRule struct {
mpAlertConfig map[string]*RuleData
}
func NewAlertRule() *AlertRule {
mp := make(map[string]*RuleData)
//add:maxTimeOutCount的配置
mp["getOrderInfo"] = &RuleData{maxTps: 100, maxErrorCount: 101, maxTimeOutCount: 5}
mp["getEvaluates"] = &RuleData{maxTps: 200, maxErrorCount: 3, maxTimeOutCount: 5}
return &AlertRule{mpAlertConfig: mp}
}
// tps阈值
func (a *AlertRule) GetTpsCount(api string) int64 {
config, ok := a.mpAlertConfig[api]
if ok {
return config.maxTps
}
return DEFAULT_RULE_MAXTIPS
}
// 错误数阈值
func (a *AlertRule) GetErrCount(api string) int64 {
config, ok := a.mpAlertConfig[api]
if ok {
return config.maxErrorCount
}
return DEFAULT_RULE_ERRCOUNT
}
//add: 获取超时数阈值
func (a *AlertRule) GetTimeoutCount(api string) int64 {
config, ok := a.mpAlertConfig[api]
if ok {
return config.maxTimeOutCount
}
return DEFAULT_RULE_TIMEOUTCOUNT
}
// 告警通知
type EmergencyLevelType int
const (
EL_URGENCY EmergencyLevelType = 0
EL_SEVERE = 4
EL_NORMAL = 5
)
type Notification struct{}
func (n *Notification) Notify(level EmergencyLevelType, msg string) {
fmt.Printf("[Notify]Level:%v, msg:%s\n", level, msg)
}
//实现AlertHandler接口,按照TPS规则
type TpsAlertHandler struct {
rule *AlertRule
notification *Notification
}
func NewTpsAlertHandler(rule *AlertRule, notification *Notification) *TpsAlertHandler {
return &TpsAlertHandler{
rule: rule,
notification: notification,
}
}
func (t *TpsAlertHandler) Check(info *ApiInfo) {
tps := info.RequestCnt / info.DurOfSecs
if tps > t.rule.GetTpsCount(info.Api) {
t.notification.Notify(EL_URGENCY, "TPS Too high!")
}
fmt.Println("TPS Alert Done")
}
//实现AlertHandler接口,按照Alert规则
type ErrAlertHandler struct {
rule *AlertRule
notification *Notification
}
func NewErrAlertHandler(rule *AlertRule, notification *Notification) *ErrAlertHandler {
return &ErrAlertHandler{
rule: rule,
notification: notification,
}
}
// 实现AlertHandler接口
func (e *ErrAlertHandler) Check(info *ApiInfo) {
if info.ErrCnt > e.rule.GetErrCount(info.Api) {
e.notification.Notify(EL_URGENCY, "ERR Count Too High!")
}
fmt.Println("Err Alert Done")
}
//add :新增超时监控维度,实现AlertHandler接口,按照Timeout规则
type TimeoutAlertHandler struct {
rule *AlertRule
notification *Notification
}
func NewTimeoutAlertHandler(rule *AlertRule, notification *Notification) *TimeoutAlertHandler {
return &TimeoutAlertHandler{
rule: rule,
notification: notification,
}
}
func (t *TimeoutAlertHandler) Check(info *ApiInfo) {
if info.TimeoutCnt > t.rule.GetTimeoutCount(info.Api) {
t.notification.Notify(EL_SEVERE, "Timeout Count Too High!")
}
fmt.Println("Timeout Alert Done")
}
func main() {
alerts := NewAlertx()
infos := &ApiInfo{
Api: "getOrderInfo",
RequestCnt: 100,
ErrCnt: 100,
DurOfSecs: 1,
TimeoutCnt: 100, //add :设置当前api的超时统计数
}
alerts.AddHandler(NewTpsAlertHandler(NewAlertRule(), &Notification{}))
alerts.AddHandler(NewErrAlertHandler(NewAlertRule(), &Notification{}))
alerts.AddHandler(NewTimeoutAlertHandler(NewAlertRule(), &Notification{})) //add:添加超时告警搞告警责任链
alerts.CheckAll(infos)
}
运行结果:
TPS Alert Done
Err Alert Done
[Notify]Level:4, msg:Timeout Count Too High!
Timeout Alert Done