69 lines
1.8 KiB
Go
69 lines
1.8 KiB
Go
package failover
|
|
|
|
import (
|
|
"github.com/juju/errors"
|
|
"github.com/siddontang/go-mysql/mysql"
|
|
)
|
|
|
|
// Failover will do below things after the master down
|
|
// 1. Elect a slave which has the most up-to-date data with old master
|
|
// 2. Promote the slave to new master
|
|
// 3. Change other slaves to the new master
|
|
//
|
|
// Limitation:
|
|
// 1, All slaves must have the same master before, Failover will check using master server id or uuid
|
|
// 2, If the failover error, the whole topology may be wrong, we must handle this error manually
|
|
// 3, Slaves must have same replication mode, all use GTID or not
|
|
//
|
|
func Failover(flavor string, slaves []*Server) ([]*Server, error) {
|
|
var h Handler
|
|
var err error
|
|
|
|
switch flavor {
|
|
case mysql.MySQLFlavor:
|
|
h = new(MysqlGTIDHandler)
|
|
case mysql.MariaDBFlavor:
|
|
return nil, errors.Errorf("MariaDB failover is not supported now")
|
|
default:
|
|
return nil, errors.Errorf("invalid flavor %s", flavor)
|
|
}
|
|
|
|
// First check slaves use gtid or not
|
|
if err := h.CheckGTIDMode(slaves); err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
|
|
// Stop all slave IO_THREAD and wait the relay log done
|
|
for _, slave := range slaves {
|
|
if err = h.WaitRelayLogDone(slave); err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
}
|
|
|
|
var bestSlave *Server
|
|
// Find best slave which has the most up-to-data data
|
|
if bestSlaves, err := h.FindBestSlaves(slaves); err != nil {
|
|
return nil, errors.Trace(err)
|
|
} else {
|
|
bestSlave = bestSlaves[0]
|
|
}
|
|
|
|
// Promote the best slave to master
|
|
if err = h.Promote(bestSlave); err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
|
|
// Change master
|
|
for i := 0; i < len(slaves); i++ {
|
|
if bestSlave == slaves[i] {
|
|
continue
|
|
}
|
|
|
|
if err = h.ChangeMasterTo(slaves[i], bestSlave); err != nil {
|
|
return nil, errors.Trace(err)
|
|
}
|
|
}
|
|
|
|
return slaves, nil
|
|
}
|