背景

集群中如果需要主备,可以基于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分布式锁实现集群主备的更多相关文章

  1. KingbaseES R3 集群主备切换信号量(semctl)错误故障分析案例

    案例说明: 某项目KingbaseES R3 一主一备流复制集群在主备切换测试中出现故障,导致主备无法正常切换:由于bm要求,数据库相关日志无法从主机中获取,只能在现场进行分析:通过对比主备切换时的时 ...

  2. Redis集群主备模式部署

    网上有非常多用Ruby安装Redis-cluster的文章.可是在实际环境下不想安装Ruby,所以本文主要介绍了用Redis命令部署Redis集群.而且为集群中每个master实例添加一个slave实 ...

  3. Centos7.6部署k8s v1.16.4高可用集群(主备模式)

    一.部署环境 主机列表: 主机名 Centos版本 ip docker version flannel version Keepalived version 主机配置 备注 master01 7.6. ...

  4. 利用redis 分布式锁 解决集群环境下多次定时任务执行

    定时任务: @Scheduled(cron= "0 39 3 * * *") public void getAllUnSignData(){ //检查任务锁,若其它节点的相同定时任 ...

  5. Mysql基于Mysql Cluster+MysqlRouter的集群部署方案

    http://note.youdao.com/noteshare?id=a61c4a6ff2b76e5305430eb66eb116e2&sub=4B4B6E8D0E2849F9B0DFB67 ...

  6. (转)基于keepalived搭建MySQL的高可用集群

    基于keepalived搭建MySQL的高可用集群  原文:http://www.cnblogs.com/ivictor/p/5522383.html MySQL的高可用方案一般有如下几种: keep ...

  7. 【原】基于 HAproxy 1.6.3 Keeplived 在 Centos 7 中实现mysql mariadb galera cluster 集群分发读写 —— 上篇

    前言 有一段时间没有写blogs,乘着周末开始整理下haproxy + keeplived 实现 mysql mariadb galera cluster 集群访问环境的搭建工作. 本文集中讲hapr ...

  8. 1 构建Mysql+heartbeat+DRBD+LVS集群应用系统系列之DRBD的搭建

    preface 近来公司利润上升,购买了10几台服务器,趁此机会,把mysql的主从同步的架构进一步扩展,为了适应日益增长的流量.针对mysql架构的扩展,先是咨询前辈,后和同事探讨,准备采用Mysq ...

  9. 【分布式锁的演化】“超卖场景”,MySQL分布式锁篇

    前言 之前的文章中通过电商场景中秒杀的例子和大家分享了单体架构中锁的使用方式,但是现在很多应用系统都是相当庞大的,很多应用系统都是微服务的架构体系,那么在这种跨jvm的场景下,我们又该如何去解决并发. ...

  10. Ubuntu16.04.1上搭建分布式的Redis集群

    为什么要集群: 通常为了,提高网站的响应速度,总是把一些经常用到的数据放到内存中,而不是放到数据库中,Redis是一个很好的Cache工具,当然了还有Memcached,这里只讲Redis.在我们的电 ...

随机推荐

  1. dotnet 6 使用 HttpWebRequest 进行 POST 文件将占用大量内存

    我有用户给我报告一个内存不足的问题,经过了调查,找到了依然是使用已经被标记过时的 HttpWebRequest 进行文件推送,推送过程中,由于 System.Net.RequestStream 将会完 ...

  2. h5开发,原生开发,混合开发

    这里做一点对h5开发,原生开发,混合开发的笔记,记一点更新一点: 一.h5开发:html,css和js编写页面和业务逻辑. 1..页面栈上,h5通过history来管理回退或者前进.vue通过配置路由 ...

  3. Ollama开发指南

    安装必备工具 确保已安装以下软件的正确版本: CMake 3.24 或更高版本 Go 1.22 或更高版本 GCC 11.4.0 或更高版本 使用 Homebrew 安装这些工具(适用于macOS和L ...

  4. 在鼠标右键菜单中新增新建Markdown文件选项(VSCode)

    引言 正常情况下,我们新建md文件有两种方式:一是通过Markdown编辑器新建,二是新建txt文件再修改后缀. 但是在Windows系统中,我们可以通过修改注册表来新增右键菜单选项.这里我们可以通过 ...

  5. Selenium4自动化测试2--元素定位By.ID,By.CLASS_NAME,By.TAG_NAME

    三.元素定位方式 1-通过id定位,By.ID id属性在HTML中是唯一的,因此使用id定位可以确保找到页面上唯一的元素. 由于id是唯一的,浏览器在查找元素时可以快速定位到目标元素,提高了定位的效 ...

  6. postgresql 开启审计日志

    1.审计清单说明 logging_collector     --是否开启日志收集开关,默认off,推荐on log_destination       --日志记录类型,默认是stderr,只记录错 ...

  7. Chrome 浏览器插件 V3 版本 Manifest.json 文件中 Action 的类型(Types)、方法(Methods)和事件(Events)的属性和参数解析

    一.类型(Types) 一.OpenPopupOptions 1. 属性 windowId: number 可选 打开操作弹出式窗口的窗口 ID.如果未指定,则默认为当前活动窗口. 二.TabDeta ...

  8. 网络安全—PKI公钥基础设施

    文章目录 前提知识 散列函数 非对称加密 数字签名 PKI 受信任的人 RA注册 CA颁发 IKE数字签名认证(交换证书) 密钥管理 前提知识 散列函数 散列也可以叫哈希函数,MD5.SHA-1.SH ...

  9. C语言:将字符逆反排列再输出的问题

    代码: #include<stdio.h> #define N 10 int main() { /*输入字符串,str[10],将里面的字符逆反排列,再输出.*/ char ch[N]; ...

  10. Android 13 - Media框架(8)- MediaExtractor(2)

    关注公众号免费阅读全文,进入音视频开发技术分享群! 上一篇 MediaExtractor 笔记中我们学习了 extractor 以及 source 调用的层次结构,这一节我们会看一看部分的实现细节. ...