package util

import (
"fmt"
"hash/crc32"
"math/rand"
"sort"
"time"
) type HttpServer struct { //目标server类
Host string
Weight int
CWeight int //当前权重
Status string //健康检查
FailCount int //计数器,默认是0
SuccessCount int //检查到连续成功,当连续成功的次数达到这个值,把宕机的的机器的FailCount立刻重置为0,加快服务器启动速度
} type HttpServers []*HttpServer func (p HttpServers) Len() int { return len(p) }
func (p HttpServers) Less(i, j int) bool { return p[i].CWeight > p[j].CWeight }
func (p HttpServers) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func NewHttpServer(host string, weight int) *HttpServer {
return &HttpServer{Host: host, Weight: weight, CWeight: 0}
} type LoadBalance struct { //负载均衡类
Servers HttpServers
CurIndex int //指向当前访问的服务器
} func NewLoadBalance() *LoadBalance {
return &LoadBalance{Servers: make([]*HttpServer, 0)}
} func (this *LoadBalance) AddServer(server *HttpServer) {
this.Servers = append(this.Servers, server)
} func (this *LoadBalance) SelectForRand() *HttpServer {
rand.Seed(time.Now().UnixNano())
index := rand.Intn(len(this.Servers))
fmt.Println(index)
return this.Servers[index]
} func (this *LoadBalance) SelectByIpHash(ip string) *HttpServer {
index := int(crc32.ChecksumIEEE([]byte(ip))) % len(this.Servers) //通过取余永远index都不会大于this.servers的长度
return this.Servers[index]
} func (this *LoadBalance) SelectByWeight(ip string) *HttpServer { //加权随机算法
rand.Seed(time.Now().UnixNano())
index := rand.Intn(len(ServerIndices)) //这里因为权重表为15个1和5个0组成,所以产生0到19的随机数
fmt.Println(this.Servers[ServerIndices[index]])
return this.Servers[ServerIndices[index]] //通过随机数的索引获得服务器索引进而获得地址
} func (this *LoadBalance) SelectByWeightBetter(ip string) *HttpServer {
rand.Seed(time.Now().UnixNano())
sumList := make([]int, len(this.Servers))
sum := 0
for i := 0; i < len(this.Servers); i++ {
sum += this.Servers[i].Weight
sumList[i] = sum }
_rand := rand.Intn(sum)
for index, value := range sumList {
if _rand < value {
return this.Servers[index]
}
}
return this.Servers[0]
} func (this *LoadBalance) RoundRobin() *HttpServer {
server := this.Servers[this.CurIndex]
//this.CurIndex ++
//if this.CurIndex >= len(this.Servers) {
// this.CurIndex = 0
//}
this.CurIndex = (this.CurIndex + 1) % len(this.Servers)
if server.Status == "Down" { //如果当前节点宕机了,则递归查找可以用的服务器
return this.RoundRobin()
}
return server
} func (this *LoadBalance) RoundRobinByWeight() *HttpServer {
server := this.Servers[ServerIndices[this.CurIndex]]
this.CurIndex = (this.CurIndex + 1) % len(ServerIndices)
return server
} func (this *LoadBalance) RoundRobinByWeight2() *HttpServer { //加权轮询 ,使用区间算法
server := this.Servers[0]
sum := 0
//3:1:1
for i := 0; i < len(this.Servers); i++ {
sum += this.Servers[i].Weight //第一次是3 [0,3) [3,4) [4,5)
if this.CurIndex < sum {
server = this.Servers[i]
if this.CurIndex == sum-1 && i != len(this.Servers)-1 {
this.CurIndex++
} else {
this.CurIndex = (this.CurIndex + 1) % sum //这里是重要的一步
}
fmt.Println(this.CurIndex)
break
}
}
return server
} func (this *LoadBalance) RoundRobinByWeight3() *HttpServer { //平滑加权轮询
for _, s := range this.Servers {
s.CWeight = s.CWeight + s.Weight
}
sort.Sort(this.Servers)
max := this.Servers[0] max.CWeight = max.CWeight - SumWeight
return max
} var LB *LoadBalance
var ServerIndices []int
var SumWeight int func checkServers(servers HttpServers) {
t:= time.NewTicker(time.Second*3)
check:=NewHtttpChecker(servers)
for {
select{
case <- t.C:
check.Check(time.Second*2)
for _,s:=range servers{
fmt.Println(s.Host,s.Status,s.FailCount)
}
fmt.Println("---------------------------------")
}
}
} func init() {
LB = NewLoadBalance()
LB.AddServer(NewHttpServer("http://localhost:12346", 3)) //web1
LB.AddServer(NewHttpServer("http://localhost:12347", 1)) //web2
LB.AddServer(NewHttpServer("http://localhost:12348", 1)) //web2
for index, server := range LB.Servers {
if server.Weight > 0 {
for i := 0; i < server.Weight; i++ {
ServerIndices = append(ServerIndices, index)
}
}
SumWeight = SumWeight + server.Weight //计算加权总和
}
go checkServers(LB.Servers) //fmt.Println(ServerIndices)
}
package util

import (
"net/http"
"time"
) type HttpChecker struct {
Servers HttpServers
FailMax int
RecovCount int //连续成功到达这个值,就会被标识为UP
} func NewHtttpChecker(servers HttpServers) *HttpChecker {
return &HttpChecker{Servers: servers, FailMax: 6, RecovCount: 3}
}
func (this *HttpChecker) Check(timeout time.Duration) {
client := http.Client{}
for _, server := range this.Servers {
res, err := client.Head(server.Host)
if res != nil {
defer res.Body.Close()
}
if err != nil { //宕机了
this.Fail(server)
continue
}
if res.StatusCode >= 200 && res.StatusCode < 400 {
this.Success(server)
} else {
this.Fail(server)
}
}
} func (this *HttpChecker) Fail(server *HttpServer) {
if server.FailCount >= this.FailMax { //超过阈值
server.Status = "DOWN"
} else {
server.FailCount++
}
server.SuccessCount = 0 } func (this *HttpChecker) Success(server *HttpServer) {
if server.FailCount > 0 {
server.FailCount--
server.SuccessCount++
if server.SuccessCount == this.RecovCount {
server.FailCount = 0
server.Status = "UP"
server.SuccessCount = 0
}
} else {
server.Status = "UP"
} }

FailOver的机制的更多相关文章

  1. MySQL Proxy和 Amoeba 工作机制浅析

    MySQL Proxy处于客户端应用程序和MySQL服务器之间,通过截断.改变并转发客户端和后端数据库之间的通信来实现其功能,这和WinGate 之类的网络代理服务器的基本思想是一样的.代理服务器是和 ...

  2. Hadoop学习笔记—15.HBase框架学习(基础知识篇)

    HBase是Apache Hadoop的数据库,能够对大型数据提供随机.实时的读写访问.HBase的目标是存储并处理大型的数据.HBase是一个开源的,分布式的,多版本的,面向列的存储模型,它存储的是 ...

  3. Thrift 个人实战--Thrift 服务化 Client的改造

    前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还 ...

  4. HBase replication

    Hbase Replication 介绍 现状 Hbase 的replication目前在业界使用并不多见,原因有很多方面,比如说HDFS目前已经有多份备份在某种程度上帮助HBASE底层数据的安全性, ...

  5. Apache-Flink深度解析-State

    摘要: 实际问题 在流计算场景中,数据会源源不断的流入Apache Flink系统,每条数据进入Apache Flink系统都会触发计算.如果我们想进行一个Count聚合计算,那么每次触发计算是将历史 ...

  6. Mysql读写分离方案-Amoeba环境部署记录

    Mysql的读写分离可以使用MySQL Proxy,也可以使用Amoeba.Amoeba(变形虫)项目是一个类似MySQL Proxy的分布式数据库中间代理层软件,是由陈思儒开发的一个开源的java项 ...

  7. Others-阿里专家强琦:流式计算的系统设计和实现

    阿里专家强琦:流式计算的系统设计和实现 更多深度文章,请关注云计算频道:https://yq.aliyun.com/cloud 阿里云数据事业部强琦为大家带来题为“流式计算的系统设计与实现”的演讲,本 ...

  8. MongoDB 走马观花(全面解读篇)

    目录 一.简介 二.基本模型 BSON 数据类型 分布式ID 三.操作语法 四.索引 索引特性 索引分类 索引评估.调优 五.集群 分片机制 副本集 六.事务与一致性 一致性 小结 一.简介 Mong ...

  9. 了解 MongoDB 看这一篇就够了【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

随机推荐

  1. Selenium自动化获取WebSocket信息

    性能日志 ChromeDriver支持性能日志记录,您可以从中获取域“时间轴”,“网络”和“页面”的事件,以及指定跟踪类别的跟踪数据. 启用性能日志 默认情况下不启用性能日志记录.因此,在创建新会话时 ...

  2. C++中的强制类型转换

    在C语言中,强制类型转换的方式为(Type)Expression,另外还有一种现在已经不用的旧式写法Type(Expression),这两种方式是等价的. 但是,C语言的强制类型转换方式存在一些问题: ...

  3. c++基础(四)—— 泛型算法

    1.find(first, last, value) 头文件:algorithm 参数:前两个参数是“表示元素范围的迭代器”,第三个是一个值 说明:find 将范围中进行寻找.搜索失败:如果范围中无匹 ...

  4. Harbor仓库配置https访问

    注:高版本(14以上)docker执行login命令,默认使用https,且harbor必须使用域名,只是用ip访问是不行的. 假设使用的网址是:www.harbor.mobi,本机ip是192.16 ...

  5. C# HtmlAgilityPack爬取静态页面

    最近对爬虫很感兴趣,稍微研究了一下,利用HtmlAgilityPack制作了一个十分简单的爬虫,这个简易爬虫只能获取静态页面的Html HtmlAgilityPack简介 HtmlAgilityPac ...

  6. 扩展JS

    //JS的扩展方法: 1 定义类静态方法扩展 2 定义类对象方法扩展            var aClass = function(){} //1 定义这个类的静态方法            aC ...

  7. 【洛谷 P2633】 Count on a tree(主席树,树上差分)

    题目链接 思维难度0 实现难度7 建出主席树后用两点的状态减去lca和lca父亲的状态,然后在新树上跑第\(k\)小 #include <cstdio> #include <cstr ...

  8. Vivado debug异常现象

    前言 bit文件和ltx文件的信号位宽不匹配问题.用了dont_touch等属性没用... WARNING: [Labtools 27-1972] Mismatch between the desig ...

  9. 实战FFmpeg--iOS平台使用FFmpeg将视频文件转换为YUV文件

    做播放器的开发这里面涉及的东西太多,我只能一步步往前走,慢慢深入.播放器播放视频采用的是渲染yuv文件.首先,要知道yuv文件是怎么转换得来的,其次,要知道怎么把视频文件保存为yuv文件.雷神的文章1 ...

  10. Python学习日记(二十一) 异常处理

    程序中异常的类型 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入^C) Exception 常规错误的基 ...