最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang?HTTP服務(wù)超時控制實現(xiàn)原理分析

 更新時間:2023年05月10日 10:09:42   作者:未來誰可知  
這篇文章主要介紹了Golang?HTTP服務(wù)超時控制實現(xiàn)原理,HTTP服務(wù)的超時控制是保障服務(wù)高可用性的重要措施之一,由于HTTP服務(wù)可能會遇到網(wǎng)絡(luò)延遲,資源瓶頸等問題,因此需要對請求進(jìn)行超時控制,以避免服務(wù)雪崩等問題,需要的朋友可以參考下

前情提要

因為上一篇提過,每次來一個請求,然后就會起一個goroutinue那么導(dǎo)致的可能就是一個樹形結(jié)構(gòu)的請求圖,底下節(jié)點在執(zhí)行中如果發(fā)生了超時,那么就有協(xié)程會堆積,所以超時控制是有必要的,一般的實現(xiàn)都由一個頂層設(shè)計一個Context進(jìn)行自頂向下傳遞,這樣可以從一個地方去避免多處執(zhí)行異常,對于Context的過多細(xì)節(jié)我不在這里一一闡述,有需要的我將單獨出一篇關(guān)于Context的介紹,下面我們就來看一下源碼是如何設(shè)計的:

Context

// Context's methods may be called by multiple goroutines simultaneously.
type Context interface {
  // 當(dāng)Context被取消或者到了deadline,返回一個被關(guān)閉的channel
  Done() <-chan struct{}
}
// 函數(shù)句柄
type CancelFunc func()

設(shè)計初衷最關(guān)注的兩個點就是一個是如何主動結(jié)束下游,另一個是如何通知上游結(jié)束下游時

前者利用CancelFunc 后者利用Done,后者需要不斷監(jiān)聽所以利用channel的返回值做監(jiān)聽

//創(chuàng)建退出Context
func WithCancel(parent Context)(ctx Context,cancel CancelFunc){}
//創(chuàng)建有超時時間的Context
func WithTimeout(parent Context,timeout time.Duration)(Context,CancelFunc){}
//創(chuàng)建有截止時間的Context
func WithDeadline(parent Context,d time.Time)(Context,CancelFunc){}

WithCancel/WithTimeout/WithDeadline都是通過定時器來自動觸發(fā)終結(jié)通知的,也就是說為父節(jié)點生成一個Done的子節(jié)點,并且返回子節(jié)點的CancelFunc函數(shù)句柄.

封裝自定義的Context

context.go

可以定義一個自己的Context,里面先擁有最基本的request和response兩個參數(shù),最后是因為思考到并發(fā)寫resposne的writer所以需要加入鎖成員變量以及防止重復(fù)寫的超時標(biāo)志位

package framework
import (
	"context"
	"encoding/json"
	"net/http"
	"sync"
)
type Context struct {
	Request        *http.Request
	ResponseWriter http.ResponseWriter
	hasTimeOut     bool // 是否超時標(biāo)記位
	writerMux      *sync.Mutex
}
func NewContext()*Context{
	return &Context{}
}
func (ctx *Context) BaseContext() context.Context {
	return ctx.Request.Context()
}
func (ctx *Context) Done() <-chan struct{} {
	return ctx.BaseContext().Done()
}
func (ctx *Context)SetHasTimeOut(){
	ctx.hasTimeOut=true
}
func (ctx *Context)HasTimeOut()bool{
	return ctx.hasTimeOut
}
// 自行封裝一個Json的方法
func (ctx *Context) Json(status int, obj interface{}) (err error) {
	if ctx.HasTimeOut(){
		return nil
	}
	bytes, err := json.Marshal(obj)
	ctx.ResponseWriter.WriteHeader(status)
	_, err = ctx.ResponseWriter.Write(bytes)
	return
}
// 對外暴露鎖
func (ctx *Context) WriterMux() *sync.Mutex {
	return ctx.writerMux
}
// 統(tǒng)一處理器Controller方法
type ControllerHandler func(c *Context) error

main.go

業(yè)務(wù)方法使用一下自己封裝的Context,里面考慮到了超時控制以及并發(fā)讀寫,以及處理panic

package main
import (
	"context"
	"fmt"
	"testdemo1/coredemo/framework"
	"time"
)
func FooController(ctx *framework.Context) error {
	durationCtx, cancel := context.WithTimeout(ctx.BaseContext(), time.Second)
	defer cancel()
	finish := make(chan struct{}, 1)
	panicChan := make(chan interface{}, 1)
	go func() {
		defer func() {
			if p := recover(); p != nil {
				panicChan <- p
			}
		}()
		time.Sleep(time.Second * 10)
		finish <- struct{}{}
	}()
	select {
	case p := <-panicChan: // panic
	fmt.Println("panic:",p)
	    ctx.WriterMux().Lock()  // 防止多個協(xié)程之前writer的消息亂序
		defer ctx.WriterMux().Unlock()
		ctx.Json(500, "panic")
	case <-finish: // 正常退出
		ctx.Json(200, "ok")
		fmt.Println("finish")
	case <-durationCtx.Done(): // 超時事件
		ctx.WriterMux().Lock()
		defer ctx.WriterMux().Unlock()
		ctx.Json(500, "timed out")
		ctx.SetHasTimeOut()  // 防止多次協(xié)程重復(fù)寫入超時日志
	}
	return nil
}

Core.go

serverHandler的類,進(jìn)行處理請求的邏輯,可以先注冊對應(yīng)的映射器和方法

package framework
import (
	"net/http"
)
type Core struct {
	RouterMap map[string]ControllerHandler
}
func (c Core) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	http.DefaultServeMux.ServeHTTP(writer, request)
}
func NewCore() *Core {
	return &Core{
		RouterMap:make(map[string]ControllerHandler,0),
	}
}
// 注冊Get方法
func (c *Core) Get(pattern string, handler ControllerHandler) {
	c.RouterMap["get"+"-"+pattern]=handler
}
// 注冊Post方法
func (c *Core) Post(pattern string, handler ControllerHandler) {
	c.RouterMap["post"+"-"+pattern]=handler
}

router.go

router統(tǒng)一管理注冊進(jìn)我們對應(yīng)的http方法到我們的請求邏輯類里去

package main
import "testdemo1/coredemo/framework"
func registerRouter(core *framework.Core){
	// 設(shè)置控制器
	core.Get("foo",FooController)
}

main.go

最后是主程序的執(zhí)行http服務(wù)監(jiān)聽和調(diào)用初始化router的注冊!傳入我們自定義的Context

package main
import (
	"log"
	"net/http"
	"testdemo1/coredemo/framework"
)
func main() {
	server:=&http.Server{Addr: ":8080",Handler: framework.NewCore()}
	// 注冊router
	registerRouter(framework.NewCore())
	err := server.ListenAndServe()
    if err!=nil{
    	log.Fatal(err)
	}
}

本文到此結(jié)束!可以自行實現(xiàn)一遍,體驗一下,實際和gin的源碼封裝就是類似的~

我們下一篇再見

到此這篇關(guān)于Golang HTTP服務(wù)超時控制實現(xiàn)原理分析的文章就介紹到這了,更多相關(guān)Golang HTTP服務(wù)超時控制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文理解Go 中的可尋址和不可尋址

    一文理解Go 中的可尋址和不可尋址

    如果字典的元素不存在,則返回零值,而零值是不可變對象,如果能尋址問題就大了。而如果字典的元素存在,考慮到 Go 中 map 實現(xiàn)中元素的地址是變化的,這意味著尋址的結(jié)果也是無意義的。下面我們就圍繞這個話題寫一篇文章吧,需要的朋友可以參考一下
    2021-10-10
  • Go 內(nèi)存分配管理

    Go 內(nèi)存分配管理

    這篇文章主要介紹了Go 內(nèi)存分配管理,go 語言實際內(nèi)存、虛擬內(nèi)存怎么分配,延遲歸還是什么機制?本文結(jié)合監(jiān)控對內(nèi)存管理進(jìn)行了觀測,深入學(xué)習(xí)golang對于內(nèi)存的管理機制,需要的朋友可以參考一下
    2022-02-02
  • 使用GO語言實現(xiàn)Mysql數(shù)據(jù)庫CURD的簡單示例

    使用GO語言實現(xiàn)Mysql數(shù)據(jù)庫CURD的簡單示例

    本文主要介紹了使用GO語言實現(xiàn)Mysql數(shù)據(jù)庫CURD的簡單示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • go zero微服務(wù)框架logx日志組件剖析

    go zero微服務(wù)框架logx日志組件剖析

    這篇文章主要為大家介紹了go zero微服務(wù)框架logx日志組件剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • windows安裝部署go超詳細(xì)實戰(zhàn)記錄(實測有用!)

    windows安裝部署go超詳細(xì)實戰(zhàn)記錄(實測有用!)

    Golang語言在近年來因為其高性能、編譯速度快、開發(fā)成本低等特點逐漸得到大家的青睞,這篇文章主要給大家介紹了關(guān)于windows安裝部署go超詳細(xì)實戰(zhàn)的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • GoFrame框架Scan類型轉(zhuǎn)換實例

    GoFrame框架Scan類型轉(zhuǎn)換實例

    這篇文章主要為大家介紹了GoFrame框架Scan類型轉(zhuǎn)換的實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • 詳解Go語言中的內(nèi)存對齊

    詳解Go語言中的內(nèi)存對齊

    前面我們學(xué)習(xí)了Go語言空結(jié)構(gòu)體詳解,最近又在看unsafe包的知識,在查閱相關(guān)資料時不免會看到內(nèi)存對齊相關(guān)的內(nèi)容。雖然不會,但可以學(xué)呀,那么這篇文章,我們就一起來看下什么是內(nèi)存對齊吧
    2022-10-10
  • golang判斷兩個事件是否存在沖突的方法示例

    golang判斷兩個事件是否存在沖突的方法示例

    這篇文章主要為大家詳細(xì)介紹了golang判斷兩個事件是否存在沖突的方法示例,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • Go語言實戰(zhàn)之詳細(xì)掌握正則表達(dá)式的應(yīng)用與技巧

    Go語言實戰(zhàn)之詳細(xì)掌握正則表達(dá)式的應(yīng)用與技巧

    正則表達(dá)式是一種從左到右與主題字符串匹配的模式,正則表達(dá)式用于替換字符串中的文本,驗證表單,基于模式匹配從字符串中提取子字符串等等,這篇文章主要給大家介紹了關(guān)于Go語言實戰(zhàn)之詳細(xì)掌握正則表達(dá)式的應(yīng)用與技巧,需要的朋友可以參考下
    2023-12-12
  • Go關(guān)鍵字defer的使用和底層實現(xiàn)

    Go關(guān)鍵字defer的使用和底層實現(xiàn)

    defer是Go語言的關(guān)鍵字,一般用于資源的釋放和異常的捕捉,defer語句后將其后面跟隨的語句進(jìn)行延遲處理,就是說在函數(shù)執(zhí)行完畢后再執(zhí)行調(diào)用,也就是return的ret指令之前,本文給大家介紹了Go關(guān)鍵字defer的使用和底層實現(xiàn),需要的朋友可以參考下
    2023-11-11

最新評論

郴州市| 桃江县| 石嘴山市| 阳高县| 包头市| 溧阳市| 侯马市| 西宁市| 伊宁市| 斗六市| 宁武县| 朝阳县| 永丰县| 类乌齐县| 万源市| 拉萨市| 玉环县| 泰州市| 石阡县| 茂名市| 巴东县| 略阳县| 太保市| 榆树市| 光山县| 文成县| 长乐市| 涿州市| 响水县| 金华市| 竹溪县| 古蔺县| 宝坻区| 奇台县| 若尔盖县| 玉屏| 安西县| 雅安市| 香河县| 巩留县| 东山县|