Skip to content

Commit 091a594

Browse files
authored
v3: Improve performance of Adaptor Middleware (#3078)
* Improve performance of adaptor middleware by over 50% * Update whats_new documentation * Remove fasthttp.Request pool * Update whats_new.md
1 parent 58d07f0 commit 091a594

File tree

2 files changed

+52
-7
lines changed

2 files changed

+52
-7
lines changed

docs/whats_new.md

+28
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,34 @@ DRAFT section
254254

255255
## 🧬 Middlewares
256256

257+
### Adaptor
258+
259+
The adaptor middleware has been significantly optimized for performance and efficiency. Key improvements include reduced response times, lower memory usage, and fewer memory allocations. These changes make the middleware more reliable and capable of handling higher loads effectively. Enhancements include the introduction of a `sync.Pool` for managing `fasthttp.RequestCtx` instances and better HTTP request and response handling between net/http and fasthttp contexts.
260+
261+
| Payload Size | Metric | V2 | V3 | Percent Change |
262+
|--------------|------------------|-----------|----------|-------------------|
263+
| 100KB | Execution Time | 1056 ns/op| 588.6 ns/op | -44.25% |
264+
| | Memory Usage | 2644 B/op | 254 B/op | -90.39% |
265+
| | Allocations | 16 allocs/op | 5 allocs/op | -68.75% |
266+
| 500KB | Execution Time | 1061 ns/op| 562.9 ns/op | -46.94% |
267+
| | Memory Usage | 2644 B/op | 248 B/op | -90.62% |
268+
| | Allocations | 16 allocs/op | 5 allocs/op | -68.75% |
269+
| 1MB | Execution Time | 1080 ns/op| 629.7 ns/op | -41.68% |
270+
| | Memory Usage | 2646 B/op | 267 B/op | -89.91% |
271+
| | Allocations | 16 allocs/op | 5 allocs/op | -68.75% |
272+
| 5MB | Execution Time | 1093 ns/op| 540.3 ns/op | -50.58% |
273+
| | Memory Usage | 2654 B/op | 254 B/op | -90.43% |
274+
| | Allocations | 16 allocs/op | 5 allocs/op | -68.75% |
275+
| 10MB | Execution Time | 1044 ns/op| 533.1 ns/op | -48.94% |
276+
| | Memory Usage | 2665 B/op | 258 B/op | -90.32% |
277+
| | Allocations | 16 allocs/op | 5 allocs/op | -68.75% |
278+
| 25MB | Execution Time | 1069 ns/op| 540.7 ns/op | -49.42% |
279+
| | Memory Usage | 2706 B/op | 289 B/op | -89.32% |
280+
| | Allocations | 16 allocs/op | 5 allocs/op | -68.75% |
281+
| 50MB | Execution Time | 1137 ns/op| 554.6 ns/op | -51.21% |
282+
| | Memory Usage | 2734 B/op | 298 B/op | -89.10% |
283+
| | Allocations | 16 allocs/op | 5 allocs/op | -68.75% |
284+
257285
### Cache
258286

259287
We are excited to introduce a new option in our caching middleware: Cache Invalidator. This feature provides greater control over cache management, allowing you to define a custom conditions for invalidating cache entries.

middleware/adaptor/adaptor.go

+24-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"net"
66
"net/http"
77
"reflect"
8+
"sync"
89
"unsafe"
910

1011
"github.com/gofiber/fiber/v3"
@@ -13,6 +14,12 @@ import (
1314
"github.com/valyala/fasthttp/fasthttpadaptor"
1415
)
1516

17+
var ctxPool = sync.Pool{
18+
New: func() any {
19+
return new(fasthttp.RequestCtx)
20+
},
21+
}
22+
1623
// HTTPHandlerFunc wraps net/http handler func to fiber handler
1724
func HTTPHandlerFunc(h http.HandlerFunc) fiber.Handler {
1825
return HTTPHandler(h)
@@ -82,12 +89,13 @@ func HTTPMiddleware(mw func(http.Handler) http.Handler) fiber.Handler {
8289
return func(c fiber.Ctx) error {
8390
var next bool
8491
nextHandler := http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
85-
next = true
8692
// Convert again in case request may modify by middleware
93+
next = true
8794
c.Request().Header.SetMethod(r.Method)
8895
c.Request().SetRequestURI(r.RequestURI)
8996
c.Request().SetHost(r.Host)
9097
c.Request().Header.SetHost(r.Host)
98+
9199
for key, val := range r.Header {
92100
for _, v := range val {
93101
c.Request().Header.Set(key, v)
@@ -124,9 +132,9 @@ func FiberApp(app *fiber.App) http.HandlerFunc {
124132

125133
func handlerFunc(app *fiber.App, h ...fiber.Handler) http.HandlerFunc {
126134
return func(w http.ResponseWriter, r *http.Request) {
127-
// New fasthttp request
128135
req := fasthttp.AcquireRequest()
129136
defer fasthttp.ReleaseRequest(req)
137+
130138
// Convert net/http -> fasthttp request
131139
if r.Body != nil {
132140
n, err := io.Copy(req.BodyWriter(), r.Body)
@@ -141,37 +149,46 @@ func handlerFunc(app *fiber.App, h ...fiber.Handler) http.HandlerFunc {
141149
req.SetRequestURI(r.RequestURI)
142150
req.SetHost(r.Host)
143151
req.Header.SetHost(r.Host)
152+
144153
for key, val := range r.Header {
145154
for _, v := range val {
146155
req.Header.Set(key, v)
147156
}
148157
}
158+
149159
if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil && err.(*net.AddrError).Err == "missing port in address" { //nolint:errorlint, forcetypeassert // overlinting
150160
r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80")
151161
}
162+
152163
remoteAddr, err := net.ResolveTCPAddr("tcp", r.RemoteAddr)
153164
if err != nil {
154165
http.Error(w, utils.StatusMessage(fiber.StatusInternalServerError), fiber.StatusInternalServerError)
155166
return
156167
}
157168

158-
// New fasthttp Ctx
159-
var fctx fasthttp.RequestCtx
169+
// New fasthttp Ctx from pool
170+
fctx := ctxPool.Get().(*fasthttp.RequestCtx) //nolint:forcetypeassert,errcheck // overlinting
171+
fctx.Response.Reset()
172+
fctx.Request.Reset()
173+
defer ctxPool.Put(fctx)
160174
fctx.Init(req, remoteAddr, nil)
175+
161176
if len(h) > 0 {
162177
// New fiber Ctx
163-
ctx := app.AcquireCtx(&fctx)
178+
ctx := app.AcquireCtx(fctx)
179+
defer app.ReleaseCtx(ctx)
180+
164181
// Execute fiber Ctx
165182
err := h[0](ctx)
166183
if err != nil {
167184
_ = app.Config().ErrorHandler(ctx, err) //nolint:errcheck // not needed
168185
}
169186
} else {
170187
// Execute fasthttp Ctx though app.Handler
171-
app.Handler()(&fctx)
188+
app.Handler()(fctx)
172189
}
173190

174-
// Convert fasthttp Ctx > net/http
191+
// Convert fasthttp Ctx -> net/http
175192
fctx.Response.Header.VisitAll(func(k, v []byte) {
176193
w.Header().Add(string(k), string(v))
177194
})

0 commit comments

Comments
 (0)