首先,在 fasthttp
中大量的使用了 sync.Pool
来缓存某些对象,已达到对象复用、减小 GC 压力的目的。 fasthttp
并不像官方 net/http
一样,创建一个 gorountine
来处理一个 http 请求,而是创建可复用的 gorountine
,并且数量会随着负载的大小伸缩。
查看自动伸缩如何实现的
从 fasthttp.ListenAndServe
入手:
func (s *Server) ListenAndServe(addr string) error {
ln, err := net.Listen("tcp4", addr) // 创建 Listen 对象用于监听端口创建tcp连接
...
return s.Serve(ln)
}
...
func (s *Server) serveConn(c net.Conn) (err error) {
// 初始化 ctx(RequestCtx)
// 执行请求处理器
}
func (s *Server) Serve(ln net.Listener) error {
....
var c net.Conn
var err error
maxWorkersCount := s.getConcurrency()
....
wp := &workerPool{
// 这个就是实现 自动伸缩功能的主体
WorkerFunc: s.serveConn,
MaxWorkersCount: maxWorkersCount,
LogAllErrors: s.LogAllErrors,
Logger: s.logger(),
connState: s.setState,
}
wp.Start() // 初始化 workerPool 并开始 循环清理 workerPool
...
for {
if c, err = acceptConn(s, ln, &lastPerIPErrorTime); err != nil {
// 监听 并得到一个TCP链接
...
}
...
if !wp.Serve(c) {
// 交由 wp 对象处理
// 无法处理请求(并发数达到上限)的一些处理代码
...
}
c = nil
}
}
// ---------------------------------------
// workerpool.go
// ---------------------------------------
...
func (wp *workerPool) Start