前戏 小白:你好,老花!最近有个刁民让我测试部署的分片集群是否可用, 除了上官方上下载mongosh, 还有其他思路?
老花:当然有的! 我们可以用golang直接撸一个! 我们先整理一个功能清单:
mclient flags: --uri mongodb 连接地址 --user 测试创建随机用户,并返回用户和密码 --insert 测试写入数据, 打印写入的随机条数 --read 测试插入随机数据, 并读取改数据 --remove 测试插入随机数据, 并删除该数据, 返回删除条数 搭建golang环境 下载 Go 语言 SDK 工具包:访问 Go 官网下载适合Linux的安装包。
解压安装包到指定目录,例如/root/go。
配置环境变量:
使用root权限编辑/etc/profile文件。 添加export GOROOT=/root/go和export PATH=$PATH:$GOROOT/bin。 执行source /etc/profile刷新配置。 测试配置是否生效,运行go version。
配置 Go 语言开发工具 可以选择多种开发工具,如 Visual Studio Code、GoLand 等,并安装相应的 Go 语言插件以支持智能提示、编译运行等功能 。
配置国内代理
由于国内网络环境的特殊性,配置国内代理可以加速 Go 模块的下载。可以通过设置环境变量 GOPROXY 来实现:
go env -w GOPROXY=https://goproxy.cn,direct go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/ mclient 功能实现 连接数据库 client, err := mongo.NewClient(options.Client().ApplyURI(uri)) if err != nil { log.Fatalf("Failed to create MongoDB client: %v", err) } // 设置连接超时 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // 连接到MongoDB集群 err = client.Connect(ctx) if err != nil { log.Fatalf("Failed to connect to MongoDB cluster: %v", err) } defer client.Disconnect(ctx) // 确认连接成功,发送ping命令 err = client.Ping(ctx, readpref.Primary()) if err != nil { log.Fatalf("Failed to ping MongoDB cluster: %v", err) } fmt.Println("Connected to MongoDB cluster successfully!") 创建随机用户 func createRandomUser(client *mongo.Client) { collection := client.Database("admin").Collection("system.users") ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() rand.Seed(time.Now().UnixNano()) username := fmt.Sprintf("user%d", rand.Int()) password := fmt.Sprintf("password%d", rand.Int()) user := bson.M{"user": username, "pwd": password, "roles": []bson.M{{"role": "readWrite", "db": "testdb"}}} _, err := collection.InsertOne(ctx, user) if err != nil { log.Fatalf("Failed to create user: %v", err) } fmt.Printf("User created with username: %s and password: %s\n", username, password) } 插入随机数据 func insertRandomDocuments(client *mongo.Client, num int) { collection := client.Database("testdb").Collection("testdata") ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() var documents []interface{} for i := 0; i < num; i++ { documents = append(documents, bson.M{"name": fmt.Sprintf("hahahaa%d", i), "age": rand.Intn(100)}) } result, err := collection.InsertMany(ctx, documents) if err != nil { log.Fatalf("Failed to insert documents: %v", err) } fmt.Printf("Inserted %d documents with IDs: %v\n", len(result.InsertedIDs), result.InsertedIDs) } 读取和删除数据 func insertAndReadRandomDocuments(client *mongo.Client, num int) { collection := client.Database("testdb").Collection("testdata") ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() var documents []interface{} for i := 0; i < num; i++ { documents = append(documents, bson.M{"name": fmt.Sprintf("hahahaa%d", i), "age": rand.Intn(100)}) } result, err := collection.InsertMany(ctx, documents) if err != nil { log.Fatalf("Failed to insert documents: %v", err) } var results []bson.M cur, err := collection.Find(ctx, bson.M{}) if err != nil { log.Fatalf("Failed to read documents: %v", err) } defer cur.Close(ctx) for cur.Next(ctx) { var elem bson.M err := cur.Decode(&elem) if err != nil { log.Fatal(err) } results = append(results, elem) } if err := cur.Err(); err != nil { log.Fatal(err) } fmt.Println("Documents read from database:", results) } func insertAndRemoveRandomDocuments(client *mongo.Client, num int) { collection := client.Database("testdb").Collection("testdata") ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() var documents []interface{} for i := 0; i < num; i++ { documents = append(documents, bson.M{"name": fmt.Sprintf("hahahaa%d", i), "age": rand.Intn(100)}) } result, err := collection.InsertMany(ctx, documents) if err != nil { log.Fatalf("Failed to insert documents: %v", err) } filter := bson.M{"name": bson.M{"$in": []string{"hahahaa0"}}} deleteResult, err := collection.DeleteMany(ctx, filter) if err != nil { log.Fatalf("Failed to delete documents: %v", err) } fmt.Printf("Deleted %d documents\n", deleteResult.DeletedCount) } 完整代码 package main import ( "context" "flag" "fmt" "log" "math/rand" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/readpref" ) // 定义命令行参数 var uri string var createUserFlag bool var insertFlag bool var readFlag bool var removeFlag bool var numDocuments int func init() { // 默认URI设置为localhost,用户可以通过命令行参数--uri来覆盖 flag.StringVar(&uri, "uri", "mongodb://localhost:27017", "MongoDB connection URI") flag.BoolVar(&createUserFlag, "user", false, "Test creating a random user") flag.BoolVar(&insertFlag, "insert", false, "Test inserting random data") flag.BoolVar(&readFlag, "read", false, "Test inserting and reading random data") flag.BoolVar(&removeFlag, "remove", false, "Test inserting and removing random data") flag.IntVar(&numDocuments, "num", 1, "Number of random documents to insert") } func main() { flag.Parse() // 解析命令行参数 // 创建MongoDB客户端 client, err := mongo.NewClient(options.Client().ApplyURI(uri)) if err != nil { log.Fatalf("Failed to create MongoDB client: %v", err) } // 设置连接超时 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() // 连接到MongoDB集群 err = client.Connect(ctx) if err != nil { log.Fatalf("Failed to connect to MongoDB cluster: %v", err) } defer client.Disconnect(ctx) // 确认连接成功,发送ping命令 err = client.Ping(ctx, readpref.Primary()) if err != nil { log.Fatalf("Failed to ping MongoDB cluster: %v", err) } fmt.Println("Connected to MongoDB cluster successfully!") if createUserFlag { createRandomUser(client) } if insertFlag { insertRandomDocuments(client, numDocuments) } if readFlag { insertAndReadRandomDocuments(client, numDocuments) } if removeFlag { insertAndRemoveRandomDocuments(client, numDocuments) } } func createRandomUser(client *mongo.Client) { collection := client.Database("admin").Collection("system.users") ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() rand.Seed(time.Now().UnixNano()) username := fmt.Sprintf("user%d", rand.Int()) password := fmt.Sprintf("password%d", rand.Int()) user := bson.M{"user": username, "pwd": password, "roles": []bson.M{{"role": "readWrite", "db": "testdb"}}} _, err := collection.InsertOne(ctx, user) if err != nil { log.Fatalf("Failed to create user: %v", err) } fmt.Printf("User created with username: %s and password: %s\n", username, password) } func insertRandomDocuments(client *mongo.Client, num int) { collection := client.Database("testdb").Collection("testdata") ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() var documents []interface{} for i := 0; i < num; i++ { documents = append(documents, bson.M{"name": fmt.Sprintf("hahahaa%d", i), "age": rand.Intn(100)}) } _, err := collection.InsertMany(ctx, documents) if err != nil { log.Fatalf("Failed to insert documents: %v", err) } fmt.Printf("Inserted %d documents with IDs: %v\n", len(result.InsertedIDs), result.InsertedIDs) } func insertAndReadRandomDocuments(client *mongo.Client, num int) { collection := client.Database("testdb").Collection("testdata") ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() var documents []interface{} for i := 0; i < num; i++ { documents = append(documents, bson.M{"name": fmt.Sprintf("hahahaa%d", i), "age": rand.Intn(100)}) } _, err := collection.InsertMany(ctx, documents) if err != nil { log.Fatalf("Failed to insert documents: %v", err) } var results []bson.M cur, err := collection.Find(ctx, bson.M{}) if err != nil { log.Fatalf("Failed to read documents: %v", err) } defer cur.Close(ctx) for cur.Next(ctx) { var elem bson.M err := cur.Decode(&elem) if err != nil { log.Fatal(err) } results = append(results, elem) } if err := cur.Err(); err != nil { log.Fatal(err) } fmt.Println("Documents read from database:", results) } func insertAndRemoveRandomDocuments(client *mongo.Client, num int) { collection := client.Database("testdb").Collection("testdata") ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() var documents []interface{} for i := 0; i < num; i++ { documents = append(documents, bson.M{"name": fmt.Sprintf("hahahaa%d", i), "age": rand.Intn(100)}) } _, err := collection.InsertMany(ctx, documents) if err != nil { log.Fatalf("Failed to insert documents: %v", err) } filter := bson.M{"name": bson.M{"$in": []string{"hahahaa0"}}} deleteResult, err := collection.DeleteMany(ctx, filter) if err != nil { log.Fatalf("Failed to delete documents: %v", err) } fmt.Printf("Deleted %d documents\n", deleteResult.DeletedCount) } 编译二进制 编译命令 编译单个文件:go build -o myapp myapp.go。 编译模块:go build -mod=readonly -o myapp ./...。 编译交叉平台:GOOS=windows GOARCH=amd64 go build -o myapp_windows_amd64 myapp.go。 编译优化 优化代码:避免不必要的包依赖,使用 Go 的性能分析工具(如 pprof),优化数据结构和算法。 优化编译选项:使用-gcflags="all=-N -l"禁用垃圾回收和内联优化,使用-buildmode=pie生成位置无关可执行文件。 优化构建工具:使用 Makefile 或构建系统(如 Bazel、Maven)自动化编译过程,使用并行编译提高编译速度。 测试效果 使用上一篇博客部署的集群测试, 拿到mongos的ip: 10.244.2.2:
...