BFE的监听器处理协程(BfeServer.Serve函数)循环接受新到的客户端连接,并创建新协程处理该连接。
// bfe_server/http_server.go
func (srv *BfeServer) Serve(l net.Listener, raw net.Listener, proto string) error {
...
for {
// accept new connection
rw, e := l.Accept()
...
// start goroutine for new connection
go func(rwc net.Conn, srv *BfeServer) {
c, err := newConn(rw, srv)
...
c.serve()
}(rw, srv)
}
}
BFE的连接bfe_server.conn 执行serve函数处理该连接,主要包含:
- 步骤1. 回调点处理:执行HandleAccept回调点的回调链函数
// bfe_server/http_conn.go
// Callback for HANDLE_ACCEPT
hl = c.server.CallBacks.GetHandlerList(bfe_module.HandleAccept)
if hl != nil {
retVal = hl.FilterAccept(c.session)
...
}
- 步骤2. 握手及协商:执行TLS握手(如果用户发起TLS连接)
在TLS握手成功后,执行HandleHandshake回调点的回调链函数
// bfe_server/http_conn.go
// Callback for HANDLE_HANDSHAKE
hl = c.server.CallBacks.GetHandlerList(bfe_module.HandleHandshake)
if hl != nil {
retVal = hl.FilterAccept(c.session)
...
}
然后基于协商协议,选择并执行应用层协议Handler(HTTP2/SPDY/STREAM)
// bfe_server/bfe_server.go
tlsNextProto[tls_rule_conf.SPDY31] = bfe_spdy.NewProtoHandler(nil)
tlsNextProto[tls_rule_conf.HTTP2] = bfe_http2.NewProtoHandler(nil)
tlsNextProto[tls_rule_conf.STREAM] = bfe_stream.NewProtoHandler(
&bfe_stream.Server{BalanceHandler: srv.Balance})
-
步骤3. 连接协议处理:区分连接的协议,执行:
- 如果是HTTP(S)连接,在当前协程中顺序读取请求并处理
- 如果是HTTP2/SPDY连接,在新建协程中并发读取请求并处理
- 如果是STREAM连接,在新建协程处理数据的双向转发(下文略去)
关于协议的实现说明,详见核心协议实现一章。
BFE的连接对象bfe_server.conn 执行serveRequest函数处理请求。虽然HTTP/HTTPS/HTTP2/SPDY/使用不同方式传输数据,但BFE从协议层接收到HTTP请求后,在上层都转化为相同的内部请求类型(bfe_http.Request),并执行统一的逻辑处理。
请求处理的具体流程如下:
-
步骤1. 回调点处理
执行HandleBeforeLocation回调点的回调链函数
// bfe_server/reverseproxy.go
// Callback for HandleBeforeLocation
hl = srv.CallBacks.GetHandlerList(bfe_module.HandleBeforeLocation)
if hl != nil {
retVal, res = hl.FilterRequest(basicReq)
...
}
-
步骤2. 租户路由:
查找请求归属的租户。详见请求路由中的说明。
// bfe_server/reverseproxy.go
// find product
if err := srv.findProduct(basicReq); err != nil {
...
}
-
步骤3.回调点处理:
执行HandleFoundProduct回调点的回调链函数
// bfe_server/reverseproxy.go
// Callback for HandleFoundProduct
hl = srv.CallBacks.GetHandlerList(bfe_module.HandleFoundProduct)
if hl != nil {
retVal, res = hl.FilterRequest(basicReq)
...
}
-
步骤4.集群路由:
查找请求归属的目的集群。详见请求路由中的说明。
// bfe_server/reverseproxy.go
if err = srv.findCluster(basicReq); err != nil {
...
}
- 步骤5.回调点处理:执行HandleAfterLocation回调点的回调链函数
// bfe_server/reverseproxy.go
// Callback for HandleAfterLocation
hl = srv.CallBacks.GetHandlerList(bfe_module.HandleAfterLocation)
if hl != nil {
...
}
-
步骤6.请求预处理:
对请求最终转发前,对请求进行预处理并获取转发参数(例如超时时间)
-
步骤7.负载均衡及转发:
向下游集群转发HTTP请求。详见负载均衡中的说明
// bfe_server/reverseproxy.go
res, action, err = p.clusterInvoke(srv, cluster, basicReq, rw)
basicReq.HttpResponse = res
- 步骤8.回调点处理:执行HandleReadResponse回调点的回调链函数
// bfe_server/reverseproxy.go
// Callback for HandleReadResponse
hl = srv.CallBacks.GetHandlerList(bfe_module.HandleReadResponse)
if hl != nil {
...
}
- 步骤9.响应发送:向用户端发送响应
// bfe_server/reverseproxy.go
err = p.sendResponse(rw, res, resFlushInterval, cancelOnClientClose)
if err != nil {
...
}
- 执行HandleRequestFinish回调点的回调链函数
// bfe_server/reverseproxy.go
// Callback for HandleRequestFinish
hl := srv.CallBacks.GetHandlerList(bfe_module.HandleRequestFinish)
if hl != nil {
...
}
- 检查连接是否需关闭(例如请求被封禁或HTTP KeepAlive未启用)
- 如需关闭,连接将停止读取后续请求并执行关闭操作
连接在结束前,还需要执行以下操作:
- 执行HandleFinish回调点的回调链函数
// bfe_server/http_conn.go
// Callback for HandleFinish
hl := srv.CallBacks.GetHandlerList(bfe_module.HandleFinish)
if hl != nil {
hl.FilterFinish(c.session)
}
- 写出连接缓存区数据并关闭连接
上一章:第二十八章 进程模型
下一章:第三十章 模块框架