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. 2.RabbitMQ 的可靠性消息的发送

      本篇包含 1. RabbitMQ 的可靠性消息的发送 2. RabbitMQ 集群的原理与高可用架构的搭建 3. RabbitMQ 的实践经验   上篇包含 1.MQ 的本质,MQ 的作用 2.R ...

  2. get merge --no-ff和git merge区别、git fetch和git pull的区别

    get merge --no-ff和git merge区别 git merge -–no-ff可以保存你之前的分支历史.能够更好的查看 merge历史,以及branch 状态. git merge则不 ...

  3. 论文笔记 XGBoost: A Scalable Tree Boosting System

    XGBoost是boosting算法的其中一种.Boosting算法的思想是将许多弱分类器集成在一起形成一个强分类器,其更关注与降低基模型的偏差.XGBoost是一种提升树模型(Gradient bo ...

  4. Java性能优化学习笔记

    1. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面: 第一,控制资源的使用,通过线程同步来控 ...

  5. 用PHP写PHP7扩展,超级简单对吧!

    [图片打不开,请用代理] 介绍: PHP扩展是编译库,它允许在您的PHP代码中使用特定的功能(主要是使用C编写的php扩展). 例如,您需要使用PHP使用SQLite3,您可以实现自己的方法和功能来连 ...

  6. iOS学习之字符串(NSString)的截取、匹配、分隔

    截取 NSString *str1 = @"this is zero"; 1.从第三个字符开始,截取长度为2的字符串.........注:空格算作一个字符 NSString *st ...

  7. UIAlertController 修改文字显示实现方法

    UIAlertController修改文字显示 不废话先上完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 UIAlertControll ...

  8. C语言的三套标准 C89(C90)、C99、C11

    C语言最初由 Dennis Ritchie 于 1969 年到 1973 年在 AT&T 贝尔实验室里开发出来,主要用于重新实现 Unix 操作系统.此时,C语言又被称为 K&R C. ...

  9. 模块之 time datetime random json pickle os sys hashlib collections

    目录 1. time模块 1.1表示时间的几种方式: 1.2格式化字符串的时间格式 1.3不同格式时间的转换 2.datetim模块 3.random模块 4. json模块 4.1dumps.loa ...

  10. 手写一个简易版Tomcat

    前言 Tomcat Write MyTomcat Tomcat是非常流行的Web Server,它还是一个满足Servlet规范的容器.那么想一想,Tomcat和我们的Web应用是什么关系? 从感性上 ...