Speed up the monolith building a smart reverse proxy in Go - - PowerPoint PPT Presentation

speed up the monolith
SMART_READER_LITE
LIVE PREVIEW

Speed up the monolith building a smart reverse proxy in Go - - PowerPoint PPT Presentation

Speed up the monolith building a smart reverse proxy in Go Alessio Caiazza Senior Backend Engineer, Infrastructure GitLab @nolith - alessio@gitlab.com Photo by Joseph Barrientos on Unsplash Photo by Timur M on Unsplash We are a Ruby shop


slide-1
SLIDE 1

Speed up the monolith

building a smart reverse proxy in Go

slide-2
SLIDE 2

Alessio Caiazza

Senior Backend Engineer, Infrastructure GitLab

@nolith - alessio@gitlab.com

slide-3
SLIDE 3

Photo by Joseph Barrientos on Unsplash

slide-4
SLIDE 4

Photo by Timur M on Unsplash

slide-5
SLIDE 5

We are a Ruby shop

Why Go ?

slide-6
SLIDE 6

Slow requests

slide-7
SLIDE 7

unicorn

Rack HTTP server for fast clients and Unix

unicorn is an HTTP server for Rack applications designed to only serve fast clients on low-latency, high-bandwidth connections and take advantage of features in Unix/Unix-like kernels. — bogomips.org/unicorn

slide-8
SLIDE 8
slide-9
SLIDE 9

Workhorse

a smart reverse proxy

slide-10
SLIDE 10

package main import ( "log" "net/http" "net/http/httputil" "net/url" ) func main() { upstream, err := url.Parse("https://httpbin.org") if err != nil { log.Fatal(err) } proxy := httputil.NewSingleHostReverseProxy(upstream) err = http.ListenAndServe(":8080", proxy) log.Fatal(err) }

slide-11
SLIDE 11

Speed up a slow request

slide-12
SLIDE 12

func main() { r := mux.NewRouter() // import "github.com/gorilla/mux" r.Use(proxyHeadersMiddleware) r.HandleFunc("/slow", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Now faster!")) }) upstream, err := url.Parse("https://httpbin.org") if err != nil { log.Fatal(err) } proxy := httputil.NewSingleHostReverseProxy(upstream) r.PathPrefix("/").Handler(proxy) err = http.ListenAndServe(":8080", r) log.Fatal(err) } func proxyHeadersMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { r.Header.Set("X-Forwarded-For", r.RemoteAddr) r.Header.Set("X-Forwarded-Proto", r.URL.Scheme) r.Header.Set("X-Forwarded-Host", r.Header.Get("Host")) next.ServeHTTP(w, r) }) }

slide-13
SLIDE 13

Speed up git

! Slow request

slide-14
SLIDE 14

Body Hijacking

slide-15
SLIDE 15
slide-16
SLIDE 16

Speed up uploads

! Slow request

slide-17
SLIDE 17

Cloud native charts

and

Network File System

slide-18
SLIDE 18
slide-19
SLIDE 19
slide-20
SLIDE 20
slide-21
SLIDE 21

Object Storage in Workhorse !

NFS

slide-22
SLIDE 22

git LFS

slide-23
SLIDE 23

io package

io.Reader | io.Writer = ❤

slide-24
SLIDE 24 // install route with r.Handle("/upload/{file}", body.HijackHandler(proxy)).Methods("PUT") func HijackHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { presigned, err := api.AuthorizeUpload(r) if err != nil { http.Error(w, err.Error(), 503) return } upload, err := http.NewRequest("POST", presigned.String(), ioutil.NopCloser(r.Body)) if err != nil { http.Error(w, err.Error(), 500) return } upload.ContentLength = r.ContentLength resp, err := http.DefaultClient.Do(upload) if err != nil { http.Error(w, err.Error(), 503) return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { http.Error(w, resp.Status, 503) return } toProxy := r.Clone(r.Context()) toProxy.Body = nil toProxy.ContentLength = 0 toProxy.Header.Set("X-My-File-Path", presigned.Path) // sign this next.ServeHTTP(w, toProxy) }) }
slide-25
SLIDE 25

Mission Complete!

slide-26
SLIDE 26

Mission Complete!

Not exactly

slide-27
SLIDE 27

Unknown length requests

from

~35k CI runners

slide-28
SLIDE 28

Multipart Upload

divide and upload

slide-29
SLIDE 29

Keep memory usage under control

process a chunk at time

slide-30
SLIDE 30

Photo by Bobby Burch on Unsplash

slide-31
SLIDE 31

Thanks!

✴ You can speed up a web application writing a reverse proxy in Go ✴ An iterative approach ✴ Rewrite only slow endpoints ✴ Forward to another service if needed ✴ Sign modified requests Workhorse source code is available at gitlab.com/ gitlab-org/gitlab-workhorse under MIT license.

@nolith - alessio@gitlab.com