Go - Googles Sprache für skalierbare Systeme

683 Aufrufe

Veröffentlicht am

Talk about Google Go given at the DevOpsCon 2015 in Berlin.

Veröffentlicht in: Software
0 Kommentare
1 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

Keine Downloads
Aufrufe
Aufrufe insgesamt
683
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
4
Aktionen
Geteilt
0
Downloads
3
Kommentare
0
Gefällt mir
1
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

Go - Googles Sprache für skalierbare Systeme

  1. 1. Go - Googles Sprache
 für skalierbare Systeme
  2. 2. Frank Müller Oldenburg Baujahr 1965 Entwickler Fachautor frank.mueller@canonical.com @themue
  3. 3. Parallelität oder Nebenläufigkeit?
  4. 4. ❝Parallelism Programming as the simultaneous execution of (possibly related) computations. Concurrency Programming as the composition of independently executing processes. Rob Pike
  5. 5. Sieh, wie wirdies nutzen ...
  6. 6. Bereitgestellte Infrastruktur ...
  7. 7. ... ist nichts ohne bereitgestellte Dienste
  8. 8. mysql wordpress Bekanntes Szenario auf individuellen Servern
  9. 9. Höhere Komplexität in Clouds wordpress mediawikihaproxy-w mediawiki memcached haproxy-b wordpress mysql wordpressvarnish
  10. 10. Ein mühsamer Weg
  11. 11. Juju - Open Source Tool zur Automatisierung von Clouds http://jujucharms.com
  12. 12. Plattformen
  13. 13. Plattformen mediawiki wordpress AWS Azure OpenStack Joyent ... haproxy-w mediawiki memcached haproxy-b wordpress mysql wordpressvarnish
  14. 14. juju generate-config juju bootstrap Bootstrap
  15. 15. Bootstrap API State Provisioner ... Zentrale Funktionen
  16. 16. Provisionierung
  17. 17. juju deploy juju-gui juju deploy wordpress juju deploy mysql juju expose juju-gui Bootstrap juju-gui wordpress mysql
  18. 18. Relationen
  19. 19. juju add-relation wordpress mysql juju expose wordpress Bootstrap juju-gui wordpress mysql
  20. 20. Konfiguration
  21. 21. juju set mysql dataset-size=50% juju set wordpress tuning=optimized Bootstrap juju-gui wordpress* mysql*
  22. 22. Skalieren
  23. 23. juju deploy memcached juju add-relation wordpress memcached juju add-unit wordpress wordpress* Bootstrap juju-gui wordpress* mysql* memcached
  24. 24. Varianten
  25. 25. Unit Unit Unter- geordnete Unit Unit Unit Unit Container Direkte Abhängigkeit Standard
  26. 26. Einige Charms ceph mediawiki mongodb cassandra rails mysql wordpress rabbitmq haproxy apache2 hadoop squid hbase couchdb postgresql nfs ntp
  27. 27. Viel Spaß in den Wolken
  28. 28. Wie hilft uns Google Go hier?
  29. 29. Moderne Mehrkernsysteme sind
 wie die Vereinigung von Flüssen
  30. 30. Ihre Energie gilt es
 effizient zu nutzen
  31. 31. Google Go als Multi-Paradigmen-Sprache imperativ bedingt funktional bedingt objektorientiert nebenläufig
  32. 32. ❝It’s better to have a
 permanent income
 than to be
 fascinating. Oscar Wilde
  33. 33. Nebenläufigkeit in Go • Leichtgewichtige Goroutines im Thread Pool • Sehr große Anzahl gleichzeitig möglich • Kommunikation und Synchronisation über Channels • Vielfältige Kontrolle durch select Statement
  34. 34. Kapselung in Typen package service type Service struct { thisChan chan *This thatChan chan *That foo bool bar int baz string }
  35. 35. Konstruktoren sind Funktionen func NewService(...) *Service { s := &Service{ thisChan: make(chan *This), thatChan: make(chan *That, 10), …, } // Start of the backend loop as goroutine. go s.loop() return s }
  36. 36. Endlosschleifen und select func (s *Service) loop() { ticker := time.NewTicker(time.Second) for { select { case this := <-s.thisChan: s.doThis(this) case that := <-s.thatChan: s.doThat(that) case <-ticker.C: s.doTick() } } }
  37. 37. Methoden als externe Schnittstellen func (s *Service) DoThis(data string) int { respChan := make(chan int) this := &This{data, respChan} s.thisChan <- this return <-respChan }
  38. 38. Beispiel: Goroutines als Server Client Client Client Server
  39. 39. Beispiel: Lastverteilung Client Client Worker Worker Worker Master
  40. 40. Netze von Goroutines A C D GFEB E1 E2 E3
  41. 41. Goroutines können eigene Wege
 gehen …
  42. 42. … oder gemeinsame
  43. 43. Ein Wimmeln wie im Bienenstock
  44. 44. Einblicke in die Juju Architektur
  45. 45. State - Watcher - Worker State API Networker Provisioner Uniter Deployer ... ! Collections Individuelle Objekte Lebenszyklen Client
  46. 46. Lauter nebenläufige Arbeit Agent State Worker Goroutine Goroutine Worker Goroutine Goroutine Worker Goroutine Goroutine
  47. 47. Beispiel Firewaller unitd Loop unitd Loop machined Loop State Main Loop machined Loop unitd Loop serviced Loop Environment Configuration Machines Machine Units Exposes Ports
  48. 48. Herausforderungen nebenläufiger Anwendungen Rechenleistung nutzen Rennen kontrollieren Konflikte vermeiden Probleme abfedern
  49. 49. Sehr naives Parallelisieren (1) func process(in []int) []int { resultChan := make(chan int) for _, value := range in { // One goroutine per value. go processValue(value, resultChan) } // Collecting the results. out := make([]int, len(in)) for i := 0; i < len(in); i++ { out[i] = <-resultChan } return out }
  50. 50. Sehr naives Parallelisieren (2) func processValue( inValue int, resultChan chan int) { // Time of result calculation may vary. outValue := inValue … resultChan <- outValue }
  51. 51. Problem und Verbesserung • Unterschiedliche Laufzeiten führen zu falscher Indizierung im Ergebnis • Index in der Verarbeitung mitführen • Ergebnis gemäß Index setzen
  52. 52. Verbesserung (1) func process(in []int) []int { resultChan := make(chan *result) for index, value := range in { // One goroutine per value. go processValue(index, value, resultChan) } out := make([]int, len(in)) for i := 0; i < len(in); i++ { result <- resultChan out[result.index] = result.value } return out }
  53. 53. Verbesserung (2) type result struct { index int value int } func processValue( index, inValue int, resultChan chan *result) { // Time of result calculation may vary. outValue := inValue … // Send index with result. resultChan <- &result{index, outValue} }
  54. 54. Isolierung von Zugriffen • Loops serialisieren Zugriffe • Synchronisation über Channels oder Package sync • Referenzen nur an eine Goroutine senden • Aufteilung von Arrays und Slices
  55. 55. Arbeitsteilung (1) // Process all data passed by reference. func process(ds []*Data) { var wg sync.WaitGroup for i := 0; i < len(ds); i += chunkSize { // Process one chunk in the background. go processChunk(ds[i:i+chunkSize], wg) } // Wait for all processing to complete. wg.Wait() }
  56. 56. Arbeitsteilung (2) // Processing a chunk of data passed by reference. func processChunk(ds []*Data, wg sync.WaitGroup) { // Increment WaitGroup counter and signal when done. wg.Add(1) defer wg.Done() // Process each data. for _, d := range ds { if d != nil { // Direct manipulation. d.Foo = ... ... } } }
  57. 57. Kontrolle von Goroutines • Keine direkte Beziehung zwischen Goroutines • Kontrolle nur über Channels • Externe Packages helfen • gopkg.in/tomb.v2 • github.com/tideland/goas/v2/loop
  58. 58. Operation in einer Schleife func (t *T) loop() { defer t.tomb.Done() for { select { case <-t.tomb.Dying(): // Cleanup ... return case f := <-t.fooChan: if err := t.foo(f); err != nil { t.tomb.Kill(err) } case b := <-t.barChan: // ... } } }
  59. 59. Steuerung von außen // Stop ends the main loop. func (t *T) Stop() error { // Kill(nil) means no error as reason. t.tomb.Kill(nil) return t.tomb.Wait() } // Err retrieves the error in case the backend loop died. func (t *T) Err() error { return t.tomb.Err() }
  60. 60. Prüfung des Backends func (t *T) Foo(foo *Foo) (*Bar, error) { env := &fooEnv{foo, make(chan *Bar)} select { case t.fooChan <- env: case <-t.tomb.Dead(): return nil, errors.New("backend dead") } select { case bar := <- env.barChan: return bar, nil case <-t.tomb.Dead(): return nil, errors.New("backend dead") } }
  61. 61. Schnittstellen
  62. 62. Flexible Nutzung • Nur Deklaration • Einbettung in umfassendere Interfaces • Implizites Duck Typing • Anwendbar auf jede Typdefination
  63. 63. Verhalten definieren und kombinieren type StorageReader interface { Get(name string) (io.ReadCloser, error) List(prefix string) ([]string, error) URL(name string) (string, error) } type StorageWriter interface { Put(name string, r io.Reader, length int64) error Remove(name string) error } type Storage interface { StorageReader StorageWriter }
  64. 64. Teilnutzung möglich // Only the writing is needed. func Write(sw StorageWriter) error { ... return sw.Put(myName, myReader, myLen) } // Full storage access here. func RemoveFirst(s Storage, prefix string) error { l, err := s.List(prefix) if err != nil { return err } return s.Remove(l[0]) }
  65. 65. Implementierung pro Provider Environ Storage Azure AWS MAAS OpenStack ...
  66. 66. Vernetzung
  67. 67. Hilfreiche Packages • net, …/http für IP und Web • html/template, mime/… für Inhalte • encoding/gob, …/json, …/xml für die Serialisierung • compress/… zur Komprimierung • crypto/… zur Verschlüsselung
  68. 68. Externe Packages von Google • WebSocket, SPDY, Dict und mehr in golang.org/x/net • Weitere Crypto Packages (u.a. OpenPGP) in golang.org/x/crypto
  69. 69. Serialisierung via JSON type Parameters map[string]interface{} type Action struct { Tag string `json:"tag"` Receiver string `json:"receiver"` Name string `json:"name"` Parameters Parameters `json:"parameters,omitempty"` }
  70. 70. Marshalling action := Action{ Tag: "FooBar", … Paramaters: Parameters{"foo": 4711, "bar": true}, } marshalledAction, err := json.Marshal(action) if err != nil { … } n, err := anyWriter.Write(marshalledAction)
  71. 71. Unmarshalling var action Action err := json.Unmarshal(marshalledAction, &action) if err != nil { … } fmt.Printf("Tag: %sn", action.Tag)
  72. 72. API in Juju Netz und Crypto Reflection für Dispatching WebSockets Serialisierung via JSON
  73. 73. Bildquellen 123RF iStockphoto eigene Quellen

×