-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcircuit_breaker.go
173 lines (142 loc) · 3.77 KB
/
circuit_breaker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package easycall
import (
"math/rand"
"sync"
"sync/atomic"
"github.com/starjiang/elog"
)
const (
CB_FAIL_RATE = 0.5
CB_LIMIT_RATE = 0.2
CB_COUNT_BASE = 10
CB_FAIL_TIME = 30000
CB_LIMIT_TIME = 30000
CB_RESET_TIME = 60000
CB_STATUS_OPEN = 1
CB_STATUS_CLOSE = 0
CB_STATUS_LIMIT = 2
)
type runFunc func() error
type failFunc func() error
type CbInfo struct {
invokeCount int64
failCount int64
lastCircuitBreakerTime int64
lastLimitPassTime int64
lastResetTime int64
status int
failRate float32
limitRate float32
countBase int
failTime int64
limitTime int64
resetTime int64
}
var cbInfos = make(map[string]*CbInfo)
var cbMutexes = make(map[string]*sync.Mutex)
var cbMutex sync.Mutex
func CbConfigure(cbName string, failRate float32, limitRate float32, countBase int, failTime int64, limitTime int64, resetTime int64) {
timeNow := GetTimeNow()
var lock *sync.Mutex
cbMutex.Lock()
lock = cbMutexes[cbName]
if lock == nil {
lock = &sync.Mutex{}
cbMutexes[cbName] = lock
}
info := cbInfos[cbName]
if info == nil {
info = &CbInfo{1, 0, 0, 0, timeNow, CB_STATUS_CLOSE, failRate, limitRate, countBase, failTime, limitTime, resetTime}
cbInfos[cbName] = info
}
cbMutex.Unlock()
lock.Lock()
info.failRate = failRate
info.limitRate = limitRate
info.countBase = countBase
info.failTime = failTime
info.limitTime = limitTime
info.resetTime = resetTime
lock.Unlock()
}
func CbCall(cbName string, run runFunc, fail failFunc) error {
timeNow := GetTimeNow()
var lock *sync.Mutex
cbMutex.Lock()
lock = cbMutexes[cbName]
if lock == nil {
lock = &sync.Mutex{}
cbMutexes[cbName] = lock
}
info := cbInfos[cbName]
if info == nil {
info = &CbInfo{1, 0, 0, 0, timeNow, CB_STATUS_CLOSE, CB_FAIL_RATE, CB_LIMIT_RATE, CB_COUNT_BASE, CB_FAIL_TIME, CB_LIMIT_TIME, CB_RESET_TIME}
cbInfos[cbName] = info
}
cbMutex.Unlock()
lock.Lock()
//熔断过期后,把熔断器状态设置为半开状
if info.status == CB_STATUS_OPEN && info.lastCircuitBreakerTime+info.failTime < timeNow {
info.status = CB_STATUS_LIMIT
info.failCount = 0
info.invokeCount = 1
info.lastLimitPassTime = timeNow
info.lastCircuitBreakerTime = 0
elog.Errorf("CircuitBreaker %s set status limit", cbName)
}
ptFlag := false
if info.status == CB_STATUS_OPEN {
ptFlag = false
} else if info.status == CB_STATUS_LIMIT {
//半开状态下,随机计算允许通过的请求
rand := rand.Float32()
if rand < info.limitRate {
ptFlag = true
}
} else {
ptFlag = true
}
if !ptFlag {
if fail != nil {
lock.Unlock()
return fail()
}
lock.Unlock()
return nil
}
//计算熔断阀值,超过阀值,熔断
f := float32(info.failCount) / float32(info.invokeCount)
if f > info.failRate && info.invokeCount > int64(info.countBase) {
info.status = CB_STATUS_OPEN
info.lastCircuitBreakerTime = timeNow
elog.Errorf("CircuitBreaker %s set status open", cbName)
if fail != nil {
lock.Unlock()
return fail()
}
lock.Unlock()
return nil
}
//半开状态下,请求没超过阀值,关闭熔断器
if info.status == CB_STATUS_LIMIT && info.lastLimitPassTime+info.limitTime < timeNow {
info.status = CB_STATUS_CLOSE
info.invokeCount = 1
info.failCount = 0
info.lastLimitPassTime = 0
elog.Errorf("CircuitBreaker %s set status close", cbName)
}
//重置统计
if info.status == CB_STATUS_CLOSE && info.lastResetTime+info.resetTime < timeNow {
info.lastResetTime = timeNow
info.failCount = 0
info.invokeCount = 1
elog.Infof("CircuitBreaker %s reset", cbName)
}
lock.Unlock()
atomic.AddInt64(&info.invokeCount, 1)
err := run()
if err != nil {
atomic.AddInt64(&info.failCount, 1)
}
return err
}