脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|shell|

服务器之家 - 脚本之家 - Golang - Golang HTTP服务超时控制实现原理分析

Golang HTTP服务超时控制实现原理分析

2023-05-11 14:13未来谁可知 Golang

这篇文章主要介绍了Golang HTTP服务超时控制实现原理,HTTP服务的超时控制是保障服务高可用性的重要措施之一,由于HTTP服务可能会遇到网络延迟,资源瓶颈等问题,因此需要对请求进行超时控制,以避免服务雪崩等问题,需要的朋

前情提要

因为上一篇提过,每次来一个请求,然后就会起一个goroutinue那么导致的可能就是一个树形结构的请求图,底下节点在执行中如果发生了超时,那么就有协程会堆积,所以超时控制是有必要的,一般的实现都由一个顶层设计一个Context进行自顶向下传递,这样可以从一个地方去避免多处执行异常,对于Context的过多细节我不在这里一一阐述,有需要的我将单独出一篇关于Context的介绍,下面我们就来看一下源码是如何设计的:

Context

?
1
2
3
4
5
6
7
// Context's methods may be called by multiple goroutines simultaneously.
type Context interface {
  // 当Context被取消或者到了deadline,返回一个被关闭的channel
  Done() <-chan struct{}
}
// 函数句柄
type CancelFunc func()

设计初衷最关注的两个点就是一个是如何主动结束下游,另一个是如何通知上游结束下游时

前者利用CancelFunc 后者利用Done,后者需要不断监听所以利用channel的返回值做监听

?
1
2
3
4
5
6
//创建退出Context
func WithCancel(parent Context)(ctx Context,cancel CancelFunc){}
//创建有超时时间的Context
func WithTimeout(parent Context,timeout time.Duration)(Context,CancelFunc){}
//创建有截止时间的Context
func WithDeadline(parent Context,d time.Time)(Context,CancelFunc){}

WithCancel/WithTimeout/WithDeadline都是通过定时器来自动触发终结通知的,也就是说为父节点生成一个Done的子节点,并且返回子节点的CancelFunc函数句柄.

封装自定义的Context

context.go

可以定义一个自己的Context,里面先拥有最基本的request和response两个参数,最后是因为思考到并发写resposne的writer所以需要加入锁成员变量以及防止重复写的超时标志位

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package framework
import (
    "context"
    "encoding/json"
    "net/http"
    "sync"
)
type Context struct {
    Request        *http.Request
    ResponseWriter http.ResponseWriter
    hasTimeOut     bool // 是否超时标记位
    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
}
// 统一处理器Controller方法
type ControllerHandler func(c *Context) error

main.go

业务方法使用一下自己封装的Context,里面考虑到了超时控制以及并发读写,以及处理panic

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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()  // 防止多个协程之前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()  // 防止多次协程重复写入超时日志
    }
    return nil
}

Core.go

serverHandler的类,进行处理请求的逻辑,可以先注册对应的映射器和方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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统一管理注册进我们对应的http方法到我们的请求逻辑类里去

?
1
2
3
4
5
6
package main
import "testdemo1/coredemo/framework"
func registerRouter(core *framework.Core){
    // 设置控制器
    core.Get("foo",FooController)
}

main.go

最后是主程序的执行http服务监听和调用初始化router的注册!传入我们自定义的Context

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)
    }
}

本文到此结束!可以自行实现一遍,体验一下,实际和gin的源码封装就是类似的~

我们下一篇再见

到此这篇关于Golang HTTP服务超时控制实现原理分析的文章就介绍到这了,更多相关Golang HTTP服务超时控制内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/jiohfgj/article/details/125643189

延伸 · 阅读

精彩推荐
  • Golang深入讲解Go语言中函数new与make的使用和区别

    深入讲解Go语言中函数new与make的使用和区别

    大家都知道Go语言中的函数new与函数make一直是新手比较容易混淆的东西,看着相似,但其实不同,不过解释两者之间的不同也非常容易,下面这篇文章主要...

    飞雪无情2192020-05-09
  • GolangGo基础教程系列之WaitGroup用法实例详解

    Go基础教程系列之WaitGroup用法实例详解

    这篇文章主要介绍了Go基础教程系列之WaitGroup用法实例详解,需要的朋友可以参考下...

    骏马金龙8662022-09-23
  • GolangGolang语言实现gRPC的具体使用

    Golang语言实现gRPC的具体使用

    本文主要介绍了Golang语言实现gRPC的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着...

    鹿鱼8342022-08-03
  • Golanggo语言实现简单http服务的方法

    go语言实现简单http服务的方法

    这篇文章主要介绍了go语言实现简单http服务的方法,涉及Go语言http操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    pythoner1872020-04-18
  • GolangBeego AutoRouter工作原理解析

    Beego AutoRouter工作原理解析

    这篇文章主要为大家介绍了Beego AutoRouter工作原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪...

    丘山子8712022-08-23
  • GolangGolang Mutex 原理详细解析

    Golang Mutex 原理详细解析

    这篇文章主要介绍了Golang Mutex原理详细解析,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下...

    ag99207372022-08-31
  • GolangGo语言通道之缓冲通道

    Go语言通道之缓冲通道

    这篇文章介绍了Go语言通道之缓冲通道,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    奋斗的大橙子3642022-07-16
  • Golanggo语言中sort包的实现方法与应用详解

    go语言中sort包的实现方法与应用详解

    golang中也实现了排序算法的包sort包,所以下面这篇文章主要给大家介绍了关于go语言中sort包的实现方法与应用的相关资料,文中通过示例代码介绍的非常详...

    Mr_len5182020-05-10