ToB企服应用市场:ToB评测及商务社交产业平台

标题: Golang基于Mysql分布式锁实现集群主备 [打印本页]

作者: 火影    时间: 2023-2-26 00:47
标题: Golang基于Mysql分布式锁实现集群主备
背景

集群中如果需要主备,可以基于Redis、zk的分布式锁等实现,本文将介绍如何利用Mysql分布式锁进行实现。
原理

数据库建表

  1. CREATE TABLE `host_master` (
  2.   `id` int NOT NULL AUTO_INCREMENT,
  3.   `master` varchar(64) NOT NULL COMMENT '主机名',
  4.   `version` int COMMENT '版本号',
  5.   `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '保存数据时间,自动生成',
  6.   PRIMARY KEY (`id`)
  7. )
  8. ENGINE=InnoDB DEFAULT CHARSET=utf8;
  9. insert into host_master(master,version) value('',0);    //插入一条空数据
复制代码
Golang实现集群主备
  1. package main
  2. import (
  3.     "errors"
  4.     "fmt"
  5.     "github.com/jinzhu/gorm"
  6.     _ "github.com/jinzhu/gorm/dialects/mysql"
  7.     "os"
  8.     "time"
  9. )
  10. var (
  11.     DB *gorm.DB
  12.     curHost = "2"
  13.     healthTime float64    = 10    //上传心跳的周期
  14.     healthTimeout float64 = 30    //健康检查过期时间
  15. )
  16. type HostMaster struct {
  17.     ID         int64     `gorm:"column:id"`
  18.     Master     string    `gorm:"column:master"`      //  主机名
  19.     Version    int64     `gorm:"column:version"`     //  版本号
  20.     UpdateTime *time.Time `gorm:"column:update_time"` //  保存数据时间,自动生成
  21. }
  22. //初始化数据库
  23. func InitDB()error{
  24.     var err error
  25.     DB, err = gorm.Open("mysql", "root:123456@(192.168.191.128:3306)/test?charset=utf8&parseTime=True&loc=Local")
  26.     if err != nil {
  27.         return err
  28.     }
  29.     DB.SingularTable(true)
  30.     return nil
  31. }
  32. //获取Master的信息
  33. func GetMasterInfo()(HostMaster,error){
  34.     var hostMasters []HostMaster
  35.     ret := DB.Find(&hostMasters)
  36.     if ret.Error!=nil{
  37.         return HostMaster{},ret.Error
  38.     }
  39.     if ret.RowsAffected==0 || ret.RowsAffected>1{
  40.         return HostMaster{},errors.New(fmt.Sprintf("HostMaster表中的条目为%d",ret.RowsAffected))
  41.     }
  42.     return hostMasters[0],nil
  43. }
  44. //抢Master与更新心跳
  45. func GrabMaster()error{
  46.     //获取Master的信息
  47.     hostMaster,err := GetMasterInfo()
  48.     if err!=nil{
  49.         return err
  50.     }
  51.     //当前主机为Master则更新心跳.或Master已down则抢Master
  52.     if hostMaster.Master==curHost || time.Now().Sub(*hostMaster.UpdateTime).Seconds()>healthTimeout{
  53.         ret := DB.Model(&HostMaster{}).Where("version = ?",hostMaster.Version).Updates(map[string]interface{}{"master":curHost,"version":hostMaster.Version+1})
  54.         if ret.Error!=nil{
  55.             return errors.New("修改失败: "+ret.Error.Error())
  56.         }
  57.         if ret.RowsAffected==0{
  58.             return nil
  59.         }else{
  60.             if hostMaster.Master==curHost{
  61.                 fmt.Println(curHost+"更新了心跳")
  62.             }else{
  63.                 fmt.Println(curHost+"抢Master成功")
  64.             }
  65.         }
  66.     }
  67.     return nil
  68. }
  69. func main() {
  70.     //初始化数据库
  71.     err := InitDB()
  72.     if err!=nil{
  73.         fmt.Println(err)
  74.         os.Exit(1)
  75.     }
  76.     //周期性更新心跳和抢Master
  77.     go func(){
  78.         for{
  79.             err := GrabMaster()
  80.             if err!=nil{
  81.                 fmt.Println(err)
  82.             }
  83.             time.Sleep(10*time.Second)
  84.         }
  85.     }()
  86.     select {}
  87. }
复制代码



郭少

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4