golang主从数据库自动负载均衡代理插件库mssqlx的使用

golang主从数据库自动负载均衡代理插件库mssqlx的使用

简介

mssqlx是一个可嵌入、高可用、高性能且轻量级的数据库客户端库,支持Go 1.9及以上版本。主要特性包括:

  • 作为sqlx的扩展层
  • 自动代理任何主从、主主数据库,兼容Wsrep、Galera集群等
  • 自动轻量级轮询负载均衡查询
  • 内置对Wsrep、Galera和一些数据库驱动程序的错误处理
  • 自动健康检查

安装

go get -u github.com/linxGnu/mssqlx

连接数据库

mssqlx兼容所有database/sql支持的数据库类型。以下是MySQL使用示例:

import (
    _ "github.com/go-sql-driver/mysql"
    "github.com/linxGnu/mssqlx"
)

dsn := "root:123@(%s:3306)/test?charset=utf8&collation=utf8_general_ci&parseTime=true"
masterDSNs := []string{
    fmt.Sprintf(dsn, "172.31.25.233"), // 主节点1地址
    fmt.Sprintf(dsn, "172.31.24.233"), // 主节点2地址(如果有)
    fmt.Sprintf(dsn, "172.31.23.233"), // 主节点3地址(如果有)
}
slaveDSNs := []string{
    fmt.Sprintf(dsn, "172.31.25.234"), // 从节点1地址
    fmt.Sprintf(dsn, "172.31.25.235"), // 从节点2地址
    fmt.Sprintf(dsn, "172.31.25.236"), // 从节点3地址
}

db, _ := mssqlx.ConnectMasterSlaves("mysql", masterDSNs, slaveDSNs)

连接Galera集群

建议设置如下标志:

db, _ := mssqlx.ConnectMasterSlaves("mysql", masterDSNs, slaveDSNs, mssqlx.WithWsrep())

自定义读查询源

读查询将在主节点和从节点之间分配:

db, _ := mssqlx.ConnectMasterSlaves("mysql", masterDSNs, slaveDSNs, mssqlx.WithReadQuerySource(mssqlx.ReadQuerySourceAll))

配置

建议在查询前进行配置:

db.SetMaxIdleConns(20) // 设置所有节点的最大空闲连接数
// db.SetMasterMaxIdleConns(20) // 设置主节点的最大空闲连接数
// db.SetSlaveMaxIdleConns(20) // 设置从节点的最大空闲连接数

db.SetMaxOpenConns(50) // 设置所有节点的最大打开连接数
// db.SetMasterMaxOpenConns(50) 
// db.SetSlaveMaxOpenConns(50)
    
// 如果节点失败,定期检查健康状态以自动重连(毫秒),默认为500
db.SetHealthCheckPeriod(1000) 
// db.SetMasterHealthCheckPeriod(1000)
// db.SetSlaveHealthCheckPeriod(1000)

查询示例

Select查询

type Person struct {
    FirstName string `db:"first_name"`
    LastName  string `db:"last_name"`
    Email     string
    Data      []byte
}

var people []Person
db.Select(&people, "SELECT * FROM person WHERE id > ? and id < ? ORDER BY first_name ASC", 1, 1000)

Get查询

var person Person
db.Get(&person, "SELECT * FROM person WHERE id = ?", 1)

Queryx查询

// 使用单个结构体循环遍历行
var person Person

rows, err := db.Queryx("SELECT * FROM person") // 或者使用db.QueryxOnMaster(...)
for rows.Next() {
    if err := rows.StructScan(&person); err != nil {
        log.Fatalln(err)
    } 
    fmt.Printf("%#v\n", person)
}

命名查询

// 使用单个结构体循环遍历行
var person Person

rows, err := db.NamedQuery(`SELECT * FROM person WHERE first_name = :fn`, map[string]interface{}{"fn": "Bin"}) // 或者使用db.NamedQueryOnMaster(...)
for rows.Next() {
    if err := rows.StructScan(&person); err != nil {
        log.Fatalln(err)
    } 
    fmt.Printf("%#v\n", person)
}

Exec操作(插入/更新/删除等)

result, err := db.Exec("DELETE FROM person WHERE id < ?", 100)

事务

// 推荐这样写事务
tx, e := db.Begin()
if e != nil {
	return e
}
    
shouldAutoRollBack := true
defer func() {
	if e := recover(); e != nil {
		err = fmt.Errorf("%v", e)
		tx.Rollback()
	} else if err != nil && shouldAutoRollBack {
		tx.Rollback()
	}
}()
			
if _, err = tx.Exec("INSERT INTO person(first_name, last_name, email, data) VALUES (?,?,?,?)", "Jon", "Dow", "jon@gmail", []byte{1, 2}); err != nil {
        return
}
    
if _, err = tx.Exec("INSERT INTO person(first_name, last_name, email, data) VALUES (?,?,?,?)", "Jon", "Snow", "snow@gmail", []byte{1}); err != nil {
    return
}
			
if err = tx.Commit(); err != nil {
    shouldAutoRollBack = false
}

注意事项

  • API支持仅在主节点或从节点上执行查询。在主节点上查询的函数名有后缀OnMaster,在从节点上查询的函数名有后缀OnSlave
  • 默认情况下,select/show查询会在从节点上负载均衡

更多关于golang主从数据库自动负载均衡代理插件库mssqlx的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang主从数据库自动负载均衡代理插件库mssqlx的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


MSSQLX: Golang主从数据库自动负载均衡代理插件库

MSSQLX是一个用于Golang的数据库代理库,专门为Microsoft SQL Server设计,提供主从数据库的自动负载均衡功能。下面我将详细介绍它的使用方法和示例代码。

主要特性

  1. 自动识别主从数据库
  2. 读写分离
  3. 负载均衡
  4. 连接池管理
  5. 故障自动转移

安装

go get github.com/denisenkom/go-mssqldb
go get github.com/your-repo/mssqlx

基本使用示例

package main

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	"github.com/denisenkom/go-mssqldb"
	"github.com/your-repo/mssqlx"
)

func main() {
	// 配置主从服务器
	config := mssqlx.Config{
		Master: mssqlx.ServerConfig{
			Host:     "master-server",
			Port:     1433,
			User:     "sa",
			Password: "your-password",
			Database: "your-db",
		},
		Slaves: []mssqlx.ServerConfig{
			{
				Host:     "slave1-server",
				Port:     1433,
				User:     "sa",
				Password: "your-password",
				Database: "your-db",
			},
			{
				Host:     "slave2-server",
				Port:     1433,
				User:     "sa",
				Password: "your-password",
				Database: "your-db",
			},
		},
		MaxOpenConns:    100,
		MaxIdleConns:    10,
		ConnMaxLifetime: time.Hour,
	}

	// 创建代理
	proxy, err := mssqlx.NewProxy(config)
	if err != nil {
		log.Fatal("Failed to create proxy:", err)
	}
	defer proxy.Close()

	// 执行查询(自动路由到从库)
	rows, err := proxy.Query("SELECT * FROM users WHERE status = ?", 1)
	if err != nil {
		log.Fatal("Query failed:", err)
	}
	defer rows.Close()

	// 处理结果...
	for rows.Next() {
		var id int
		var name string
		if err := rows.Scan(&id, &name); err != nil {
			log.Fatal("Scan failed:", err)
		}
		fmt.Printf("ID: %d, Name: %s\n", id, name)
	}

	// 执行写入(自动路由到主库)
	result, err := proxy.Exec("UPDATE users SET status = ? WHERE id = ?", 2, 123)
	if err != nil {
		log.Fatal("Exec failed:", err)
	}
	affected, _ := result.RowsAffected()
	fmt.Printf("Rows affected: %d\n", affected)
}

高级功能

1. 自定义负载均衡策略

// 自定义负载均衡策略
type CustomBalancer struct{}

func (b *CustomBalancer) Select(slaves []*sql.DB) *sql.DB {
	// 实现自定义的选择逻辑,例如轮询、随机或基于权重的选择
	return slaves[0] // 简单示例:总是选择第一个从库
}

// 使用自定义负载均衡器
config := mssqlx.Config{
	// ...其他配置
	Balancer: &CustomBalancer{},
}

2. 事务处理

// 开始事务(总是在主库上执行)
tx, err := proxy.Begin()
if err != nil {
	log.Fatal("Begin transaction failed:", err)
}

// 执行事务操作
_, err = tx.Exec("UPDATE accounts SET balance = balance - ? WHERE id = ?", 100, 1)
if err != nil {
	tx.Rollback()
	log.Fatal("Update failed:", err)
}

_, err = tx.Exec("UPDATE accounts SET balance = balance + ? WHERE id = ?", 100, 2)
if err != nil {
	tx.Rollback()
	log.Fatal("Update failed:", err)
}

// 提交事务
err = tx.Commit()
if err != nil {
	log.Fatal("Commit failed:", err)
}

3. 手动指定数据库

// 强制使用主库查询
rows, err := proxy.Master().Query("SELECT * FROM sensitive_data")

// 强制使用特定从库查询
rows, err := proxy.Slave(1).Query("SELECT * FROM large_table")

4. 健康检查与监控

// 获取主库状态
masterStatus := proxy.MasterStatus()
fmt.Printf("Master status: %+v\n", masterStatus)

// 获取所有从库状态
for i, slaveStatus := range proxy.SlavesStatus() {
	fmt.Printf("Slave %d status: %+v\n", i, slaveStatus)
}

// 设置健康检查间隔
proxy.SetHealthCheckInterval(30 * time.Second)

最佳实践

  1. 连接池配置:根据应用负载合理设置MaxOpenConns和MaxIdleConns
  2. 错误处理:实现重试逻辑处理临时性故障
  3. 监控:定期检查数据库节点健康状况
  4. 读写分离:确保只读查询确实不需要最新数据时才路由到从库

注意事项

  1. 主从复制延迟可能导致从库数据不是最新的
  2. 事务中的所有操作都会在主库上执行
  3. 某些特定SQL可能需要在主库上执行(如存储过程调用)

MSSQLX通过简单的API抽象了主从数据库的复杂性,使得开发者可以专注于业务逻辑而不必担心数据库路由的细节。

回到顶部