Golang負(fù)載均衡和?;钤O(shè)計(jì)原理示例探究
引言
通過(guò)本項(xiàng)目可以學(xué)到什么?
負(fù)載均衡算法代碼實(shí)現(xiàn)
調(diào)度器如何維護(hù)節(jié)點(diǎn)Live方案(參考)
loadbalance 負(fù)載均衡算法
隨機(jī)算法,輪詢算法,加權(quán)輪詢算法
隨機(jī)算法
// 隨機(jī) type Rand struct { addrs []string } func (r *Rand) Add(param []string) error { iflen(param) != 1 { return ErrParam } r.addrs = append(r.addrs, param[0]) returnnil } // 隨機(jī)種子,每次隨機(jī)返回一個(gè) func (r *Rand) Get() (string, error) { iflen(r.addrs) == 0 { return"", ErrNoAddr } rand.Seed(time.Now().UnixNano()) idx := rand.Intn(len(r.addrs)) return r.addrs[idx], nil }
輪詢算法
// 輪詢 type RoundRobin struct { addrs []string curIdx int } func (r *RoundRobin) Add(param []string) error { iflen(param) != 1 { return ErrParam } r.addrs = append(r.addrs, param[0]) returnnil } func (r *RoundRobin) Get() (string, error) { iflen(r.addrs) == 0 || r.curIdx >= len(r.addrs) { return"", ErrNoAddr } addr := r.addrs[r.curIdx] r.curIdx = (r.curIdx + 1) % len(r.addrs) // 對(duì)curIdx每次+1 return addr, nil }
加權(quán)輪詢算法
實(shí)現(xiàn)原理
對(duì)節(jié)點(diǎn)設(shè)置權(quán)重,權(quán)重越大被選中次數(shù)越高,節(jié)點(diǎn)被選中的次數(shù)≈(本節(jié)點(diǎn)權(quán)重/全部權(quán)重) * 總次數(shù)。
舉例說(shuō)明:
節(jié)點(diǎn)權(quán)重為:weight [a=1,b=2,c=5]
節(jié)點(diǎn)當(dāng)前權(quán)重為curWeight:初始值為[a=0,b=0,c=0],變化規(guī)則為:curWeight + weight
全部權(quán)重sumWeight: 代表所有節(jié)點(diǎn)初始權(quán)重之和 1+2+5=8
第一次請(qǐng)求:
curWeight 為 [a=0+1,b=0+2,c=0+5] ,選中最大的c做為本次輸出,之后c節(jié)點(diǎn)的權(quán)重需要減去sumWeight,調(diào)整后 [a=1,b=2,c=5-8] 也就是 [a=1,b=2,c=-3]
第二次請(qǐng)求:
curWeight 為 [a=1+1,b=2+2,c=-3+5] 結(jié)果為 [a=2,b=4,c=2],選中最大的b作為本次輸出,之后節(jié)點(diǎn)權(quán)重變更為 [a=2,b=-4,c=2]
第三次請(qǐng)求:
curWeight 為 [a=2+1,b=-4+2,c=2+5] 結(jié)果為 [a=3,b=-2,c=7],又輪到c(權(quán)重大的好處體現(xiàn)出來(lái)了),之后節(jié)點(diǎn)權(quán)重變更為 [a=3,b=-2,c=-1]
第四次請(qǐng)求:
[a=3,b=-2,c=-1] 加權(quán)后[a=4,b=0,c=4],a與c相等,優(yōu)先選前者輸出a
type WeigthRoundRobin struct { weightAddrs []*weightAddr } type weightAddr struct { addr string// 地址 weight int// 權(quán)重 curWeight int// 計(jì)算使用 } func (w *WeigthRoundRobin) Add(param []string) error { iflen(param) != 2 { return ErrParam } weight, err := strconv.Atoi(param[1]) if err != nil { return err } w.weightAddrs = append(w.weightAddrs, &weightAddr{ addr: param[0], weight: weight, curWeight: 0, }) returnnil } func (w *WeigthRoundRobin) Get() (string, error) { iflen(w.weightAddrs) == 0 { return"", ErrNoAddr } maxWeight := math.MinInt idx := 0 sumWeight := 0// 權(quán)重總和 for k, weightAddr := range w.weightAddrs { sumWeight += weightAddr.weight // 權(quán)重總和 weightAddr.curWeight += weightAddr.weight // 加上權(quán)重 if weightAddr.curWeight > maxWeight { // 記錄最大值 maxWeight = weightAddr.curWeight idx = k } } w.weightAddrs[idx].curWeight -= sumWeight // 減去權(quán)重總和 return w.weightAddrs[idx].addr, nil// 返回最大權(quán)重的結(jié)果 }
有效服務(wù)維護(hù)方案(參考)
方案一:heart【心跳】
前置配置:
1.啟動(dòng)docker
docker-compose -f docker-compose-env.yml up -d zookeeper docker-compose -f docker-compose-env.yml up -d kafka
2.修改本地hostsvim /etc/hosts
增加 127.0.0.1 kafka
3.kafka常用腳本【可選】 [進(jìn)入docker中*.sh位于 /opt/kafka/bin目錄](méi)
# 創(chuàng)建topic ./kafka-topics.sh --create --zookeeper zookeeper:2181 --replication-factor 1 --partitions 3 --topic easy_topic # 列出所有topic ./kafka-topics.sh --list --zookeeper zookeeper:2181 # 從頭開始消費(fèi) ./kafka-console-consumer.sh --bootstrap-server kafka:9092 --from-beginning --topic easy_topic # 消費(fèi)組【從最新的消息消費(fèi)】 ./kafka-console-consumer.sh --bootstrap-server kafka:9092 --consumer-property group.id=testGroup --topic easy_topic # 從最新開始消費(fèi) ./kafka-console-consumer.sh --bootstrap-server kafka:9092 --topic easy_topic # 生產(chǎn)消息 ./kafka-console-producer.sh --broker-list kafka:9092 --topic easy_topic
調(diào)度器訂閱kafka消息,同時(shí)維護(hù)一個(gè)有效服務(wù),然后按照負(fù)載均衡策略分發(fā)請(qǐng)求。
func main() { // 服務(wù)負(fù)責(zé)發(fā)送心跳 go heart.RunHeartBeat() // 調(diào)度器負(fù)責(zé)接收心跳 go heart.ListenHeartbeat() // 利用負(fù)載均衡獲取 lb := loadbalance.LoadBalanceFactory(loadbalance.BalanceTypeRand) gofunc() { for { time.Sleep(5 * time.Second) for _, v := range heart.GetAddrList() { lb.Add([]string{v}) } fmt.Println(lb.Get()) } }() sigusr1 := make(chan os.Signal, 1) signal.Notify(sigusr1, syscall.SIGTERM) <-sigusr1 }
方案二:health【健康檢查】
通過(guò)HTTP請(qǐng)求服務(wù),維護(hù)活躍節(jié)點(diǎn)
func main() { health.AddAddr("https://www.sina.com.cn/", "https://www.baidu.com/", "http://www.aajklsdfjklsd") go health.HealthCheck() time.Sleep(50 * time.Second) alist := health.GetAliveAddrList() for i := 0; i < len(alist); i++ { fmt.Println(alist[i]) } var block = make(chanbool) <-block }
以上就是Golang負(fù)載均衡和保活設(shè)計(jì)原理示例探究的詳細(xì)內(nèi)容,更多關(guān)于Golang負(fù)載均衡?;钤O(shè)計(jì)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解讀unsafe.Pointer和uintptr的區(qū)別
這篇文章主要介紹了解讀unsafe.Pointer和uintptr的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02go語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之前綴樹Trie
這篇文章主要介紹了go語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之前綴樹Trie,文章圍繞主題展開詳細(xì)內(nèi)容介紹,具有一定得參考價(jià)值,需要的小伙伴可以參考一下2022-05-05一文掌握Go語(yǔ)言并發(fā)編程必備的Mutex互斥鎖
Go 語(yǔ)言提供了 sync 包,其中包括 Mutex 互斥鎖、RWMutex 讀寫鎖等同步機(jī)制,本篇博客將著重介紹 Mutex 互斥鎖的基本原理,需要的可以參考一下2023-04-04golang 監(jiān)聽服務(wù)的信號(hào),實(shí)現(xiàn)平滑啟動(dòng),linux信號(hào)說(shuō)明詳解
這篇文章主要介紹了golang 監(jiān)聽服務(wù)的信號(hào),實(shí)現(xiàn)平滑啟動(dòng),linux信號(hào)說(shuō)明詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-05-05Golang 錯(cuò)誤捕獲Panic與Recover的使用
對(duì)于Go語(yǔ)言的錯(cuò)誤是通過(guò)返回值的方式,本文主要介紹了Golang 錯(cuò)誤捕獲Panic與Recover的使用,文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03golang簡(jiǎn)易令牌桶算法實(shí)現(xiàn)代碼
這篇文章主要介紹了golang簡(jiǎn)易令牌桶算法實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04Go切片擴(kuò)容機(jī)制詳細(xì)說(shuō)明和舉例
Go 語(yǔ)言中的切片是一種動(dòng)態(tài)數(shù)組,它可以自動(dòng)擴(kuò)容和縮容以適應(yīng)不同的數(shù)據(jù)量,這篇文章主要給大家介紹了關(guān)于Go切片擴(kuò)容機(jī)制詳細(xì)說(shuō)明和舉例的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03Golang?WorkerPool線程池并發(fā)模式示例詳解
這篇文章主要為大家介紹了Golang?WorkerPool線程池并發(fā)模式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08