栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Go Web服务器的流程管理

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Go Web服务器的流程管理

调整/配置HTTP服务器

实现HTTP服务器的类型为

http.Server
。如果您不创建
http.Server
自己,例如因为调用
http.ListenAndServe()
函数,那么
http.Server
将为您创建一个幕后花絮:

func ListenAndServe(addr string, handler Handler) error {    server := &Server{Addr: addr, Handler: handler}    return server.ListenAndServe()}

因此,如果您想周/自定义HTTP服务器,请自己创建一个并自己调用其

Server.ListenAndServe()
方法。
http.Server
是一个结构,其零值为有效配置。查看其文档,其中包含哪些字段,以及可以进行哪些调整/配置。

HTTP服务器的“进程管理”记录在

Server.Serve()

服务在侦听器l上接受传入的连接, 为每个服务创建一个新的服务goroutine
。服务goroutine读取请求,然后调用srv.Handler对其进行回复。服务始终返回非零错误。

因此,每个传入的HTTP请求都在其新的goroutine中进行处理,这意味着它们可以同时得到服务。不幸的是,API没有记录任何进入和更改其工作方式的方法。

并查看当前的实现(Go
1.6.2),也没有未记录的方法来实现。

server.go
,目前第2107-2139行:

2107    func (srv *Server) Serve(l net.Listener) error {2108        defer l.Close()2109        if fn := testHookServerServe; fn != nil {2110 fn(srv, l)2111        }2112        var tempDelay time.Duration // how long to sleep on accept failure2113        if err := srv.setupHTTP2(); err != nil {2114 return err2115        }2116        for {2117 rw, e := l.Accept()2118 if e != nil {2119     if ne, ok := e.(net.Error); ok && ne.Temporary() {2120         if tempDelay == 0 {2121  tempDelay = 5 * time.Millisecond2122         } else {2123  tempDelay *= 22124         }2125         if max := 1 * time.Second; tempDelay > max {2126  tempDelay = max2127         }2128         srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)2129         time.Sleep(tempDelay)2130         continue2131     }2132     return e2133 }2134 tempDelay = 02135 c := srv.newConn(rw)2136 c.setState(c.rwc, StateNew) // before Serve can return2137 go c.serve()2138        }2139    }

如您在第2137行中所见,该连接是在新的goroutine上 无条件 提供的,因此您无能为力。

限制“工人” goroutines

如果您想限制为请求提供服务的goroutine的数量,您仍然可以这样做。

您可以将它们限制在多个级别。有关限制听众级别的信息,请参见Darigaaz的答案。要限制处理程序级别,请继续阅读。

例如,您可以在每个

http.Handler
或处理程序函数(
http.HandlerFunc
)中插入代码,仅当并发请求服务goroutine的数量小于指定的限制时,该代码才会继续执行。

这种限制同步代码有很多构造。一个示例可能是:创建一个容量为您所需限制的缓冲通道。每个处理程序应首先在此通道上发送一个值,然后再进行工作。当处理程序返回时,它必须从通道接收一个值:因此最好在延迟函数中完成(不要忘记“清理”自身)。

如果缓冲区已满,则尝试在通道上发送的新请求将被阻止:等待直到请求完成其工作。

请注意,您不必将此限制代码注入所有处理程序,您可以使用“中间件”模式,使用新的处理程序类型包装您的处理程序,执行此限制同步工作,并在中间调用包装的处理程序它的。

在处理程序中进行限制(相对于在侦听器中进行限制)的优势在于,在处理程序中我们知道处理程序的作用,因此我们可以进行 选择性
限制(例如,我们可以选择限制某些请求,例如数据库操作,而不是限制限制其他人,例如提供静态资源),或者我们可以根据需要任意创建 多个不同的限制组
(例如,将并发数据库请求限制为10个最大值,将静态请求限制为100个最大值,将繁重的计算请求限制为3个最大值)等。我们也可以轻松实现各种限制,例如已登录/付费用户的无限制(或上限),以及匿名/非付费用户的低限制。

还要注意,您甚至可以在一个位置进行速率限制,而无需使用中间件。创建一个“主处理程序”,并将其传递给

http.ListenAndServe()
(或
Server.ListenAndServe()
)。在此主处理程序中进行速率限制(例如,使用如上所述的缓冲通道),然后简单地将调用转发给
http.ServeMux
您正在使用的对象。

这是一个简单的示例,它使用包()

http.ListenAndServe()
的默认多路复用器进行演示。它将并发请求限制为2:
http``http.DefaultServeMux

func fooHandler(w http.ResponseWriter, r *http.Request) {    log.Println("Foo called...")    time.Sleep(3 * time.Second)    w.Write([]byte("I'm Foo"))    log.Println("Foo ended.")}func barHandler(w http.ResponseWriter, r *http.Request) {    log.Println("Bar called...")    time.Sleep(3 * time.Second)    w.Write([]byte("I'm Bar"))    log.Println("Bar ended.")}var ch = make(chan struct{}, 2) // 2 concurrent requestsfunc mainHandler(w http.ResponseWriter, r *http.Request) {    ch <- struct{}{}    defer func() {        <-ch    }()    http.DefaultServeMux.ServeHTTP(w, r)}func main() {    http.HandleFunc("/foo", fooHandler)    http.HandleFunc("/bar", barHandler)    panic(http.ListenAndServe(":8080", http.HandlerFunc(mainHandler)))}

部署方式

用Go编写的Web应用程序不需要外部服务器来控制流程,因为Go Web服务器本身可以同时处理请求。

因此,您可以按原样启动以Go语言编写的Web服务器:Go Web服务器已准备好投入生产。

当然,您可以根据需要将其他服务器用于其他任务(例如HTTPS处理,身份验证/授权,路由,多个服务器之间的负载平衡)。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/370108.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号