golang实现mysql实例存活检查及全量备份是否完成检查工具开发

在这里插入图片描述

系列文章目录

golang实现mysql全量备份工具
golang命令行框架cobra



前言

在顶部文章中,通过golang编写了一个mysql的全量备份工具,经过验证备份工具没有问题,可以正常使用。但是在正式的生产环境中,作为运维的你怎么确认昨天的备份是成功的?最普通的方式是登上服务器手动查看,这种方式在当前的自动化运维中显得有些low了。因为生产环境中避免不了prometheus监控的接入,因此,为了解决手动确认备份成功的问题,并结合Prometheus实现备份检查告警,通过golang的cobra命令行框架编写一个备份检查工具脚本和mysql实例存活探测脚本来实现。Cobra 的命令行工具 cobra-cli 进一步提高了编写命令行程序的效率,非常推荐使用它来实现命令行工具的开发,可以加快开发速度。


一、引入cobra命令行框架

因为要开发的工具最终是以二进制命令的方式在linux服务器中执行,恰好golang的标准库cobra满足该条件,因此使用它为基础实现备份检查和实例存活检查工具的开发

在阅读下方的开发脚本过程前,先阅读顶部的第二篇文章golang命令行框架cobra,
对cobra的概念和命令使用有个整体了解后,阅读下方代码会更加容易

二、工具开发过程

1.引入库

命令如下(示例):

[root@python2 ~]# go get -u -v github.com/spf13/cobra      

[root@python2 ~]# go install github.com/spf13/cobra-cli@latest

2.cobra-cli初始化项目

[root@python2 ~]# cobra-cli init mysql_golang_tools
[root@python2 ~]# tree mysql_golang_tools
├── mysql_golang_tools
│   ├── cmd
│   │   └── root.go
│   ├── LICENSE
│   └── main.go 

3.修改cmd/root.go文件

因为备份检查和存活检查工具是分别写在不同的文件中的,所以在root.go文件中将不必要的代码先删除掉

代码如下(示例):

/*
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
*/
package cmd

import (
	"os"

	"github.com/spf13/cobra"
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
	Use:   "mysql_golang_tools",
	Short: "include mysql backupfile check and mysql alive check",
	Long:  `这是一个检查mysql 全量备份及mysql实例存活的golang脚本`,

	//Run: func(cmd *cobra.Command, args []string) { fmt.Println("hello cobra") },
}

// Execute adds all child commands to the root command and sets flags appropriately.
// 命令执行入口处
func Execute() {
	err := rootCmd.Execute()
	if err != nil {
		os.Exit(1)
	}
}

4.编写备份检查代码

mysql全量备份可参考顶部文章golang实现mysql全量备份
采用上述工具备份完成后,备份日志及备份存放目录截图如下

代码功能(示例):

1、检查指定备份存放目录下是否存在对应的备份文件
2、检查指定备份日志文件中是否包含‘compeleted OK!’字样,如果包含则说明备份是成功且完整的,反之,备份失败
3、执行构建好的二进制程序后,返回值是 mysqlbackupcheck,port=xxxx status=0/1i
4、因为这个返回值后期在对接Prometheus的自定义监控时会使用到,这个后续再说
5、status=0i代表备份失败,反之status=1i代表备份成功。只有这两种状态

代码如下(示例):

//backupFileCheck.go
package cmd

import (
	"bufio"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/spf13/cobra"
)

var mysqlBackupDirectory, mysqlBackupLogDir string

// 备份文件检查子命令入口
var backupFileCheck = &cobra.Command{
	Use:   "mysqlbackupcheck",
	Short: "这是mysql全量备份文件检查工具",
	Args:  cobra.ArbitraryArgs, //接收任意参数
	Run: func(cmd *cobra.Command, args []string) {
		CheckBackup(mysqlBackupDirectory, mysqlPort)
	},
}

// checkBackup 检查备份文件和日志文件
func CheckBackup(backupDir string, port int) {
	yesterday := time.Now().AddDate(0, 0, -1)
	filename := fmt.Sprintf("full_%s.tar.gz", yesterday.Format("20060102"))
	filePath := filepath.Join(backupDir, filename)
	logFilePath := filepath.Join(mysqlBackupLogDir, fmt.Sprintf("full_backup_data_%s.log", yesterday.Format("2006-01-02")))

	// 检查备份文件是否存在
	if _, err := os.Stat(filePath); err == nil {
		//fmt.Printf("检测到备份文件: %s\n", filePath)

		if CheckLogFile(logFilePath) {
			//fmt.Printf("备份文件 %s 完整性检查通过。\n", filePath)
			status = 1 // 昨天的备份成功
		} else {
			fmt.Printf("备份文件 %s 的日志检查失败!\n", logFilePath)
		}
	} else if os.IsNotExist(err) {
		fmt.Printf("未找到备份文件: %s\n", filePath)
	} else {
		fmt.Printf("检查文件 %s 时发生错误: %v\n", filePath, err)
	}

	// 输出结果
	fmt.Printf("mysqlbackupcheck,port=%d status=%di\n", port, status)
}

// checkLogFile 检查日志文件的最后一行是否包含 "completed OK!"
func CheckLogFile(logFilePath string) bool {
	file, err := os.Open(logFilePath)
	if err != nil {
		fmt.Printf("打开日志文件 %s 时发生错误: %v\n", logFilePath, err)
		return false
	}
	defer file.Close()

	/*
		创建一个 bufio.Scanner 对象,用于逐行读取文件中的内容。
		for scanner.Scan() 循环会遍历文件的每一行,将当前行的内容存储到 lastLine 变量中。经过完整的循环后,lastLine 中将保存文件的最后一行文本
	*/
	var lastLine string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lastLine = scanner.Text()
	}
	//在读取完所有行后,使用 scanner.Err() 检查在扫描过程中是否发生错误。如果发生错误,则打印错误信息并返回 false
	if err := scanner.Err(); err != nil {
		fmt.Printf("读取日志文件 %s 时发生错误: %v\n", logFilePath, err)
		return false
	}
	//使用 strings.Contains() 函数检查 lastLine 是否包含字符串 "completed OK!"。
	return strings.Contains(lastLine, "completed OK!")
}
func init() {
	/*
		IntVarP 方法用于定义一个整数类型的命令行标志(flag)。
		第一个参数 &port 是一个指向变量的指针,它将接收命令行输入的值。
		第二个参数 "port" 是标志的名称,可以通过 --port 来指定。
		第三个参数 "p" 是短标志的名称,可以通过 -p 来指定。
		第四个参数 3306 是该标志的默认值。如果用户在运行程序时不指定 -p 或 --port 参数,则 port 变量将自动获取这个默认值。
		最后一个参数 "MySQL 端口" 是对该参数的描述。
		因此,在运行程序时,如果您不提供 -p 参数,port 将会默认设置为 3306。如果您希望使用不同的 MySQL 端口,您可以在命令行中指定该参数
	*/
	rootCmd.AddCommand(backupFileCheck)
	backupFileCheck.Flags().StringVarP(&mysqlBackupDirectory, "directory", "d", "/export/servers/data/mybackup/my3306/xtrabackup/data", "数据库备份存放目录")
	backupFileCheck.Flags().StringVarP(&mysqlBackupLogDir, "logDir", "L", "/export/servers/data/mybackup/my3306/xtrabackup/log", "数据库备份日志目录")
	backupFileCheck.Flags().IntVarP(&mysqlPort, "port", "P", 3306, "数据库端口")
}

5.编写实例存活探测代码

代码功能(示例):

1、通过golnag 的database/sql库以及"github.com/go-sql-driver/mysql"驱动库实现在连接mysql后	,
	使用标准库中的ping()方法进行探测
2、返回值是mysqlping,host=192.168.56.131,port=3308 status=0/1i 这样,方便后续对接Prometheus的自定义监控
3、status=0i代表实例已宕机,反之status=1i代码实例存活。只有这两种状态

代码如下(示例):

//checkMysqlAlive.go
package cmd

import (
	"database/sql"
	"fmt"

	_ "github.com/go-sql-driver/mysql"
	"github.com/spf13/cobra"
)

var mysqlHost, mysqlUser, mysqlPwd string

// mysql实例通过ping 存活检查
var pingMysqlCheck = &cobra.Command{
	Use:   "mysqlping",
	Short: "这是mysql ping alive 检查工具",
	Args:  cobra.ArbitraryArgs, //接收任意参数
	Run: func(cmd *cobra.Command, args []string) {
		CheckMysqlAlive(mysqlUser, mysqlPwd, mysqlHost, mysqlPort)
	},
}

func CheckMysqlAlive(mysqluser, mysqlpwd, mysqlhost string, mysqlport int) {

	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s",
		mysqlUser, mysqlPwd, mysqlHost, mysqlPort, "mysql")
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		fmt.Printf("failed to open database connection: %v", err)
	}

	if err = db.Ping(); err != nil {
		fmt.Printf("mysqlping,host=%s,port=%d status=%di\n", mysqlHost, mysqlPort, status)
	} else {
		status := 1
		fmt.Printf("mysqlping,host=%s,port=%d status=%di\n", mysqlHost, mysqlPort, status)
	}

}

func init() {
	//将子命令pingMysqlCheck添加到主命令rootCmd中
	rootCmd.AddCommand(pingMysqlCheck)
	pingMysqlCheck.Flags().StringVarP(&mysqlUser, "user", "u", "monitor", "数据库用户")
	pingMysqlCheck.Flags().StringVarP(&mysqlPwd, "pwd", "p", "monitor", "数据库密码")
	pingMysqlCheck.Flags().StringVarP(&mysqlHost, "host", "H", "127.0.0.1", "数据库IP")
	pingMysqlCheck.Flags().IntVarP(&mysqlPort, "port", "P", 3306, "数据库端口")
}

6.公共变量定义

//common.go
package cmd

//该文件用于定义公共变量及公共函数等
var mysqlPort, status int

至此,代码功能已完成,接下来对命令工具的使用做一下演示

三、工具使用演示

1.完整的目录结构

在这里插入图片描述

2.命令工具使用

2.1.源代码构建为二进制程序

[root@python2 mysql_golang_tools]# go build -o mysqlCheckTools main.go

2.2.二进制程序帮助命令查看

父命令帮助手册

[root@python2 mysql_golang_tools]# ./mysqlCheckTools -h
这是一个检查mysql 全量备份及mysql实例存活的golang脚本

Usage:
  mysql_golang_tools [command]

Available Commands:
  completion       Generate the autocompletion script for the specified shell
  help             Help about any command
  mysqlbackupcheck 这是mysql全量备份文件检查工具
  mysqlpingcheck   这是mysql ping alive 检查工具

Flags:
  -h, --help   help for mysql_golang_tools

Use "mysql_golang_tools [command] --help" for more information about a command

两个子命令帮助手册

 [root@python2 mysql_golang_tools]# ./mysqlCheckTools mysqlbackupcheck -h
        这是mysql全量备份文件检查工具

        Usage:
        mysql_golang_tools mysqlbackupcheck [flags]

        Flags:
        -d, --directory string   数据库备份存放目录 (default "/export/servers/data/mybackup/my3306/xtrabackup/data")
        -h, --help               help for mysqlbackupcheck
        -L, --logDir string      数据库备份日志目录 (default "/export/servers/data/mybackup/my3306/xtrabackup/log")
        -P, --port int           数据库端口 (default 3306)
        
    
[root@python2 mysql_golang_tools]# ./mysqlCheckTools mysqlpingcheck -h
        这是mysql ping alive 检查工具

        Usage:
        mysql_golang_tools mysqlpingcheck [flags]

        Flags:
        -h, --help          help for mysqlpingcheck
        -H, --host string   数据库IP (default "127.0.0.1")
        -P, --port int      数据库端口 (default 3306)
        -p, --pwd string    数据库密码 (default "monitor")
        -u, --user string   数据库用户 (default "monitor")

2.3.命令执行

2.3.1. 使用自定义参数执行命令

mysql实例存活探测

[root@python2 mysql_golang_tools]# ./mysqlCheckTools mysqlpingcheck -H 192.168.56.131 -P 3308 -p dbbackup -u dbbackup
mysqlping,host=192.168.56.131,port=3308 status=0i

mysql全量备份检查

[root@python2 mysql_golang_tools]# ./mysqlCheckTools mysqlbackupcheck -d /opt/servers/data/mybackup/my3306/xtrabackup/data -L /opt/servers/data/mybackup/my3306/xtrabackup/log -P 3307
2.3.2.使用工具的默认值执行命令

准备数据库备份文件
在这里插入图片描述

#mysql实例状态检测
[root@python2 mysql_golang_tools]# ./mysqlCheckTools mysqlpingcheck 
      mysqlping,host=127.0.0.1,port=3306 status=0i

#mysql备份情况检查
[root@python2 mysql_golang_tools]# ./mysqlCheckTools mysqlbackupcheck
      mysqlbackupcheck,port=3306 status=1i

总结

写本篇文章的主要目的是加强对cobra命令行框架的使用,其次是为了满足项目需求,对全量备份结果进行自定义监控。实现自定义监控的过程在下一篇文章中,此篇文章不做概述。Cobra 不仅支持子命令,还能够完美兼容 pflag 和 Viper 包,因为这三个包都是同一个作者开发的。关于标志,Cobra 支持持久标志、本地标志以及将标志标记为必选。Cobra 可以将标志绑定到 Viper,方便使用 viper.Get() 来获取标志的值。对于命令行参数,Cobra 提供了不少验证函数,我们也可以自定义验证函数。最后,Cobra 的命令行工具 cobra-cli 进一步提高了编写命令行程序的效率,非常推荐使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值