網站首頁 編程語言 正文
一、背景
本文描述的是客戶端接收心跳信息的超時實現。心跳超時,或者接受信息超過限定時間在分布式系統中出現的次數比較多。常見的就有hadoop中節點超時,或者日志中出現timeout的字樣。
在學習go語言中,我也根據go語言的機制實現了心跳超時的這個問題。踩過坑,趟過水。
二、心跳超時的實現
2.1 通過select case (設計概念比較多)
這種方法實現心跳,需要對go語言中的channel和select case 機制有所了解。select代碼段中沒有包含default條件時,會一直阻塞到有通道操作。
需要注意的是!!!! select語言只會阻塞一次,且執行一次。如果需要多次判斷,或者可能有多個case條件需要滿足,那就需要增加for語句。
首先需要知道的是select是專為channel設計的,所以說每個case表達式都必須是包含操作通道的表達式。下面這段代碼是描述了隨機抽取一個channel發消息,正常情況下,不會觸發超時。為了觸發超時,注釋掉通道發送數據操作。超時五秒,則觸發超時。
package main import ( "fmt" "math/rand" "time" ) func main() { // 準備好三個通道。 intChannels := [3]chan int{ make(chan int, 1), make(chan int, 1), make(chan int, 1), } // 隨機選擇一個通道,并向它發送元素值。 index := rand.Intn(3) fmt.Printf("The index: %d\n", index) //?? 取消這行代碼的注視,超時條件的選擇就會觸發。 //intChannels[index] <- index // 哪一個通道中有可取的元素值,哪個對應的分支就會被執行。 select { case <-intChannels[0]: fmt.Println("The first candidate case is selected.") case <-intChannels[1]: fmt.Println("The second candidate case is selected.") case elem := <-intChannels[2]: fmt.Printf("The third candidate case is selected, the element is %d.\n", elem) case <-time.After(5 * time.Second): fmt.Println("timed out") } }
2.2 通過time.sleep(簡單有效)
通過time.sleep()實現超時操作,是比較巧妙的。一般來說心跳超時是一個雙方交互的行為。
下面畫一個圖來描述一下。
?為了方便理解,定義雙方都使用共同時間。
下面是代碼。
基本的邏輯是:
? ? ? ? 1、先給客戶端設置一個下次超時的時間
? ? ? ? ?2、客戶端每次收到心跳的時候,更新這個時間
? ? ? ? ?3、開啟一個獨立的線程,一致判斷當前客戶端是否超時。
ps:結合時效和性能,可以間隔一定的時間來進行判斷。
package main import ( "fmt" "sync" "time" ) type Client struct { lock sync.Mutex //加鎖 nextTimeOutTime time.Time //下次超時時間 } const tenSec = 10 /** 刷新每次的心跳超時機制 */ func (client *Client) freshTimeOutTime() { client.lock.Lock() defer client.lock.Unlock() client.nextTimeOutTime =time.Now().Add(tenSec*time.Second) } //開啟一個gp,每隔500ms判斷有沒有超時 func (client *Client) judgeTimeOut() { for { time.Sleep(500*time.Millisecond) fmt.Printf("%v 在判斷是否超時\n", client.nextTimeOutTime) if time.Now().After(client.nextTimeOutTime) { fmt.Printf("%v 超時了\n", client.nextTimeOutTime) } } } //客戶端收到以后,修改下次心跳超時時間 func (client *Client) receiveHeart() { client.freshTimeOutTime() } //開啟一個模擬ping 客戶端的線程 func pingClient(client *Client) { for true { time.Sleep(11*time.Second) fmt.Printf("%v 請求發送時間\n", time.Now()) client.receiveHeart() } } func main() { client := Client{ lock: sync.Mutex{}, nextTimeOutTime: time.Time{}, } //在當前時刻,更新下次的超時時刻是10s中后 client.freshTimeOutTime() go pingClient(&client) go client.judgeTimeOut() for true { } }
三、個人的實現觀感
使用select case 和 time.sleep實現超時的最大區別在于,time.sleep沒有太多的?語言相關的語法和知識,更容易理解和掌握。相對于channel來說,掌握需要了解channel的基本使用方法,一些常見的特性等。
原文鏈接:https://blog.csdn.net/alike_u/article/details/123763980
相關推薦
- 2022-03-16 Linux系統中日志詳細介紹_Linux
- 2022-12-19 教你react中如何理解usestate、useEffect副作用、useRef標識和useCont
- 2022-05-29 Linux上使用Docker部署ASP.NET?Core應用程序_實用技巧
- 2022-04-19 C語言位段(位域)機制結構體的特殊實現及解析_C 語言
- 2023-01-05 基于Go語言實現冒泡排序算法_Golang
- 2022-11-30 Python利用裝飾器click處理解析命令行參數_python
- 2022-04-17 將本地jar放到pom中被maven管理
- 2022-08-17 C語言堆結構處理TopK問題詳解_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支