Golang基于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分布式锁实现集群主备的更多相关文章
- KingbaseES R3 集群主备切换信号量(semctl)错误故障分析案例
案例说明: 某项目KingbaseES R3 一主一备流复制集群在主备切换测试中出现故障,导致主备无法正常切换:由于bm要求,数据库相关日志无法从主机中获取,只能在现场进行分析:通过对比主备切换时的时 ...
- Redis集群主备模式部署
网上有非常多用Ruby安装Redis-cluster的文章.可是在实际环境下不想安装Ruby,所以本文主要介绍了用Redis命令部署Redis集群.而且为集群中每个master实例添加一个slave实 ...
- Centos7.6部署k8s v1.16.4高可用集群(主备模式)
一.部署环境 主机列表: 主机名 Centos版本 ip docker version flannel version Keepalived version 主机配置 备注 master01 7.6. ...
- 利用redis 分布式锁 解决集群环境下多次定时任务执行
定时任务: @Scheduled(cron= "0 39 3 * * *") public void getAllUnSignData(){ //检查任务锁,若其它节点的相同定时任 ...
- Mysql基于Mysql Cluster+MysqlRouter的集群部署方案
http://note.youdao.com/noteshare?id=a61c4a6ff2b76e5305430eb66eb116e2&sub=4B4B6E8D0E2849F9B0DFB67 ...
- (转)基于keepalived搭建MySQL的高可用集群
基于keepalived搭建MySQL的高可用集群 原文:http://www.cnblogs.com/ivictor/p/5522383.html MySQL的高可用方案一般有如下几种: keep ...
- 【原】基于 HAproxy 1.6.3 Keeplived 在 Centos 7 中实现mysql mariadb galera cluster 集群分发读写 —— 上篇
前言 有一段时间没有写blogs,乘着周末开始整理下haproxy + keeplived 实现 mysql mariadb galera cluster 集群访问环境的搭建工作. 本文集中讲hapr ...
- 1 构建Mysql+heartbeat+DRBD+LVS集群应用系统系列之DRBD的搭建
preface 近来公司利润上升,购买了10几台服务器,趁此机会,把mysql的主从同步的架构进一步扩展,为了适应日益增长的流量.针对mysql架构的扩展,先是咨询前辈,后和同事探讨,准备采用Mysq ...
- 【分布式锁的演化】“超卖场景”,MySQL分布式锁篇
前言 之前的文章中通过电商场景中秒杀的例子和大家分享了单体架构中锁的使用方式,但是现在很多应用系统都是相当庞大的,很多应用系统都是微服务的架构体系,那么在这种跨jvm的场景下,我们又该如何去解决并发. ...
- Ubuntu16.04.1上搭建分布式的Redis集群
为什么要集群: 通常为了,提高网站的响应速度,总是把一些经常用到的数据放到内存中,而不是放到数据库中,Redis是一个很好的Cache工具,当然了还有Memcached,这里只讲Redis.在我们的电 ...
随机推荐
- 02 python爬虫-bs4
目录 步骤 代码 结果 new.csv 图片 步骤 爬取主页面中的文章详情的url和图片地址 下载图片 并请求加文章详情中的页面内容 爬取文章详情中的标题.作者.发布时间 代码 import requ ...
- 什么是NASM
什么是NASM NASM是一个汇编器的名称,全称是Netwide Assembler,支持x86与x64架构的CPU(注意不支持ARM架构). 我们知道,在x86和x64架构上有多个操作系统,比较流行 ...
- go高并发之路——go语言如何解决并发问题
一.选择GO的原因 作为一个后端开发,日常工作中接触最多的两门语言就是PHP和GO了.无可否认,PHP确实是最好的语言(手动狗头哈哈),写起来真的很舒爽,没有任何心智负担,字符串和整型压根就不用区分, ...
- 京东面试:SpringBoot同时可以处理多少请求?
Spring Boot 作为 Java 开发中必备的框架,它为开发者提供了高效且易用的开发工具,所以和它相关的面试题自然也很重要,咱们今天就来看这道经典的面试题:SpringBoot同时可以处理多少个 ...
- asp.net core api 3.1 dynamic 入参转json对象
比如接口 public object GetList(dynamic obj){ //var jElement=(JsonElement)obj;//使用system.text.json处理 var ...
- mysql忘记密码找回的方法
mysql忘记密码找回的方法: 在找回之前需要对 --skip-networking 参数进行了解 --skip-grant-tables: 关闭mysql验证模块 同时还需要关闭远程连接(避免他人连 ...
- Qt一键部署配置(Qt程序打包)
Qt一键部署配置(Qt程序打包) 1.版本 系统版本:windows10 Qt版本:5.15.2 2.设置可执行程序输出路径 打开.pro文件,输入DESTDIR = $$PWD/../bin,这 ...
- OpenCV笔记(7) 轮廓
1. 查找轮廓 FindContours public static void FindContours(InputOutputArray image, //输入8-bit单通道的图片 out Mat ...
- 穿透 wsl 和 ssh, 新版本 neovim 跨设备任意复制,copy anywhere!
获得更好的阅读体验,欢迎查看原文:穿透 wsl 和 ssh, 新版本 neovim 跨设备任意复制,copy anywhere! 1. 创作动机 最近一个星期,我入坑了 neovim, 然后开始配置各 ...
- 头条abogus与Js补环境代理Upgrade!
声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关,若有侵权,请联系我立即删除! 目标网站 aHR0cHM6 ...