Horisontaalselt laiendatavaks loodud veebirakendused nõuavad sageli ühte või mitut koormuse tasakaalustamise sõlme. Nende peamine eesmärk on jaotada sissetulev liiklus õiglaselt kättesaadavate veebiserverite vahel. Võimalus suurendada veebirakenduse üldist võimsust lihtsalt sõlmede arvu suurendamise ja koormuse tasakaalustajate selle muutusega kohanemise abil võib osutuda tootmisel tohutult kasulikuks.
NGINX on veebiserver, mis pakub paljude muude võimaluste hulgas ka suure jõudlusega koormuse tasakaalustamise funktsioone. Mõned neist funktsioonidest on saadaval ainult nende tellimusmudeli osana, kuid tasuta ja avatud lähtekoodiga versioon on endiselt väga funktsioonirikas ja kaasas kõige olulisemad koormuse tasakaalustamise funktsioonid.
Selles õpetuses uurime seadme sisemist mehaanikat eksperimentaalne tööriist see võimaldab teil NGINX-i eksemplari lennult konfigureerida, et see toimiks koormuse tasakaalustajana, eemaldades NGINX-i konfiguratsioonifailide kõik üksikasjad, pakkudes korraliku veebipõhise kasutajaliidese. Selle artikli eesmärk on näidata, kui lihtne on sellise tööriista ehitamist alustada. Tasub mainida, et projekt Loadcat on suuresti inspireeritud Linode oma NodeBalancers .
NGINXi üks populaarsemaid kasutusvõimalusi on klientide taotluste pöördproksimine veebiserveri rakendustesse. Ehkki programmeerimiskeeltes nagu Node.js ja Go välja töötatud veebirakendused võivad olla isemajandavad veebiserverid, pakub vastupidise puhverserveri olemasolu tegeliku serverirakenduse ees mitmeid eeliseid. Sellise lihtsa kasutusjuhtumi serveri plokk NGINX-i konfiguratsioonifailis võib välja näha umbes selline:
server { listen 80; server_name example.com; location / { proxy_pass http://192.168.0.51:5000; } }
See paneks NGINXi kuulama pordis 80 kõiki päringuid, mis on viidatud saidile example.com, ja edastama need kõik mõnele veebiserveri rakendusele, mis töötab aadressil 192.168.0.51:5000. Kui veebirakendusserver töötab lokaalselt, võiksime siin kasutada ka loopbacki IP-aadressi 127.0.0.1. Pange tähele, et ülaloleval koodilõigul puuduvad mõned ilmsed näpunäited, mida sageli kasutatakse puhverserveri konfiguratsioonis, kuid seda hoitakse lühiduse huvides.
Aga mis oleks, kui me tahaksime tasakaalustada kõiki sissetulevaid taotlusi sama veebirakendusserveri kahe eksemplari vahel? Siinkohal muutub kasulik “ülesvoolu” käsitlev direktiiv. NGINX-is on 'ülesvoolu' direktiiviga võimalik määratleda mitu taustsõlme, mille vahel NGINX tasakaalustab kõiki sissetulevaid taotlusi. Näiteks:
upstream nodes { server 192.168.0.51:5000; server 192.168.0.52:5000; } server { listen 80; server_name example.com; location / { proxy_pass http://nodes; } }
Pange tähele, kuidas me määratlesime kahest serverist koosneva ploki nimega „sõlmed“. Iga serveri tuvastab IP-aadress ja pordi number, mida nad kuulavad. Sellega saab NGINX-st koormuse tasakaalustaja oma lihtsal kujul. Vaikimisi jaotab NGINX sissetulevad päringud ringkäigul, kus esimene on puhverdatud esimese serveri, teine teise serveri, kolmas esimese serveri ja nii edasi.
NGINXil on aga koormuse tasakaalustamise osas palju rohkem pakkuda. See võimaldab teil määratleda iga serveri kaalu, märkida need ajutiselt kättesaamatuks, valida teise tasakaalustusalgoritmi (nt on üks, mis töötab kliendi IP-räsi põhjal) jne. Need funktsioonid ja seadistamisjuhised on kõik kenasti dokumenteeritud aadressil nginx.org . Lisaks võimaldab NGINX peaaegu ilma katkestusteta konfiguratsioonifaile käigu pealt muuta ja uuesti laadida.
NGINX-i konfigureeritavus ja lihtsad konfiguratsioonifailid muudavad selle paljudele vajadustele kohandamise väga lihtsaks. Ja ohtralt õpetusi juba olemas Internetis, mis õpetavad täpselt, kuidas NGINX-i koormuse tasakaalustajana konfigureerida.
Programmides on midagi põnevat, mis selle asemel, et midagi ise teha, konfigureerige nende jaoks teiste tööriistade loomiseks. Nad ei tee tegelikult midagi muud, kui võib-olla võtavad kasutaja sisendeid ja loovad mõne faili. Enamik neist tööriistadest saadavatest eelistest on tegelikult muude tööriistade omadused. Kuid need muudavad elu kindlasti lihtsaks. Ühe oma projekti jaoks koormuse tasakaalustaja seadistamisel mõtlesin: miks mitte teha midagi sarnast NGINXi ja selle koormuse tasakaalustamise võimaluste jaoks?
Koormakass sündis!
Loadcat, ehitatud koos Mine , on alles lapsekingades. Praegu võimaldab tööriist NGINX-i konfigureerida ainult koormuse tasakaalustamiseks ja SSL-i lõpetamiseks. See pakub lihtsat veebipõhist Kasutaja GUI . Selle asemel, et käia läbi tööriista üksikute funktsioonide, heitkem pilk selle alla, mis seal all on. Pange tähele, et kui kellelegi meeldib NGINX-i konfiguratsioonifailidega käsitsi töötada, võib ta sellises tööriistas vähe väärtust leida.
Go'i valimiseks selle programmeerimiskeeleks on mõned põhjused. Üks neist on see, et Go toodab kompileeritud kahendfaile. See võimaldab meil koostada ja levitada või juurutada Loadcati kompileeritud kahendkoodina kaugserveritesse, muretsemata sõltuvuste lahendamise pärast. Midagi, mis lihtsustab seadistamisprotsessi oluliselt. Muidugi eeldab binaarne, et NGINX on juba installitud ja selle jaoks on olemas systemd üksuse fail.
Juhul kui te pole a Minge inseneriks , ärge muretsege üldse. Mine on üsna lihtne ja lõbus alustamiseks. Pealegi on rakendamine ise väga lihtne ja peaksite saama hõlpsalt kaasa minna.
Rakenduse Go build tööriistad seavad mõned piirangud rakenduse struktureerimisele ja ülejäänud jätavad arendaja hooleks. Meie puhul oleme jaotanud asjad mõneks Go paketiks nende eesmärkide põhjal:
Kui vaatame pakendi struktuuri lähemalt, eriti kasside paketis, märkame, et kogu NGINX-i spetsiifiline kood on hoitud kasside / nginxi alampaketis. Seda tehakse selleks, et saaksime ülejäänud rakenduse loogika üldisena hoida ja laiendada teiste koormuse tasakaalustajate (nt HAProxy) tuge tulevikus.
Alustame Loadcati põhipaketist, mis asub kataloogis „cmd / loadcatd”. Põhifunktsioon, rakenduse sisestuspunkt, teeb kolme asja.
func main() { fconfig := flag.String('config', 'loadcat.conf', '') flag.Parse() cfg.LoadFile(*fconfig) feline.SetBase(filepath.Join(cfg.Current.Core.Dir, 'out')) data.OpenDB(filepath.Join(cfg.Current.Core.Dir, 'loadcat.db')) defer data.DB.Close() data.InitDB() http.Handle('/api', api.Router) http.Handle('/', ui.Router) go http.ListenAndServe(cfg.Current.Core.Address, nil) // Wait for an “interrupt“ signal (Ctrl+C in most terminals) }
Asjade lihtsuse ja koodi hõlpsama loetavuse huvides on ülaltoodud koodilõigust (ja ka käesolevas artiklis toodud juppidest) eemaldatud kogu veakäsitluskood.
Nagu koodist aru saate, laadime konfiguratsioonifaili käsurea lipul „-config” (mis praeguses kataloogis on vaikimisi „loadcat.conf”). Järgmisena lähtestame paari komponenti, nimelt kasside põhipaketti ja andmebaasi. Lõpuks alustame veebipõhise GUI jaoks veebiserverit.
Konfiguratsioonifaili laadimine ja parsimine on siin ilmselt kõige lihtsam osa. Konfiguratsiooniteabe kodeerimiseks kasutame TOML-i. Go jaoks on saadaval korralik TOML-i sõelumispakett. Vajame kasutajalt väga vähe konfiguratsiooniteavet ja enamasti saame nende väärtuste jaoks mõistlikud vaikeväärtused kindlaks määrata. Järgnev struktuur tähistab konfiguratsioonifaili struktuuri:
struct { Core struct { Address string Dir string Driver string } Nginx struct { Mode string Systemd struct { Service string } } }
Ja siin võib tüüpiline fail „loadcat.conf” välja näha:
[core] address=':26590' dir='/var/lib/loadcat' driver='nginx' [nginx] mode='systemd' [nginx.systemd] service='nginx.service'
Nagu näeme, on TOML-i kodeeritud konfiguratsioonifaili struktuur sarnasus struktuur selle kohal näidatud. Konfiguratsioonipakett algab mõne mõistliku vaikesätte määramisega struktuur ja sõelub seejärel selle üle konfiguratsioonifaili. Juhul kui see ei leia määratud teelt konfiguratsioonifaili, loob ta selle ja viskab selles kõigepealt vaikeväärtused.
func LoadFile(name string) error { f, _ := os.Open(name) if os.IsNotExist(err) { f, _ = os.Create(name) toml.NewEncoder(f).Encode(Current) f.Close() return nil } toml.NewDecoder(f).Decode(&Current) return nil }
Saage kokku Polt . Manustatud võtme / väärtuste salvestus, mis on kirjutatud puhta Go-ga. See on väga lihtsa API-ga pakett, toetab tehinguid kastist välja ja on häirivalt kiiresti.
Pakettandmete sees oleme struktuurid esindavad igat tüüpi üksusi. Näiteks on meil:
type Balancer struct { Id bson.ObjectId Label string Settings BalancerSettings } type Server struct { Id bson.ObjectId BalancerId bson.ObjectId Label string Settings ServerSettings }
... kus näiteks Tasakaalustaja tähistab ühte koormuse tasakaalustajat. Loadcat võimaldab tõhusalt tasakaalustada mitme veebirakenduse taotlusi ühe NGINX-i eksemplari kaudu. Igal tasakaalustajal võib siis olla taga üks või mitu serverit, kus iga server võib olla eraldi taustsõlm.
Kuna Bolt on võtmeväärtuste salvestus ja see ei toeta täpsemaid andmebaasipäringuid, on meil rakendusepõhine loogika, mis teeb seda meie eest. Loadcat ei ole mõeldud tuhandete tasakaalustajate konfigureerimiseks koos tuhandete serveritega igas neist, nii et loomulikult töötab see naiivne lähenemine suurepäraselt. Samuti töötab Bolt võtmete ja väärtustega, mis on baidiviilud, ja seetõttu kodeerime BSON-i struktuurid enne nende Boltis hoidmist. Funktsiooni rakendamine, mis otsib loendi Tasakaalustaja juhib andmebaasist on näidatud allpool:
func ListBalancers() ([]Balancer, error) { bals := []Balancer{} DB.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte('balancers')) c := b.Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { bal := Balancer{} bson.Unmarshal(v, &bal) bals = append(bals, bal) } return nil }) return bals, nil }
ListBalancers Funktsioon käivitab kirjutuskaitstud tehingu, kordab kõik võtmed ja väärtused „tasakaalustajate” ämbris, dekodeerib iga väärtuse eksemplariks Tasakaalustaja struktuur ja tagastab need massiivi.
Tasakaalustaja hoidmine ämbris on peaaegu sama lihtne:
func (l *Balancer) Put() error { if !l.Id.Valid() { l.Id = bson.NewObjectId() } if l.Label == '' { l.Label = 'Unlabelled' } if l.Settings.Protocol == 'https' { // Parse certificate details } else { // Clear fields relevant to HTTPS only, such as SSL options and certificate details } return DB.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte('balancers')) p, err := bson.Marshal(l) if err != nil { return err } return b.Put([]byte(l.Id.Hex()), p) }) }
The Pane funktsioon määrab teatud väljadele mõned vaikeväärtused, sõelub lisatud SSL-sertifikaati HTTPS-i seadistuses, alustab tehingut, kodeerib struktuur ja salvestab selle ämbrisse tasakaalustaja ID-le.
SSL-sertifikaadi sõelumisel eraldatakse kasutades kahte teavet standardne pakettkodeering / pem ja salvestatud SSLValikud all Seaded väli: DNS-i nimed ja sõrmejälg.
Meil on ka funktsioon, mis otsib servereid tasakaalustaja järgi:
func ListServersByBalancer(bal *Balancer) ([]Server, error) { srvs := []Server{} DB.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte('servers')) c := b.Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { srv := Server{} bson.Unmarshal(v, &srv) if srv.BalancerId.Hex() != bal.Id.Hex() { continue } srvs = append(srvs, srv) } return nil }) return srvs, nil }
See funktsioon näitab, kui naiivne on meie lähenemine tegelikult. Siin loeme tõhusalt kogu 'serverite' rühma ja filtreerime ebaolulised üksused enne massiivi tagastamist. Kuid jällegi töötab see lihtsalt hästi ja selle muutmiseks pole reaalset põhjust.
The Pane serverite funktsioon on palju lihtsam kui Tasakaalustaja struktuur kuna see ei nõua nii palju koodiseadete ridu vaikeväärtusi ja arvutatud välju.
Enne Loadcati kasutamist peame NGINX-i konfigureerima genereeritud konfiguratsioonifailide laadimiseks. Loadcat genereerib iga tasakaalustaja jaoks faili nginx.conf kataloogi järgi tasakaalustaja ID abil (lühike kuusnurkne string). Need kataloogid luuakse kataloogi 'välja' all cwd
. Seetõttu on oluline, et seadistaksite NGINX-i nende loodud konfiguratsioonifailide laadimiseks. Seda saab teha plokis „http” oleva „include” -direktiivi abil:
Redigeerige /etc/nginx/nginx.conf ja lisage järgmine rida ploki “http” lõppu:
http { include /path/to/out/*/nginx.conf; }
See paneb NGINX-i skannima kõiki kataloogist / / path / to / out / leitud katalooge, otsima igas kataloogis faile nimega 'nginx.conf' ja laadima üles kõik leitud failid.
Meie põhipaketis kasside määratleme liidese Autojuht . Ükskõik struktuur mis pakub kahte funktsiooni, Loo ja Laadige uuesti , õige allkirjaga, kvalifitseerub autojuhiks.
type Driver interface { Generate(string, *data.Balancer) error Reload() error }
Näiteks struktuur Nginx kasside / nginxi pakendite all:
type Nginx struct { sync.Mutex Systemd *dbus.Conn } func (n Nginx) Generate(dir string, bal *data.Balancer) error { // Acquire a lock on n.Mutex, and release before return f, _ := os.Create(filepath.Join(dir, 'nginx.conf')) TplNginxConf.Execute(f, /* template parameters */) f.Close() if bal.Settings.Protocol == 'https' { // Dump private key and certificate to the output directory (so that Nginx can find them) } return nil } func (n Nginx) Reload() error { // Acquire a lock on n.Mutex, and release before return switch cfg.Current.Nginx.Mode { case 'systemd': if n.Systemd == nil { c, err := dbus.NewSystemdConnection() n.Systemd = c } ch := make(chan string) n.Systemd.ReloadUnit(cfg.Current.Nginx.Systemd.Service, 'replace', ch) <-ch return nil default: return errors.New('unknown Nginx mode') } }
Loo saab käivitada stringiga, mis sisaldab väljundkataloogi teed ja kursorit a-le Tasakaalustaja struktureeritud eksemplar. Go pakub tekstimallide jaoks standardset paketti, mida NGINX-draiver kasutab lõpliku NGINX-i konfiguratsioonifaili loomiseks. Mall koosneb 'ülesvoolu' plokist, millele järgneb 'serveri' plokk, mis on loodud tasakaalustaja seadistamise põhjal:
var TplNginxConf = template.Must(template.New('').Parse(` upstream {{.Balancer.Id.Hex}} { {{if eq .Balancer.Settings.Algorithm 'least-connections'}} least_conn; {{else if eq .Balancer.Settings.Algorithm 'source-ip'}} ip_hash; {{end}} {{range $srv := .Balancer.Servers}} server {{$srv.Settings.Address}} weight={{$srv.Settings.Weight}} {{if eq $srv.Settings.Availability 'available'}}{{else if eq $srv.Settings.Availability 'backup'}}backup{{else if eq $srv.Settings.Availability 'unavailable'}}down{{end}}; {{end}} } server { {{if eq .Balancer.Settings.Protocol 'http'}} listen {{.Balancer.Settings.Port}}; {{else if eq .Balancer.Settings.Protocol 'https'}} listen {{.Balancer.Settings.Port}} ssl; {{end}} server_name {{.Balancer.Settings.Hostname}}; {{if eq .Balancer.Settings.Protocol 'https'}} ssl on; ssl_certificate {{.Dir}}/server.crt; ssl_certificate_key {{.Dir}}/server.key; {{end}} location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://{{.Balancer.Id.Hex}}; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; } } `))
Laadige uuesti on teine funktsioon sisse lülitatud Nginxi struktuur see paneb NGINX-i konfiguratsioonifailid uuesti laadima. Kasutatav mehhanism põhineb sellel, kuidas Loadcat on konfigureeritud. Vaikimisi eeldatakse, et NGINX on systemd-teenus, mis töötab kui nginx.service, nii et [sudo] systemd reload nginx.service
töötaks. Kuid shellikäsu käivitamise asemel loob see ühenduse süsteemiga D-bussi kaudu, kasutades pakett github.com/coreos/go-systemd/dbus .
Kui kõik need komponendid on paigas, ühendame selle kõik tavalise Bootstrapi kasutajaliidesega.
Nende põhifunktsioonide jaoks piisab mõnest lihtsast GET- ja POST-marsruudi käitlejast:
GET /balancers GET /balancers/new POST /balancers/new GET /balancers/{id} GET /balancers/{id}/edit POST /balancers/{id}/edit GET /balancers/{id}/servers/new POST /balancers/{id}/servers/new GET /servers/{id} GET /servers/{id}/edit POST /servers/{id}/edit
Iga üksiku marsruudi läbimine ei pruugi siin olla kõige huvitavam, kuna need on üsna CRUD-lehed. Võite täiesti vabalt piiluda paketi ui kood et näha, kuidas nende marsruutide käitlejad on rakendatud.
Iga käitleja funktsioon on rutiin, mis kas:
Näiteks:
func ServeServerNewForm(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bal, _ := data.GetBalancer(bson.ObjectIdHex(vars['id'])) TplServerNewForm.Execute(w, struct { Balancer *data.Balancer }{ Balancer: bal, }) } func HandleServerCreate(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) bal, _ := data.GetBalancer(bson.ObjectIdHex(vars['id'])) r.ParseForm() body := struct { Label string `schema:'label'` Settings struct { Address string `schema:'address'` } `schema:'settings'` }{} schema.NewDecoder().Decode(&body, r.PostForm) srv := data.Server{} srv.BalancerId = bal.Id srv.Label = body.Label srv.Settings.Address = body.Settings.Address srv.Put() feline.Commit(bal) http.Redirect(w, r, '/servers/'+srv.Id.Hex()+'/edit', http.StatusSeeOther) }
Kõik ServeeriServerNewForm Funktsioon on see, et see tõmbab tasakaalustaja andmepoest ja renderdab malli, TplServerList mis sel juhul otsib asjakohaste serverite loendi, kasutades Serverid funktsioon tasakaalustajal.
HandleServerCreate funktsioon aga sõelub sissetuleva POST-i kasuliku koormuse kehast a-ks struktuur ja kasutab neid andmeid uue loomiseks ja säilitamiseks Serveri struktuur enne paketi feline kasutamist tasakaalustaja NGINX-i konfiguratsioonifaili taastamiseks andmepoes.
Kõik lehemallid on salvestatud faili „ui / templates.go” ja vastavad HTML-vormingus mallifailid leiate kataloogist „ui / templates”.
Loadcati juurutamine kaugserverisse või isegi kohalikku keskkonda on ülilihtne. Kui kasutate Linuxi (64-bitine), saate hoidlast hankida eelnevalt koostatud binaarse Loadcati arhiivi Väljalasete jaotis . Kui tunnete end veidi seikluslikult, võite kloonida hoidla ja ise koodi kokku panna. Kuigi kogemus võib sellisel juhul olla natuke pettumus kuna Go programmide koostamine pole tegelikult väljakutse. Ja kui teil on Arch Linux, siis on teil õnne! Mugavuse huvides on levitamiseks ehitatud pakett. Lihtsalt laadige see alla ja installige see oma paketihalduri abil. Asjakohased sammud on projekti üksikasjalikumalt välja toodud README.md fail .
Kui olete Loadcati konfigureerinud ja töötanud, suunake veebibrauser „http: // localhost: 26590” peale (eeldades, et see töötab kohalikult ja kuulab porti 26590). Järgmisena looge tasakaalustaja, looge paar serverit, veenduge, et nendes määratletud portides midagi kuulaks, ja voila, teil peaks olema jooksvate serverite vahel NGINX-i koormuse tasakaalu sissetulevad päringud.
See tööriist pole kaugeltki täiuslik ja tegelikult on see üsna eksperimentaalne projekt. See tööriist ei hõlma isegi kõiki NGINX-i põhifunktsioone. Näiteks kui soovite vahemällu salvestada kihi NGINX taustsõlmede teenindatavad varad, peate ikkagi NGINX-i konfiguratsioonifaile käsitsi muutma. Ja see teebki asja põnevaks. Siin on võimalik palju ära teha ja see on täpselt järgmine: hõlmab veelgi enam NGINXi koormuse tasakaalustamise funktsioone - põhilisi ja tõenäoliselt isegi neid, mida NGINX Plus pakub.
Proovige Loadcati. Kontrollige koodi, hargitage see, muutke seda, mängige sellega. Samuti andke meile teada, kui olete loonud tööriista, mis konfigureerib muu tarkvara, või olete kasutanud seda, mis teile allpool kommentaaride jaotises väga meeldib.