巡检任务应使用 time.ticker 配合非阻塞 select 和 context 控制单次执行生命周期,避免堆积;通过 inspector 接口和注册表实现多类型复用;结果存入 wal 模式 sqlite 并定期归档;禁用 ssh 密码登录,强制密钥认证与指纹校验;异常阈值须可配、可灰度、可交叉判断。

巡检任务怎么用 time.Ticker 安全调度而不堆积
直接用 time.Tick 或裸写 for { time.Sleep(); do() } 很容易在任务执行时间超过间隔时造成并发堆积,尤其当巡检项涉及 HTTP 请求、SSH 登录或数据库查询时。
正确做法是用 time.Ticker 配合非阻塞 select + context 控制单次执行生命周期:
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
<p>for {
select {
case </p>
- 不要在
ticker.C分支里直接调用耗时函数,必须用 goroutine 包裹 -
runInspection内部所有阻塞操作(http.Client.Do、ssh.Dial、db.QueryRowContext)都得传入ctx - 避免用
time.AfterFunc替代 ticker——它不保证准时,且无法优雅停止
如何让不同巡检类型复用同一套执行框架
HTTP 探活、端口连通性、SQL 查询结果校验、日志关键词扫描……这些逻辑差异大,但共性是「输入参数 → 执行 → 输出结构化结果」。硬编码每种类型会导致维护爆炸。
推荐定义统一接口 + 注册表模式:
type Inspector interface {
Name() string
Run(ctx context.Context, cfg map[string]interface{}) (InspectionResult, error)
}
<p>var inspectors = make(map[string]Inspector)</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill8096" title="Alibabacloud Sdk Client Initialization For Golang"><img
src="https://img.php.cn/upload/skill/000/000/081/179186233233253.jpg" alt="Alibabacloud Sdk Client Initialization For Golang" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill8096" title="Alibabacloud Sdk Client Initialization For Golang" class="overflowclass">Alibabacloud Sdk Client Initialization For Golang</a>
<p class="overflowclass">初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。</p>
</div>
<a rel="nofollow" href="/xiazai/skill8096" title="Alibabacloud Sdk Client Initialization For Golang" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><p>func Register(name string, insp Inspector) {
inspectors[name] = insp
}</p>
- 每个巡检类型实现
Inspector,例如HTTPInspector、PortInspector - 配置文件中用
"type": "http"字段决定实例化哪个,避免 if-else 链 - 参数通过
cfg map[string]interface{}传入,比强绑定 struct 更灵活,也方便从 YAML/JSON 解析
巡检结果怎么存才方便告警和回溯
只打日志或打印到控制台等于没巡检。但直接写 MySQL 或 PostgreSQL 又太重,小规模部署反而成瓶颈。
折中方案:本地 SQLite + WAL 模式 + 定期归档:
- 用
github.com/mattn/go-sqlite3,打开时加_journal_mode=WAL参数,支持高并发写入 - 表结构聚焦三个字段:
inspection_name TEXT、status INTEGER(0=ok, 1=warn, 2=error)、message TEXT、created_at DATETIME - 每天凌晨自动把前一天数据
INSERT INTO history SELECT ...到归档表,再DELETE FROM current WHERE created_at - 告警模块轮询
SELECT * FROM current WHERE status > 0 ORDER BY created_at DESC LIMIT 10即可
为什么别在巡检里做 SSH 密码登录
Go 标准库 golang.org/x/crypto/ssh 支持密码认证,但生产环境用密码登录巡检主机属于高危行为:凭据硬编码、无审计、易爆破、无法批量轮换。
- 强制使用密钥对,私钥路径从环境变量读取(如
SSH_KEY_PATH=/etc/inspector/id_rsa),绝不写死 - 连接前加指纹校验:
ssh.InsecureIgnoreHostKey()必须禁用,改用knownhosts.New加载~/.ssh/known_hosts - 如果目标机器不支持密钥登录,宁可先走 Ansible 推送密钥,也不要妥协用密码
- 注意:某些旧版 OpenSSH 默认禁用
rsa-sha2-256等新算法,ssh.ClientConfig需显式启用HostKeyAlgorithms
巡检平台真正的难点不在调度或采集,而在于「异常边界怎么定义」——HTTP 状态码 503 算故障还是临时抖动?SQL 查询超时 3s 是慢还是挂了?这些阈值必须可配、可灰度、可关联多个指标交叉判断,否则自动化只是把人工点鼠标变成了自动点鼠标。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










