Skip to content

Commit

Permalink
use readerfrom optimization by forking Go reverseproxy
Browse files Browse the repository at this point in the history
This PR also updates dependencies, credits and also
does not treat idle connection errors as backend down
  • Loading branch information
harshavardhana committed Sep 7, 2023
1 parent 9c30de3 commit 88013c6
Show file tree
Hide file tree
Showing 12 changed files with 2,841 additions and 243 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
go-version: [1.20.x]
go-version: [1.21.x]
os: [ubuntu-latest]
steps:
- name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/vulncheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [ 1.20.x ]
go-version: [ 1.21.1 ]
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*~
sidekick
dist/
*.test
*.test
2 changes: 2 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ issues:
exclude:
- should have a package comment
- error strings should not be capitalized or end with punctuation or a newline
- http.CloseNotifier has been deprecated since
- has been deprecated since Go 1.6
service:
golangci-lint-version: 1.45.2 # use the fixed version to not introduce new linters unexpectedly
1,010 changes: 839 additions & 171 deletions CREDITS

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ require (
github.com/minio/cli v1.24.2
github.com/minio/dnscache v0.1.1
github.com/minio/pkg v1.6.5
github.com/minio/pkg/v2 v2.0.0
github.com/prometheus/client_golang v1.15.0
github.com/rivo/tview v0.0.0-20230406072732-e22ce9588bb4
github.com/sirupsen/logrus v1.9.0
go.uber.org/atomic v1.10.0
golang.org/x/sys v0.7.0
golang.org/x/term v0.7.0
golang.org/x/net v0.10.0
golang.org/x/sys v0.8.0
golang.org/x/term v0.8.0
)

require (
Expand All @@ -32,7 +34,7 @@ require (
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/minio/madmin-go/v2 v2.0.19 // indirect
github.com/minio/madmin-go/v3 v3.0.1 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.52 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
Expand All @@ -52,8 +54,7 @@ require (
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.8.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
Expand Down
22 changes: 12 additions & 10 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,16 @@ github.com/minio/cli v1.24.2 h1:J+fCUh9mhPLjN3Lj/YhklXvxj8mnyE/D6FpFduXJ2jg=
github.com/minio/cli v1.24.2/go.mod h1:bYxnK0uS629N3Bq+AOZZ+6lwF77Sodk4+UL9vNuXhOY=
github.com/minio/dnscache v0.1.1 h1:AMYLqomzskpORiUA1ciN9k7bZT1oB3YZN4cEIi88W5o=
github.com/minio/dnscache v0.1.1/go.mod h1:WCumm6offO4rQ/82oTCSoHnlhTmc81+vXgKpBtSYRbg=
github.com/minio/madmin-go/v2 v2.0.19 h1:XznxdMVCTyr0A88JrZFhdxWY8KLfJcrs0TTmFiE9cc8=
github.com/minio/madmin-go/v2 v2.0.19/go.mod h1:8bL1RMNkblIENFSgGYjeHrzUx9PxROb7OqfNuMU9ivE=
github.com/minio/madmin-go/v3 v3.0.1 h1:+WuNw0q8gYTNHUmV5X1nCox28uYmJkeMT75vh9VKPkA=
github.com/minio/madmin-go/v3 v3.0.1/go.mod h1:lPrMoc1aeiIWmmrxBthkDqzMPQwC/Lu9ByuyM2wenJk=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.52 h1:8XhG36F6oKQUDDSuz6dY3rioMzovKjW40W6ANuN0Dps=
github.com/minio/minio-go/v7 v7.0.52/go.mod h1:IbbodHyjUAguneyucUaahv+VMNs/EOTV9du7A7/Z3HU=
github.com/minio/pkg v1.6.5 h1:T9cRNcCLJTFFgQGH0Rzr1CtAWLAIchTsbE0lSztCf40=
github.com/minio/pkg v1.6.5/go.mod h1:0iX1IuJGSCnMvIvrEJauk1GgQSX9JdU6Kh0P3EQRGkI=
github.com/minio/pkg/v2 v2.0.0 h1:IbbRstuf4rCKuOlTaa/azoXXHME9XMAH6UBhKxRbRqM=
github.com/minio/pkg/v2 v2.0.0/go.mod h1:6xTAr5M9yobpUroXAAaTrGJ9fhOZIqKYOT0I87u2yZ4=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
Expand Down Expand Up @@ -124,17 +126,17 @@ go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -156,14 +158,14 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
Expand Down
20 changes: 6 additions & 14 deletions http-tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,14 @@ import (
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"strconv"
"strings"
"time"

"github.com/dustin/go-humanize"

"github.com/minio/pkg/console"
"github.com/minio/pkg/v2/console"
)

// recordRequest - records the first recLen bytes
Expand Down Expand Up @@ -87,6 +86,7 @@ type ResponseWriter struct {
// Internal recording buffer
headers bytes.Buffer
body bytes.Buffer

// Indicate if headers are written in the log
headersLogged bool
}
Expand Down Expand Up @@ -178,17 +178,14 @@ func (r *recordRequest) Data() []byte {
}

func traceHealthCheckReq(req *http.Request, resp *http.Response, reqTime, respTime time.Time, backend *Backend) {
ti := InternalTrace(req, resp, reqTime, respTime)
ti := InternalTrace(req, resp, reqTime, respTime, backend.endpoint)
doTrace(ti, backend)
}

// InternalTrace returns trace for sidekick http requests
func InternalTrace(req *http.Request, resp *http.Response, reqTime, respTime time.Time) TraceInfo {
func InternalTrace(req *http.Request, resp *http.Response, reqTime, respTime time.Time, endpoint string) TraceInfo {
t := TraceInfo{}
t.NodeName = req.Host
if host, _, err := net.SplitHostPort(t.NodeName); err == nil {
t.NodeName = host
}
t.NodeName = endpoint
reqHeaders := req.Header.Clone()
reqHeaders.Set("Host", req.Host)
if len(req.TransferEncoding) == 0 {
Expand Down Expand Up @@ -245,10 +242,6 @@ func Trace(f http.HandlerFunc, logBody bool, w http.ResponseWriter, r *http.Requ
t := TraceInfo{}
reqBodyRecorder = &recordRequest{Reader: r.Body, logBody: logBody, headers: reqHeaders}
r.Body = ioutil.NopCloser(reqBodyRecorder)
t.NodeName = r.Host
if host, _, err := net.SplitHostPort(t.NodeName); err == nil {
t.NodeName = host
}

rw := NewResponseWriter(w)
rw.LogBody = logBody
Expand Down Expand Up @@ -276,7 +269,6 @@ func Trace(f http.HandlerFunc, logBody bool, w http.ResponseWriter, r *http.Requ

t.ReqInfo = rq
t.RespInfo = rs

t.NodeName = endpoint
t.CallStats = traceCallStats{
Latency: rs.Time.Sub(rw.StartTime),
Expand Down Expand Up @@ -367,7 +359,7 @@ type shortTraceMsg struct {

func (s shortTraceMsg) String() string {
b := &strings.Builder{}
fmt.Fprintf(b, " %5s: ", TraceMsgType)
fmt.Fprintf(b, " %5s: ", LogMsgType)
fmt.Fprintf(b, "%s ", s.Time.Format(timeFormat))
statusStr := console.Colorize("RespStatus", fmt.Sprintf("%d %s", s.StatusCode, s.StatusMsg))
if s.StatusCode >= http.StatusBadRequest {
Expand Down
78 changes: 39 additions & 39 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"math/rand"
"net"
"net/http"
"net/http/httputil"
"net/http/pprof"
"net/url"
"os"
Expand All @@ -40,14 +39,15 @@ import (
"time"

"github.com/gorilla/mux"
"github.com/minio/dnscache"
"github.com/sirupsen/logrus"
"golang.org/x/term"

"github.com/minio/cli"
"github.com/minio/pkg/console"
"github.com/minio/pkg/ellipses"
xnet "github.com/minio/pkg/net"
"github.com/minio/dnscache"
"github.com/minio/pkg/v2/console"
"github.com/minio/pkg/v2/ellipses"
xnet "github.com/minio/pkg/v2/net"
"github.com/minio/sidekick/reverse"
)

// Use e.g.: go build -ldflags "-X main.version=v1.0.0"
Expand Down Expand Up @@ -146,7 +146,7 @@ func (l logMessage) String() string {
type Backend struct {
siteNumber int
endpoint string
proxy *httputil.ReverseProxy
proxy *reverse.Proxy
httpClient *http.Client
up int32
healthCheckURL string
Expand Down Expand Up @@ -198,11 +198,30 @@ type BackendStats struct {
// ErrorHandler called by httputil.ReverseProxy for errors.
// Avoid canceled context error since it means the client disconnected.
func (b *Backend) ErrorHandler(_ http.ResponseWriter, _ *http.Request, err error) {
if err != nil && !errors.Is(err, context.Canceled) {
if globalLoggingEnabled {
logMsg(logMessage{Endpoint: b.endpoint, Status: "down", Error: err})
if err != nil {
offline := true
for _, nerr := range []error{
context.Canceled,
io.EOF,
io.ErrClosedPipe,
io.ErrUnexpectedEOF,
errors.New("http: server closed idle connection"),
} {
if errors.Is(err, nerr) {
offline = false
break
}
if err.Error() == nerr.Error() {
offline = false
break
}
}
if offline {
if globalLoggingEnabled {
logMsg(logMessage{Endpoint: b.endpoint, Status: "down", Error: err})
}
b.setOffline()
}
b.setOffline()
}
}

Expand Down Expand Up @@ -273,6 +292,14 @@ func (b *Backend) healthCheck() {
}
}

func drainBody(resp *http.Response) {
if resp != nil {
// Drain the connection.
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}
}

func (b *Backend) doHealthCheck() error {
// Set up a maximum timeout time for the healtcheck operation
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
Expand All @@ -286,11 +313,7 @@ func (b *Backend) doHealthCheck() error {
reqTime := time.Now().UTC()
resp, err := b.httpClient.Do(req)
respTime := time.Now().UTC()
if err == nil {
// Drain the connection.
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}
drainBody(resp)
if err != nil || (err == nil && resp.StatusCode != http.StatusOK) {
if globalLoggingEnabled && (!b.Online() || b.Stats.UpSince.IsZero()) {
logMsg(logMessage{Endpoint: b.endpoint, Status: "down", Error: err})
Expand Down Expand Up @@ -588,28 +611,6 @@ func modifyResponse() func(*http.Response) error {
}
}

type bufPool struct {
pool sync.Pool
}

func (b *bufPool) Put(buf []byte) {
b.pool.Put(&buf)
}

func (b *bufPool) Get() []byte {
bufp := b.pool.Get().(*[]byte)
return *bufp
}

func newBufPool(sz int) httputil.BufferPool {
return &bufPool{pool: sync.Pool{
New: func() interface{} {
buf := make([]byte, sz)
return &buf
},
}}
}

// sortIPs - sort ips based on higher octects.
// The logic to sort by last octet is implemented to
// prefer CIDRs with higher octects, this in-turn skips the
Expand Down Expand Up @@ -731,7 +732,7 @@ func configureSite(ctx *cli.Context, siteNum int, siteStrs []string, healthCheck
// this is only used if r.RemoteAddr is localhost which means that
// sidekick endpoint being accessed is 127.0.0.x
realIP := getPublicIP()
proxy := &httputil.ReverseProxy{
proxy := &reverse.Proxy{
Director: func(r *http.Request) {
r.Header.Add("X-Forwarded-Host", r.Host)
host := realIP
Expand All @@ -744,7 +745,6 @@ func configureSite(ctx *cli.Context, siteNum int, siteStrs []string, healthCheck
r.URL.Host = target.Host
},
Transport: transport,
BufferPool: newBufPool(128 << 10),
ModifyResponse: modifyResponse(),
}
stats := BackendStats{MinLatency: 24 * time.Hour, MaxLatency: 0}
Expand Down
Loading

0 comments on commit 88013c6

Please sign in to comment.