Wizard is database/sql management library for multi instance and sharding in golang
Go
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
errors
orm/xorm
.gitignore
.travis.yml
README.md
hash.go
hash_test.go
helper.go
helper_test.go
node.go
node_test.go
reflect.go
reflect_test.go
shard_cluster.go
shard_cluster_test.go
standard_cluster.go
standard_cluster_test.go
wizard.go
wizard_test.go

README.md

Wizard

Build Status codecov.io GoDoc Join the chat at https://gitter.im/evalphobia/wizard

Wizard is database/sql management library for multi instance and sharding in golang. Inspired by MixedGauge

Supported orm list

Quick Usage

Register database clusters

import (
	_ "github.com/go-sql-driver/mysql"
	"github.com/go-xorm/xorm"

	"github.com/evalphobia/wizard"
)

type Blog struct {
	ArticleID string `xorm:"article_id pk VARCHAR(255) not null"`
	Content   string `xorm:"content text"`
}

type User struct {
	ID   int64  `xorm:"id pk BIGINT(20) not null" shard_key:"true"`
	Name string `xorm:"name VARCHAR(100) not null"`
}

func main() {
	wiz = wizard.NewWizard()

	/**
		register normal cluster
	*/

	// create engines
	blogMaster, _ = xorm.NewEngine("mysql", "root:@tcp(db-master:3306)/blog?charset=utf8")
	blogSlave01, _ = xorm.NewEngine("mysql", "root:@tcp(db-slave01:3306)/blog?charset=utf8")
	blogSlave02, _ = xorm.NewEngine("mysql", "root:@tcp(db-slave01:3306)/blog?charset=utf8")

	// create cluster with master nodel; CreateCluster(name, master-instance)
	blogCluster := wiz.CreateCluster(Blog{}, blogMaster)
	blogCluster.RegisterSlave(blogSlave01) // add slaves
	blogCluster.RegisterSlave(blogSlave02)


	/**
		register shard clusters
	*/

	// shard one
	user01Master, _ = xorm.NewEngine("mysql", "root:@/tcp(shard01-master:3306)/users?charset=utf8")
	user01Slave01, _ = xorm.NewEngine("mysql", "root:@/tcp(shard01-slave01:3306)/users?charset=utf8")
	user01Slave02, _ = xorm.NewEngine("mysql", "root:@/tcp(shard01-slave02:3306)/users?charset=utf8")

	// shard two
	user02Master, _ = xorm.NewEngine("mysql", "root:@/tcp(shard02-master:3306)/users?charset=utf8")
	user02Slave01, _ = xorm.NewEngine("mysql", "root:@/tcp(shard02-slave01:3306)/users?charset=utf8")
	user02Slave02, _ = xorm.NewEngine("mysql", "root:@/tcp(shard02-slave02:3306)/users?charset=utf8")

	// create shard clusters; CreateShardCluster(name, slot-size)
	shardClusters := wiz.CreateShardCluster(User{}, 1023)

	// create single shard set #1
	shardCluster01 := wizard.NewCluster(user01Master)
	shardCluster01.RegisterSlave(user01Slave01)
	shardCluster01.RegisterSlave(user01Slave02)

	// create single shard set #2
	shardCluster02 := wizard.NewCluster(user02Master)
	shardCluster02.RegisterSlave(user02Slave01)
	shardCluster02.RegisterSlave(user02Slave02)

	// register shards with slot; RegisterShard(min, max, cluster)
	shardClusters.RegisterShard(0, 500, shardCluster01)
	shardClusters.RegisterShard(501, 1022, shardCluster02)
}

Query on database clusters

import (
	"fmt"

	"github.com/evalphobia/wizard/orm/xorm"
)

func main() {
	orm := xorm.New(wiz)

	blog := &Blog{ArticleID: "hello-world"}
	has, err := orm.Get(blog, func(s xorm.Session) (bool, error) {
		return s.Get(blog)
	})
	// => SELECT * FROM blog WHERE article_id = "hello-world"; -- execute on blog SLAVE


	fmt.Println(has)
	fmt.Println(blog.Content)

	user := &User{
		ID:   1600, // 1600 % 1023 = 577; => shard02
		Name: "Adam Smith",
	}

	err = orm.Begin(user) // => BEGIN; -- execute on user02-MASTER
	if err != nil {
		panic("Error on transaction beginning")
	}

	total, err := orm.Insert(user, func(s xorm.Session) (int64, error) {
		return s.Insert(user)
	})
	// => INSERT INTO users VALUES(1600, "Adam Smith"); -- execute on user02-MASTER

	fmt.Println(total)

	newUser := &User{ID: 1600}
	has, err = orm.GetUsingMaster(newUser, func(s xorm.Session) (bool, error) {
		return s.Get(newUser)
	})
	// => SELECT * FROM users WHERE id = 1600; -- execute on user02-MASTER


	err = orm.Commit(user)
	// => COMMIT; -- execute on user02-MASTER
	if err != nil {
		panic("Error on transaction ending")
	}
}

Notes

  • Clusters is selected by name, which can be any value like string, struct, pointer.
    • the pointer value automatically converts to the non-pointer value.
  • Struct field tag: shard_key:"true" is used as a shard-key
    • shard_key is divided by slot size and the mod value is used for shard mapping
    • string shard_key convert to int64 with CRC64 and divided by slot-size

Other info