golang数据库分片支持ORM和原生SQL的插件库octillery的使用

Golang数据库分片支持ORM和原生SQL的插件库Octillery的使用

Octillery是一个Go语言的数据库分片库,支持与各种ORM库(xorm、gorp、gorm、dbr等)一起使用,也支持原生SQL。它目前支持MySQL(生产环境)和SQLite3(测试环境)。

主要特性

  • 支持所有实现了database/sql接口的ORM库
  • 支持直接使用原生SQL
  • 可插拔的分片算法(内置modulo和hashmap算法)
  • 可插拔的数据库适配器(内置mysql和sqlite3适配器)
  • 使用YAML声明式配置分片
  • 可配置分片算法、数据库适配器、分片键、是否使用序列生成器等
  • 支持在查询传递给数据库驱动前捕获读写查询
  • 支持通过CLI进行数据库迁移(基于schemalex)
  • 支持从CSV导入种子数据

安装

安装CLI工具

go get go.knocknote.io/octillery/cmd/octillery

安装库

go get go.knocknote.io/octillery

使用示例

1. 替换database/sql导入

octillery transpose

2. 安装数据库适配器

octillery install --mysql

3. 创建YAML配置文件(databases.yml)

default: &default
  adapter: mysql
  encoding: utf8mb4
  username: root
  master:
    - localhost:3306

tables:
  posts:
    shard: true
    shard_key: user_id
    shards:
      - post_shard_1:
          <<: *default
          database: posts_shard_1
      - post_shard_2:
          <<: *default
          database: posts_shard_2

4. 数据库迁移

octillery migrate --config databases.yml /path/to/schema

5. 在代码中使用

package main

import (
	"go.knocknote.io/octillery"
	"go.knocknote.io/octillery/database/sql"
)

func main() {
	if err := octillery.LoadConfig("databases.yml"); err != nil {
		panic(err)
	}
	db, _ := sql.Open("mysql", "")
	db.QueryRow("...")
}

工作原理

Octillery通过以下方式工作:

  1. 替换database/sql导入为go.knocknote.io/octillery/database/sql,从而可以捕获所有查询
  2. 使用vitess-sqlparser解析SQL语句
  3. 根据配置决定使用序列生成器还是分片键
  4. 根据分片算法选择目标数据库

分片策略

Octillery支持两种分片策略:

1. 使用序列生成器

当需要所有分片中的ID保持唯一时使用。工作流程:

  1. 应用向序列生成器请求ID值
  2. 序列生成器生成全局唯一ID
  3. 替换SQL中的ID值为生成的ID
  4. 根据ID值选择目标分片

2. 使用分片键(不使用序列生成器)

当不关心ID的唯一性时使用。工作流程:

  1. 根据分片键值选择目标分片
  2. 直接插入记录到选定分片

扩展支持

添加新的数据库适配器

  1. 实现DBAdapter接口
  2. 将新适配器文件放入go.knocknote.io/octillery/plugin目录

添加新的分片算法

  1. 实现ShardingAlgorithm接口
  2. 将新算法文件放入go.knocknote.io/octillery/algorithm目录

开发

安装依赖

make deps

运行测试

make test

Octillery是一个功能强大的Go语言数据库分片解决方案,可以轻松地与现有ORM或原生SQL代码集成,提供灵活的配置选项和扩展能力。


更多关于golang数据库分片支持ORM和原生SQL的插件库octillery的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang数据库分片支持ORM和原生SQL的插件库octillery的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Octillery: Golang 数据库分片插件库

Octillery 是一个支持数据库分片(sharding)的 Golang ORM 和原生 SQL 插件库,它可以在不修改现有代码的情况下为应用添加分片功能。

主要特性

  1. 同时支持 ORM 和原生 SQL 操作
  2. 支持多种分片策略
  3. 与现有 ORM 兼容(如 GORM)
  4. 支持读写分离
  5. 支持事务

安装

go get -u github.com/knocknote/octillery

基本使用示例

1. 配置分片

首先需要创建一个配置文件 config.yaml

development:
  databases:
    - name: user_shard_1
      driver: "mysql"
      datasource: "user:password@tcp(127.0.0.1:3306)/user_shard_1?parseTime=true"
      show_query: true
    - name: user_shard_2
      driver: "mysql"
      datasource: "user:password@tcp(127.0.0.1:3306)/user_shard_2?parseTime=true"
      show_query: true
  shards:
    - name: user_shard
      adapter: modulo
      databases:
        - user_shard_1
        - user_shard_2
      tables:
        - users

2. 初始化 Octillery

package main

import (
	"github.com/knocknote/octillery"
	_ "github.com/go-sql-driver/mysql"
)

func init() {
	if err := octillery.LoadConfig("config.yaml"); err != nil {
		panic(err)
	}
}

3. 使用 ORM 方式操作分片数据库

package main

import (
	"fmt"
	"log"
	
	"github.com/knocknote/octillery"
	"github.com/knocknote/octillery/connection"
)

type User struct {
	ID   int64  `db:"id"`
	Name string `db:"name"`
	Age  int    `db:"age"`
}

func main() {
	// 获取分片连接管理器
	manager := connection.NewConnectionManager()
	
	// 通过 ORM 方式插入数据
	user := &User{Name: "Alice", Age: 25}
	if _, err := manager.InsertByTableName("users", user); err != nil {
		log.Fatal(err)
	}
	
	// 查询数据
	var users []*User
	if err := manager.FindByTableName("users", &users, "name = ?", "Alice"); err != nil {
		log.Fatal(err)
	}
	
	for _, u := range users {
		fmt.Printf("ID: %d, Name: %s, Age: %d\n", u.ID, u.Name, u.Age)
	}
}

4. 使用原生 SQL 操作分片数据库

package main

import (
	"fmt"
	"log"
	
	"github.com/knocknote/octillery"
	"github.com/knocknote/octillery/connection"
)

func main() {
	// 获取分片连接管理器
	manager := connection.NewConnectionManager()
	
	// 原生 SQL 插入
	result, err := manager.ExecByTableName("users", 
		"INSERT INTO users (name, age) VALUES (?, ?)", "Bob", 30)
	if err != nil {
		log.Fatal(err)
	}
	id, _ := result.LastInsertId()
	fmt.Printf("Inserted user ID: %d\n", id)
	
	// 原生 SQL 查询
	rows, err := manager.QueryByTableName("users", 
		"SELECT id, name, age FROM users WHERE name = ?", "Bob")
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()
	
	for rows.Next() {
		var id int64
		var name string
		var age int
		if err := rows.Scan(&id, &name, &age); err != nil {
			log.Fatal(err)
		}
		fmt.Printf("ID: %d, Name: %s, Age: %d\n", id, name, age)
	}
}

5. 与 GORM 集成

package main

import (
	"fmt"
	"log"
	
	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	"github.com/knocknote/octillery"
	"github.com/knocknote/octillery/connection"
)

type User struct {
	gorm.Model
	Name string
	Age  int
}

func main() {
	// 初始化 Octillery
	if err := octillery.LoadConfig("config.yaml"); err != nil {
		log.Fatal(err)
	}
	
	// 获取 GORM 分片连接
	db, err := connection.GormConnectionManager().Connection("users")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	
	// 自动迁移
	db.AutoMigrate(&User{})
	
	// 创建记录
	db.Create(&User{Name: "Charlie", Age: 35})
	
	// 查询
	var user User
	db.First(&user, "name = ?", "Charlie")
	fmt.Printf("User: %+v\n", user)
}

分片策略

Octillery 支持多种分片策略:

  1. Modulo:基于 ID 的取模分片
  2. Range:基于 ID 的范围分片
  3. Date:基于日期的分片
  4. Custom:自定义分片策略

可以在配置文件中指定分片策略:

shards:
  - name: user_shard
    adapter: modulo  # 或 range, date, custom
    databases:
      - user_shard_1
      - user_shard_2
    tables:
      - users

事务支持

func transferMoney(fromID, toID int64, amount float64) error {
	tx, err := connection.NewConnectionManager().BeginByTableName("accounts")
	if err != nil {
		return err
	}
	defer tx.RollbackUnlessCommitted()
	
	// 扣款
	if _, err := tx.Exec("UPDATE accounts SET balance = balance - ? WHERE id = ?", amount, fromID); err != nil {
		return err
	}
	
	// 存款
	if _, err := tx.Exec("UPDATE accounts SET balance = balance + ? WHERE id = ?", amount, toID); err != nil {
		return err
	}
	
	return tx.Commit()
}

注意事项

  1. 跨分片事务不被支持
  2. 复杂的跨分片 JOIN 操作可能会有性能问题
  3. 分片键的选择对性能至关重要

Octillery 为 Golang 应用提供了简单易用的数据库分片解决方案,无论是使用 ORM 还是原生 SQL,都能轻松实现分片功能。

回到顶部