# network-probe **Repository Path**: lsq_keith/network-probe ## Basic Information - **Project Name**: network-probe - **Description**: 基于C/S架构的网络探针工具 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-02-07 - **Last Updated**: 2024-02-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 一.server端和agent端 ## 通用的点: + 都通过提前想好程序可能会跟的参数 并结合flag.StringVar命令行参数 来实现代替通过配置文件进行可能会更改的变量和配置 最后启动的时候只需要类似[./agent 自定义配置]的方式来启动,而不需要通过配置文件 + 使用errgroup封装的包,使用group.Go()启动协程,来实现协程的编排(共进退,一个出错,全部退出),优雅关闭。 ## agent端 + 核心功能:根据拿到的targets进行探测,收集指标数据 + 提供的http接口: 1. /metrics 用于将agent自己探测的结果作为指标提供出去 ## server端 + 核心功能:1.为客户端提供探测目标targets 2.进行targets的存储 + 提供的http接口: 1. /metrics 用于把当前的所有target作为指标提供出去 2. /api/v1/probe-targets GET/POST/DELETE 对于探测目标target的增删改查 3. /api/v1/hello 测试接口,可作为健康检查 # 二.指标探测(属于agent端代码) * 注:下面的ProbeManager是给agent端使用的,用于对target进行探测,获取指标,因此是在agent中进行初始化并且调用 + 单个ProbeTarget(类似用户,是需要存储的对象)的设计 PO(Persistent Objects): ```go DestAddr string `json:"dest_addr" validate:"required"` // 目标地址 可以是域名, 也可以是 ip地址 or tcp 10.1.1.1:2379 http://xxxxx/ Func string `json:"func" validate:"required"` // ping/tcp/http/dns ProbeTw int `json:"probe_tw" validate:"required"` // 超时时间:过了这个秒数 就认为探测失败:不可能一直等待 HttpRcErr int `json:"http_rc_err"` // http-rc错误阈值 =400 代表4xx 认为错误 ``` + ProbeManager(类似blog中的ipml)的设计 BO(Business Objects) : 需要实现的方法如下: 1. 实现prometheus.Collector接口,来实现自定义exporter,采集探测的ProbeTarget指标 + Describe(ch chan<- *prometheus.Desc) + Collect(metricCh chan<- prometheus.Metric) 使用workerpool来控制并发任务,并且每一种探测都需要考虑超时的处理 + DNS + http + tcp + icmp 2. 实现对缓存中的targets的查询和修改 + GetTs + SetTs 3. 刷新任务:定时把存储中的targets加载到内存中作为缓存 + 其中定时执行使用的是wait.UntilWithContext(采用time.ticker同样可以实现) # 三.数据存储(属于server端代码) * 注:存储属于服务端需要关心的内容,服务端来存储有哪些targets的数据,和客户端无关,因此最终会在server端进行初始化,并且调用 + 通用存储接口的定义 对应上面server端提供的http接口的业务逻辑 ```go type TargetStore interface { // 新增/更新探测目标 :对应的是用户 post /probe-targets 来新增/更新探测目标的 view函数底层的方法 // 更新底层存储,而不是mem-cache ,避免宕机 UpdateTargets(ts []*probe.ProbeTarget) (addNum, totalNum int, err error) // 给用户 或者 agent 来 获取探测目标的 get /probe-targets GetTargets() (ts []*probe.ProbeTarget) // 重载的管理器 ReLoadTargetManager(ctx context.Context) error // 重载的方法: mem-cache 和 底层存储 定时从底层存储中把数据加载到mem-cache中 Load() (ts []*probe.ProbeTarget, err error) // prometheus sdk所必须要实现的接口 Describe(ch chan<- *prometheus.Desc) Collect(metricCh chan<- prometheus.Metric) // 删除 返回删除了几个 还剩下几个 DeleteTargets(ts []*probe.ProbeTarget) (int, int, error) } ``` + 基于文件存储targets的具体实现 file_store.go:实现上面接口中所有的方法 # 四.协程的编排管理以及程序的优雅推出 考虑到主要是server端的接口涉及到对存储的修改,因此借助httpserver.Shutdown(ctx)做一个优雅关闭,能实现kill -9,kill -15退出程序的时候,http server能够关闭目前的连接之后才会整体退出 通过errgroup实现,详见server的main.go ```go // http server优雅退出的处理 // 创建一个监听中断信号的channel interruptChan := make(chan os.Signal, 1) // 确保只被调用一次,如果ctrl + c第一次没有成功退出,再按一次会强制panic退出 defer close(interruptChan) // 监听kill -15 -9 中断信号 signal.Notify(interruptChan, syscall.SIGTERM, os.Interrupt) // 关闭超时时间限制为5s shutdownctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // 收到退出信号的动作 <-interruptChan klog.Infoln("Received interrupt signal. http server Shutting down...") err := server.Shutdown(shutdownctx) if err != nil && err != http.ErrServerClosed { klog.Errorf("http server stop error:%s", err) return err } // 这里一定不能只写 return err,如果返回http.ErrServerClosed,会被认为是正常退出,不认为是个错误,因此if err := group.Wait(); err != nil不会被触发 return errors.New("http server shutdown gracefully") ``` # 部署运行方法 见项目deploy目录 # 更新计划 + server端补充代码,当调用自己的get接口获取数据的时候,打印agent端信息 √ + server端的deploy文件补充健康检查探针部分 √ + 补充一个简单的前端,提供一个页面可以让用户对targets进行增删改查