Golang基于Mysql分布式锁实现集群主备
Posted NetRookieX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang基于Mysql分布式锁实现集群主备相关的知识,希望对你有一定的参考价值。
集群中如果需要主备,可以基于Redis、zk的分布式锁等实现,本文将介绍如何利用Mysql分布式锁进行实现。
背景
集群中如果需要主备,可以基于Redis、zk的分布式锁等实现,本文将介绍如何利用Mysql分布式锁进行实现。
原理
- 数据库中包含数据字段(此处为Master的主机名)、版本号和上一次更新时间。
- Master不断上传自己的心跳,即刷新数据库中的"更新时间"。
- 上一次更新时间超过了一定时间,则认为Master已Down,则可以抢Master。
- 抢Master和更新心跳时,版本号+1,要判断版本号是否与上一次读取的数据相同。如果相同,则修改成功。如果不相同,则说明Master已经被其他主机抢走。
数据库建表
- master存放主机名
CREATE TABLE `host_master` (
`id` int NOT NULL AUTO_INCREMENT,
`master` varchar(64) NOT NULL COMMENT \'主机名\',
`version` int COMMENT \'版本号\',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT \'保存数据时间,自动生成\',
PRIMARY KEY (`id`)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into host_master(master,version) value(\'\',0); //插入一条空数据
Golang实现集群主备
package main
import (
"errors"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"os"
"time"
)
var (
DB *gorm.DB
curHost = "2"
healthTime float64 = 10 //上传心跳的周期
healthTimeout float64 = 30 //健康检查过期时间
)
type HostMaster struct
ID int64 `gorm:"column:id"`
Master string `gorm:"column:master"` // 主机名
Version int64 `gorm:"column:version"` // 版本号
UpdateTime *time.Time `gorm:"column:update_time"` // 保存数据时间,自动生成
//初始化数据库
func InitDB()error
var err error
DB, err = gorm.Open("mysql", "root:123456@(192.168.191.128:3306)/test?charset=utf8&parseTime=True&loc=Local")
if err != nil
return err
DB.SingularTable(true)
return nil
//获取Master的信息
func GetMasterInfo()(HostMaster,error)
var hostMasters []HostMaster
ret := DB.Find(&hostMasters)
if ret.Error!=nil
return HostMaster,ret.Error
if ret.RowsAffected==0 || ret.RowsAffected>1
return HostMaster,errors.New(fmt.Sprintf("HostMaster表中的条目为%d",ret.RowsAffected))
return hostMasters[0],nil
//抢Master与更新心跳
func GrabMaster()error
//获取Master的信息
hostMaster,err := GetMasterInfo()
if err!=nil
return err
//当前主机为Master则更新心跳.或Master已down则抢Master
if hostMaster.Master==curHost || time.Now().Sub(*hostMaster.UpdateTime).Seconds()>healthTimeout
ret := DB.Model(&HostMaster).Where("version = ?",hostMaster.Version).Updates(map[string]interface"master":curHost,"version":hostMaster.Version+1)
if ret.Error!=nil
return errors.New("修改失败: "+ret.Error.Error())
if ret.RowsAffected==0
return nil
else
if hostMaster.Master==curHost
fmt.Println(curHost+"更新了心跳")
else
fmt.Println(curHost+"抢Master成功")
return nil
func main()
//初始化数据库
err := InitDB()
if err!=nil
fmt.Println(err)
os.Exit(1)
//周期性更新心跳和抢Master
go func()
for
err := GrabMaster()
if err!=nil
fmt.Println(err)
time.Sleep(10*time.Second)
()
select
郭少
以上是关于Golang基于Mysql分布式锁实现集群主备的主要内容,如果未能解决你的问题,请参考以下文章