重写健康检查

This commit is contained in:
huangmengzhu
2023-03-24 18:47:17 +08:00
parent 42adb01a19
commit f7803009c7
20 changed files with 150 additions and 560 deletions

View File

@@ -1,29 +1 @@
package health_check_http
import "github.com/eolinker/apinto/discovery"
// agent 从属于HTTPCheck,实现了IHealthChecker接口
type agent struct {
agentID string
checker *HTTPCheck
}
// NewAgent 创建agent
func NewAgent(agentID string, checker *HTTPCheck) discovery.IHealthChecker {
return &agent{agentID: agentID, checker: checker}
}
// AddToCheck 将节点添加进HTTPCheck的检查列表
func (a *agent) AddToCheck(node discovery.BaseNode) error {
a.checker.addToCheck(&checkNode{
node: node,
agentID: a.agentID,
})
return nil
}
// Stop 停止agent并且将HTTPCheck中属于该agent的正在检查的所有节点都移除
func (a *agent) Stop() error {
a.checker.stop(a.agentID)
return nil
}

View File

@@ -11,7 +11,10 @@ import (
"github.com/eolinker/eosc/log"
"github.com/eolinker/apinto/discovery"
"github.com/google/uuid"
)
var (
_ discovery.IHealthChecker = (*HTTPCheck)(nil)
)
// NewHTTPCheck 创建HTTPCheck
@@ -22,32 +25,36 @@ func NewHTTPCheck(config Config) *HTTPCheck {
config: &config,
ctx: ctx,
cancel: cancel,
ch: make(chan *checkNode, 10),
client: &http.Client{},
locker: sync.RWMutex{},
}
go checker.doCheckLoop()
return checker
}
// HTTPCheck HTTP健康检查结构,实现了IHealthChecker接口
type HTTPCheck struct {
config *Config
nodes discovery.INodes
ctx context.Context
cancel context.CancelFunc
ch chan *checkNode
delCh chan string
client *http.Client
locker sync.RWMutex
}
func (h *HTTPCheck) Check(nodes discovery.INodes) {
go h.doCheckLoop(nodes)
}
// doCheckLoop 定时检查,维护了一个待检测节点集合
func (h *HTTPCheck) doCheckLoop() {
func (h *HTTPCheck) doCheckLoop(nodes discovery.INodes) {
if h.config.Period < 1 {
return
}
ticker := time.NewTicker(h.config.Period)
nodes := map[string]map[string]*checkNode{}
defer ticker.Stop()
for {
select {
@@ -55,84 +62,43 @@ func (h *HTTPCheck) doCheckLoop() {
return
case <-ticker.C:
{
nodes = h.check(nodes)
}
//接收待检测节点并存入待检测节点集合
case node, ok := <-h.ch:
{
if ok {
if _, ok := nodes[node.agentID]; !ok {
nodes[node.agentID] = make(map[string]*checkNode)
}
nodes[node.agentID][node.node.ID()] = node
}
}
//接收agentID,并将待检测集合中属于该agent的所有节点移除
case agentID, ok := <-h.delCh:
{
if ok {
delete(nodes, agentID)
}
h.check(nodes.All())
}
}
}
}
// Agent 生成一个agent
func (h *HTTPCheck) Agent() (discovery.IHealthChecker, error) {
return NewAgent(uuid.NewString(), h), nil
}
// Reset 重置HTTPCheck的配置
func (h *HTTPCheck) Reset(conf Config) error {
h.config = &conf
func (h *HTTPCheck) Reset(conf interface{}) error {
cf, ok := conf.(Config)
if !ok {
return nil
}
h.reset(&cf)
return nil
}
// AddToCheck 将节点添加进HTTPCheck的检查列表
func (h *HTTPCheck) AddToCheck(node discovery.BaseNode) error {
h.addToCheck(&checkNode{
node: node,
agentID: "",
})
return nil
}
// addToCheck 将节点传入HTTPCheck的检测Channel
func (h *HTTPCheck) addToCheck(node *checkNode) error {
h.ch <- node
return nil
func (h *HTTPCheck) reset(conf *Config) {
h.config = conf
}
// Stop 停止HTTPCheck中止定时检查
func (h *HTTPCheck) Stop() error {
func (h *HTTPCheck) Stop() {
h.cancel()
return nil
}
// stop 停止从属该agentID的所有节点的健康检查
func (h *HTTPCheck) stop(agentID string) {
h.delCh <- agentID
}
// check 对待检查的节点集合进行检测入参nodes map[agentID][nodeID]*checkNode
func (h *HTTPCheck) check(nodes map[string]map[string]*checkNode) map[string]map[string]*checkNode {
//将待检测节点集合中地址相同的节点整合在一起结构为map[node.Addr][]*checkNode
newNodes := make(map[string][]*checkNode)
for _, ns := range nodes {
for _, n := range ns {
if n.node.Status() == discovery.Down {
newNodes[n.node.Addr()] = append(newNodes[n.node.Addr()], n)
}
}
}
func (h *HTTPCheck) check(nodes []discovery.INode) {
/*对每个节点地址进行检测
成功则将属于该地址的所有节点的状态都置于可运行并从HTTPCheck维护的待检测节点列表中移除
失败则下次定时检查再进行检测
*/
for addr, ns := range newNodes {
uri := fmt.Sprintf("%s://%s/%s", h.config.Protocol, strings.TrimSuffix(addr, "/"), strings.TrimPrefix(h.config.URL, "/"))
for _, ns := range nodes {
if ns.Status() != discovery.Down {
continue
}
uri := fmt.Sprintf("%s://%s/%s", h.config.Protocol, strings.TrimSuffix(ns.Addr(), "/"), strings.TrimPrefix(h.config.URL, "/"))
h.client.Timeout = h.config.Timeout
request, err := http.NewRequest(h.config.Method, uri, nil)
if err != nil {
@@ -149,16 +115,6 @@ func (h *HTTPCheck) check(nodes map[string]map[string]*checkNode) map[string]map
log.Error(err)
continue
}
for _, n := range ns {
n.node.Up()
delete(nodes[n.agentID], n.node.ID())
}
ns.Up()
}
return nodes
}
// checkNode 进入检查channel的节点结构
type checkNode struct {
node discovery.BaseNode
agentID string
}