亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一文帶你搞懂go中的請(qǐng)求超時(shí)控制

 更新時(shí)間:2023年11月06日 10:42:07   作者:小范真是一把好手  
在日常開發(fā)中,對(duì)于RPC、HTTP調(diào)用設(shè)置超時(shí)時(shí)間是非常重要的,這就需要我們?cè)O(shè)置超時(shí)控制,本文將通過相關(guān)示例為大家深入介紹一下go中的請(qǐng)求超時(shí)控制,希望對(duì)大家有所幫助

一、為什么需要超時(shí)控制

在日常開發(fā)中,對(duì)于RPC、HTTP調(diào)用設(shè)置超時(shí)時(shí)間是非常重要的。那為什么需要超時(shí)控制呢?我們可以從用戶、系統(tǒng)兩個(gè)角度進(jìn)行考慮;

  • 用戶角度:在這個(gè)快節(jié)奏的時(shí)代,如果一個(gè)接口耗時(shí)太長(zhǎng),用戶可能已經(jīng)離開頁(yè)面了。這種請(qǐng)求下,后續(xù)的計(jì)算任務(wù)就沒用了。比如說,最近的AIGC,我們有個(gè)需求需要用到微軟的ChatGPT,這類接口有個(gè)特點(diǎn),耗時(shí)不受控制,可能30s,可能1min,我們和產(chǎn)品討論以后,這個(gè)接口最后的超時(shí)時(shí)間設(shè)置為9s。(說實(shí)在,有點(diǎn)短,很多超時(shí)的情況)
  • 系統(tǒng)角度:因?yàn)镠TTP、RPC請(qǐng)求均會(huì)占用資源,比如鏈接數(shù)、計(jì)算資源等等,盡快返回,可能防止資源被耗盡的請(qǐng)求;

現(xiàn)在,我們知道要設(shè)置超時(shí)時(shí)間了,那就有個(gè)問題,超時(shí)時(shí)間設(shè)置為多少呢?設(shè)置太小,可能會(huì)出現(xiàn)大面積超時(shí)的情況,不符合業(yè)務(wù)需求。設(shè)置太長(zhǎng),可能會(huì)有以上兩個(gè)缺點(diǎn)。

二、超時(shí)時(shí)間設(shè)置為多少

超時(shí)時(shí)間的設(shè)置可以從這四個(gè)角度考慮:

  • 問產(chǎn)品;產(chǎn)品從業(yè)務(wù)、用戶的角度,行為考慮,這個(gè)頁(yè)面他們能夠接受的時(shí)間是多少。
  • 看歷史數(shù)據(jù);我們可以看這個(gè)接口歷史數(shù)據(jù)的99線,也就是99%的接口耗時(shí)是多少。
  • 壓測(cè);如果這是個(gè)新接口,沒有歷史數(shù)據(jù)可查,那么我們可以考慮進(jìn)行壓測(cè),觀察99%接口耗時(shí)是多少;
  • 計(jì)算代碼邏輯;通過巴拉代碼,看有多少次MySQL、redis查找與插入;

上面四個(gè)方法,只要有一個(gè)湊效就行,但是,我們要秉承數(shù)據(jù)來源要有依據(jù)這條原則,優(yōu)先考慮歷史數(shù)據(jù)、壓測(cè),其次結(jié)合業(yè)務(wù)需求,決定是否需要優(yōu)化代碼等等。

三、超時(shí)控制的種類

在微服務(wù)框架中,我們一個(gè)請(qǐng)求可能需要經(jīng)歷多個(gè)服務(wù),那么在生產(chǎn)環(huán)境下,咱們應(yīng)該得兩手抓:

  • 鏈路超時(shí):也就是在服務(wù)進(jìn)入gate-api的時(shí)候,應(yīng)該設(shè)置一個(gè)鏈路時(shí)間。(我們服務(wù)設(shè)置的是10s)
  • 服務(wù)時(shí)間:每個(gè)微服務(wù)請(qǐng)求其他服務(wù)的超時(shí)時(shí)間。(我們?cè)O(shè)置的是3s)

【注:我們公司大概是這樣的】

上面,服務(wù)時(shí)間的控制里頭,有包含兩方面,客戶端超時(shí)控制與服務(wù)端超時(shí)控制,我們通過一個(gè)例子來表述這兩者之間的差異。如果A服務(wù)請(qǐng)求B服務(wù),這個(gè)請(qǐng)求設(shè)置的超時(shí)時(shí)間為3s,但是B服務(wù)處理數(shù)據(jù)的需要話費(fèi)兩分鐘,那么:

  • 對(duì)于A客戶端,rpc框架大部分都設(shè)置了客戶端超時(shí)時(shí)間,3s就會(huì)返回了。
  • 對(duì)于B服務(wù)端,當(dāng)客戶端3s超時(shí)了,那是否還需要執(zhí)行兩分鐘呢?這個(gè)一般都會(huì)繼續(xù)執(zhí)行了(我們公司就會(huì)執(zhí)行),如果你在代碼里頭有明確的校驗(yàn)超時(shí)時(shí)間,也能做到只執(zhí)行3s的。

接下來,我們來看幾個(gè)例子。

四、Golang超時(shí)控制實(shí)操

案例一

func hardWork(job interface{}) error {
    time.Sleep(time.Minute)
    return nil
}

func requestWorkV1(ctx context.Context, job interface{}) error {
    ctx, cancel := context.WithTimeout(ctx, time.Second*2)
    defer cancel()

    // 僅需要改這里即可
    // done := make(chan error, 1)
    done := make(chan error)

    // done 退出以后,沒有接受者,會(huì)導(dǎo)致協(xié)程阻塞
    go func() {
        done <- hardWork(job)
    }()

    select {
        case err := <-done:
        return err
        case <-ctx.Done():   // 這一部分提前退出
        return ctx.Err()
    }
}

// 可以做到超時(shí)控制,但是會(huì)出現(xiàn)協(xié)程泄露的情況
func TestV1(t *testing.T) {
    const total = 1000
    var wg sync.WaitGroup
    wg.Add(total)
    now := time.Now()

    for i := 0; i < total; i++ {
        go func() {
            defer wg.Done()
            requestWorkV1(context.Background(), "any")
        }()
    }

    wg.Wait()
    fmt.Println("elapsed:", time.Since(now))  // 2秒后打印這條語(yǔ)句,說明協(xié)程只執(zhí)行了兩秒

    time.Sleep(time.Minute * 2)
    fmt.Println("number of goroutines:", runtime.NumGoroutine())  // number of goroutines: 1002
}

執(zhí)行上述代碼:我們會(huì)發(fā)現(xiàn)協(xié)程執(zhí)行2秒就退出了 【滿足我們超時(shí)控制需求】 ,但是第2個(gè)打印語(yǔ)句顯示協(xié)程泄漏了,當(dāng)前有1002個(gè)協(xié)程;

原因:select中的協(xié)程提前退出,從而導(dǎo)致無(wú)緩存chan沒有接受者,從而導(dǎo)致協(xié)程泄漏。只需要將無(wú)緩存chan改為有緩存chan即可。

五、GRPC中如何做超時(shí)控制

接著,我們?cè)诳纯丛贕RPC中,我們?nèi)绾巫龀瑫r(shí)控制。

首先,我們看下這個(gè)小Demo的目錄結(jié)構(gòu):

.
├── client_test.go
├── proto
│   ├── hello.pb.go
│   ├── hello.proto
│   └── hello_grpc.pb.go
└── server_test.go

定義接口IDL文件

syntax = "proto3";

package helloworld;

option go_package = ".";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

執(zhí)行protoc工具

hello git:(master) ? protoc -I proto/ proto/hello.proto --go_out=./proto --go-grpc_out=./proto

寫client代碼

const (
    address     = "localhost:50051"
    defaultName = "world"
)

func TestClient(t *testing.T) {
    conn, err := grpc.Dial(address, grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewGreeterClient(conn)

    name := defaultName

    ctx, cancel := context.WithTimeout(context.Background(), 2*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.Message)
}

在客戶端代碼中,我們只需要設(shè)置ctx即可。grpc客戶端框架就會(huì)幫我們監(jiān)控ctx,只要超時(shí)了就會(huì)返回。

寫server代碼

func (s *server) SayHello(ctx context.Context, request *pb.HelloRequest) (*pb.HelloReply, error) {
    logrus.Info("request in")

    time.Sleep(5 * time.Second)

    //select {
    //case <-ctx.Done():
    // fmt.Println("time out Done")
    //}

    logrus.Info("requst out")

    if ctx.Err() == context.DeadlineExceeded {
        log.Printf("RPC has reached deadline exceeded state: %s", ctx.Err())
        return nil, ctx.Err()
    }

    return &pb.HelloReply{Message: "Hello, " + request.Name}, nil
}

func TestServer(t *testing.T) {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("Failed to listen: %v", err)
    }

    s := grpc.NewServer()
    pb.RegisterGreeterServer(s, &server{})
    if err := s.Serve(lis); err != nil {
        log.Fatalf("Failed to serve: %v", err)
    }
}

服務(wù)端,grpc框架就沒有替我們監(jiān)控了,需要我們自己寫邏輯,上述代碼可以通過注釋不同部分,驗(yàn)證以下幾點(diǎn):

  • grpc框架沒有替我們監(jiān)控ctx,需要我們自己監(jiān)控;
  • 通過select監(jiān)控ctx;
  • 通過context.DeadlineExceeded來監(jiān)控ctx,從而提前返回;

六、GRPC框架如何監(jiān)控超時(shí)的呢

代碼在grpc/stream.go文件:

func newClientStreamWithParams(ctx context.Context, desc *StreamDesc, cc *ClientConn, method string, mc serviceconfig.MethodConfig, onCommit, doneFunc func(), opts ...CallOption) (_ iresolver.ClientStream, err error) {
    // .....


	if desc != unaryStreamDesc {
		// Listen on cc and stream contexts to cleanup when the user closes the
		// ClientConn or cancels the stream context.  In all other cases, an error
		// should already be injected into the recv buffer by the transport, which
		// the client will eventually receive, and then we will cancel the stream's
		// context in clientStream.finish.
		go func() {
			select {
			case <-cc.ctx.Done():
				cs.finish(ErrClientConnClosing)
			case <-ctx.Done():
				cs.finish(toRPCErr(ctx.Err()))
			}
		}()
	}
}

可以看到,在newClientStreamWithParams中,GRPC替我們起了一個(gè)協(xié)程,監(jiān)控ctx.Done。

以上就是一文帶你搞懂go中的請(qǐng)求超時(shí)控制的詳細(xì)內(nèi)容,更多關(guān)于go請(qǐng)求超時(shí)控制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • pytorch中的transforms.ToTensor和transforms.Normalize的實(shí)現(xiàn)

    pytorch中的transforms.ToTensor和transforms.Normalize的實(shí)現(xiàn)

    本文主要介紹了pytorch中的transforms.ToTensor和transforms.Normalize的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Go中regexp包常見的正則表達(dá)式操作

    Go中regexp包常見的正則表達(dá)式操作

    本文主要介紹了Go中regexp包常見的正則表達(dá)式操作,包括匹配、查找、替換和分割字符串等,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02
  • 重學(xué)Go語(yǔ)言之如何使用Redis

    重學(xué)Go語(yǔ)言之如何使用Redis

    Redis是我們開發(fā)應(yīng)用程序中很常用的NoSQL數(shù)據(jù)庫(kù),那么在Go語(yǔ)言中要如何連接和操作Redis呢,在這篇文章中,我們就來一起來探究一下吧
    2023-08-08
  • Go工具鏈之go tool cover使用方法和示例詳解

    Go工具鏈之go tool cover使用方法和示例詳解

    go tool cover是Go工具鏈中的一個(gè)命令,作用是分析測(cè)試用例的代碼覆蓋率,本文將對(duì)go tool cover 作用,使用方法和使用場(chǎng)景作一個(gè)簡(jiǎn)單的介紹,感興趣的同學(xué)可以參考閱讀一下
    2023-07-07
  • GoLang實(shí)現(xiàn)Viper庫(kù)的封裝流程詳解

    GoLang實(shí)現(xiàn)Viper庫(kù)的封裝流程詳解

    Viper是一個(gè)用于Go語(yǔ)言應(yīng)用程序的配置管理庫(kù),它提供了一種簡(jiǎn)單而靈活的方式來處理應(yīng)用程序的配置,支持多種格式的配置文件,這篇文章主要介紹了GoLang封裝Viper庫(kù)的流程,感興趣的同學(xué)可以參考下文
    2023-05-05
  • vscode 通過Go:Install/Update Tools命令安裝失敗的問題解決

    vscode 通過Go:Install/Update Tools命令安裝失敗的問題解決

    本文介紹了在VSCode開發(fā)環(huán)境中通過Go:Install/UpdateTools命令安裝工具時(shí)遇到網(wǎng)絡(luò)問題的解決方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-12-12
  • Go語(yǔ)言執(zhí)行cmd命令庫(kù)的方法實(shí)現(xiàn)

    Go語(yǔ)言執(zhí)行cmd命令庫(kù)的方法實(shí)現(xiàn)

    go語(yǔ)言用來執(zhí)行一個(gè)系統(tǒng)的命令相對(duì)python來說還是有點(diǎn)復(fù)雜的,執(zhí)行命令是一個(gè)非常常見的需求,本文主要介紹了Go語(yǔ)言執(zhí)行cmd命令庫(kù)的方法實(shí)現(xiàn),感興趣的可以了解一下
    2023-09-09
  • go如何利用orm簡(jiǎn)單實(shí)現(xiàn)接口分布式鎖

    go如何利用orm簡(jiǎn)單實(shí)現(xiàn)接口分布式鎖

    本篇文章主要介紹了go如何利用orm簡(jiǎn)單實(shí)現(xiàn)接口分布式鎖,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-07-07
  • Golang中的四個(gè)括號(hào)示例詳解

    Golang中的四個(gè)括號(hào)示例詳解

    這篇文章主要介紹了Golang中的四個(gè)括號(hào),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),通過實(shí)例代碼補(bǔ)充介紹了有效的括號(hào)golang實(shí)現(xiàn),需要的朋友可以參考下
    2024-03-03
  • Go?gRPC進(jìn)階教程服務(wù)超時(shí)設(shè)置

    Go?gRPC進(jìn)階教程服務(wù)超時(shí)設(shè)置

    這篇文章主要為大家介紹了Go?gRPC進(jìn)階,gRPC請(qǐng)求的超時(shí)時(shí)間設(shè)置,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06

最新評(píng)論