第三期:gRPC客戶端與服務(wù)端連接失敗后,是否會有重試機(jī)制恳不?

grpc 版本1.50

client.go 代碼:

func main() {
    flag.Parse()
    // Set up a connection to the server.
    conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewGreeterClient(conn)

    // Contact the server and print out its response.
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.GetMessage())
}

Dial 源碼:

func Dial(target string, opts ...DialOption) (*ClientConn, error) {
    return DialContext(context.Background(), target, opts...)
}

DialContext 源碼:

省略次部分代碼

// 首先會創(chuàng)建 ClientConn檩小,初始化相關(guān)字段
func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *ClientConn, err error) {
    cc := &ClientConn{
        target:            target,
        csMgr:             &connectivityStateManager{},
        conns:             make(map[*addrConn]struct{}),
        dopts:             defaultDialOptions(),
        blockingpicker:    newPickerWrapper(),
        czData:            new(channelzData),
        firstResolveEvent: grpcsync.NewEvent(),
    }

    // 將用戶設(shè)置的連接參數(shù)更新到客戶端連接器 ClientConn
    for _, opt := range opts {
        opt.apply(&cc.dopts)
    }

    return cc, nil
}

connect() 方法:

func (ac *addrConn) connect() error {
    ac.mu.Lock()
    // if 校驗狀態(tài)
    if ac.state == connectivity.Shutdown {
        ac.mu.Unlock()
        return errConnClosing
    }
    if ac.state != connectivity.Idle {
        ac.mu.Unlock()
        return nil
    }
    ac.updateConnectivityState(connectivity.Connecting, nil)
    ac.mu.Unlock()
    // 主要看這個方法,重試連接
    ac.resetTransport()
    return nil
}

進(jìn)入 resetTransport() 源碼

func (ac *addrConn) resetTransport() {
    ac.mu.Lock()
    // 判斷狀態(tài)若為 shutdown妆够,則不再連接直接推出
    if ac.state == connectivity.Shutdown {
        ac.mu.Unlock()
        return
    }

    addrs := ac.addrs
    // 連接失敗负蚊,需要進(jìn)行重試的
    // Backoff 是需要等待的時間姨伤,ac.backoffIdx表示第幾次重試
    backoffFor := ac.dopts.bs.Backoff(ac.backoffIdx)
    // 計算出本次向gRPC服務(wù)嘗試建立TCP連接的最長時間
    // 若超過這個時間還是連接不上,則主動斷開渠概,等待嘗試下次連接
    // This will be the duration that dial gets to finish.
    dialDuration := minConnectTimeout
    if ac.dopts.minConnectTimeout != nil {
        dialDuration = ac.dopts.minConnectTimeout()
    }

    if dialDuration < backoffFor {
        // Give dial more time as we keep failing to connect.
        dialDuration = backoffFor
    }
    connectDeadline := time.Now().Add(dialDuration)

    // 更新結(jié)構(gòu)addrConn狀態(tài)為connecting
    ac.updateConnectivityState(connectivity.Connecting, nil)
    ac.mu.Unlock()

    // 向服務(wù)器連接失敗后需要做的邏輯
    if err := ac.tryAllAddrs(addrs, connectDeadline); err != nil {
        ac.cc.resolveNow(resolver.ResolveNowOptions{})
        // After exhausting all addresses, the addrConn enters
        // TRANSIENT_FAILURE.
        ac.mu.Lock()
        if ac.state == connectivity.Shutdown {
            ac.mu.Unlock()
            return
        }
        ac.updateConnectivityState(connectivity.TransientFailure, err)

        // Backoff.
        b := ac.resetBackoff
        ac.mu.Unlock()

        // 定時的超時間
        timer := time.NewTimer(backoffFor)
        // 1.timer.C如果連接超時套耕,重試的次數(shù)+1,繼續(xù)下一次重試連接肴捉,但需要等待一段時間
        // 2. b,直接關(guān)閉,將繼續(xù)進(jìn)行重新連接
        // 2. ac.ctx.Done芝薇,走這里的話,上下文結(jié)束绣夺,這里不會再次重試了
        select {
        case <-timer.C:
            ac.mu.Lock()
            ac.backoffIdx++
            ac.mu.Unlock()
        case <-b:
            timer.Stop()
        case <-ac.ctx.Done():
            timer.Stop()
            return
        }

        ac.mu.Lock()
        // 狀態(tài) != shutdown就更新為空閑狀態(tài)
        if ac.state != connectivity.Shutdown {
            ac.updateConnectivityState(connectivity.Idle, err)
        }
        ac.mu.Unlock()
        return
    }
    // 連接成功,重新設(shè)置backoff為原始值0
    ac.mu.Lock()
    ac.backoffIdx = 0
    ac.mu.Unlock()
}

如何計算重試連接等待時間佃扼?

進(jìn)入Backoff方法


func (bc Exponential) Backoff(retries int) time.Duration {
    if retries == 0 {
        return bc.Config.BaseDelay
    }
    backoff, max := float64(bc.Config.BaseDelay), float64(bc.Config.MaxDelay)
    for backoff < max && retries > 0 {
        // 冪次方
        backoff *= bc.Config.Multiplier
        retries--
    }
    // 不能超過最大延時時間
    if backoff > max {
        backoff = max
    }
    // Randomize backoff delays so that if a cluster of requests start at
    // the same time, they won't operate in lockstep.
    backoff *= 1 + bc.Config.Jitter*(grpcrand.Float64()*2-1)
    if backoff < 0 {
        return 0
    }
    return time.Duration(backoff)
}

總結(jié):

  • 連接失敗后郁季,客戶端會進(jìn)行重試連接冗恨。
  • 重試次數(shù)越多,等待下一次連接時間也會變長尿招,但不能超過MaxDelay值。

更多Go云原生學(xué)習(xí)資料咖城,收錄于Github:https://github.com/metashops/GoFamily

本文由mdnice多平臺發(fā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末定枷,一起剝皮案震驚了整個濱河市荐虐,隨后出現(xiàn)的幾起案子晴圾,更是在濱河造成了極大的恐慌颂砸,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件死姚,死亡現(xiàn)場離奇詭異人乓,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)都毒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門色罚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人账劲,你說我怎么就攤上這事戳护〗鹇眨” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵姑尺,是天一觀的道長竟终。 經(jīng)常有香客問我,道長切蟋,這世上最難降的妖魔是什么统捶? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮柄粹,結(jié)果婚禮上喘鸟,老公的妹妹穿的比我還像新娘。我一直安慰自己驻右,他們只是感情好什黑,可當(dāng)我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堪夭,像睡著了一般愕把。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上森爽,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天恨豁,我揣著相機(jī)與錄音,去河邊找鬼爬迟。 笑死橘蜜,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的付呕。 我是一名探鬼主播计福,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼徽职!你這毒婦竟也來了象颖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤姆钉,失蹤者是張志新(化名)和其女友劉穎说订,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體育韩,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡克蚂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年闺鲸,在試婚紗的時候發(fā)現(xiàn)自己被綠了筋讨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡摸恍,死狀恐怖悉罕,靈堂內(nèi)的尸體忽然破棺而出赤屋,到底是詐尸還是另有隱情,我是刑警寧澤壁袄,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布类早,位于F島的核電站,受9級特大地震影響嗜逻,放射性物質(zhì)發(fā)生泄漏涩僻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一栈顷、第九天 我趴在偏房一處隱蔽的房頂上張望逆日。 院中可真熱鬧,春花似錦萄凤、人聲如沸室抽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坪圾。三九已至,卻和暖如春惑朦,著一層夾襖步出監(jiān)牢的瞬間兽泄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工行嗤, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留已日,地道東北人。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓栅屏,卻偏偏與公主長得像飘千,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子栈雳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,678評論 2 354

推薦閱讀更多精彩內(nèi)容