go to the cloud
DESCRIPTION
TRANSCRIPT
Go to the Cloud
Frank Müller - Go to the Cloud 2
Baujahr 1965
Wohnhaft in Oldenburg
Software-Entwicklung seitmehr als 25 Jahren
Fachautor seit 1999
Frank MüllerFrank Müller — Go to the Cloud — 2/49
http://www.dpunkt.de/googlego
Typische Systeme heute
Betriebssystem
Datenbank
Hardware
Web Server
Message QueuesJobs
Caching
Load Balancer
Redundanz
Frank Müller — Go to the Cloud — 3/49
Google App Engine
Platform as a Service
Basis für eigene Web-Anwendungen
Bereitstellung von Diensten
Transparente Skalierung
Einfaches Deployment und Monitoring
Google App Engine • EigenschaftenFrank Müller — Go to the Cloud — 5/49
2008 Vorstellung für Python
2009 Erweiterung um Java
2011 Integration von Go
Aktuell Version 1.6.x
Go noch mit Status „experimentell“
Google App Engine • HistorieFrank Müller — Go to the Cloud — 6/49
Verarbeitung von HTTP Requests
Asynchrone Datenverarbeitung
Langlaufende Jobs
Chronologische Jobs
Google App Engine • Services für Go IFrank Müller — Go to the Cloud — 7/49
Schemalose Datenbank
Zugriff über Schlüssel und Abfragen
Keine Relationen, dafür Schlüsseltypen
Speicher für BLOBs
Memcache
Google App Engine • Services für Go IIFrank Müller — Go to the Cloud — 8/49
Nutzung von Google-Konten möglich
Persistente Verbindungen zum Client
Skalierbare Zugriffe auf URLs
Google App Engine • Services für Go IIIFrank Müller — Go to the Cloud — 9/49
Google Go
„Go hat das Ziel, die Sicherheit und Geschwindigkeit einer statisch typisierten kompilierten Sprache mit der Ausdrucksstärke und dem Komfort einer dynamisch typisierten interpretierten Sprache zu verbinden.
Zudem soll die Sprache für moderne, stark skalierende Systeme geeignet sein.“
— Rob Pike
Google Go • MotivationFrank Müller — Go to the Cloud — 11/49
Ken Thompson● Multics, Unix, B, Plan 9, ed, UTF-8● Turing Award
Robe Pike● Unix, Plan 9, Inferno, acme, Limbo,
UTF-8
Google Go • Bekannte VäterFrank Müller — Go to the Cloud — 12/49
Systemprogrammierung
Nebenläufigkeit
Statisch typisiert
Garbage Collection
Compiliert
Google Go • Kurz umrissenFrank Müller — Go to the Cloud — 13/49
Google Go • Einfache Struktur
package main
import ("fmt"
)
func greeting(greeting, name string) {fmt.Printf("%s, %s!\n", greeting, name)
}
func main() {hello := "Hello"world := "World"
greeting(hello, world)}
Frank Müller — Go to the Cloud — 14/49
Einfache Datentypen
Komplexe Datentypen
Kommunikationstypen
Funktionstypen
Interfaces und Methoden
Google Go • Flexibles TypenmodellFrank Müller — Go to the Cloud — 15/49
Google Go • Kein OO, aber Methoden
type Door struct { ... }
func NewDoor(width, height float64) *Door { ... }
func (d *Door) Open() { ... }
func (d *Door) Close() { ... }
func (d Door) IsOpen() bool { ... }
func (d Door) Size() (float64, float64) { ... }
func (d Door) String() string { ... }
Frank Müller — Go to the Cloud — 16/49
Google Go • Polymorphie über Schnittstellen
type TypeStringer interface {TypeString() string
}
type Foo int64type Bar struct { id string }
func (f Foo) TypeString() string {return "I'm a Foo (int64)."
}
func (b Bar) TypeString() string {return "I'm a Bar (struct)."
}
func TypePrint(ts TypeStringer) { ... }
Frank Müller — Go to the Cloud — 17/49
Goroutinen leichtgewichtiger als Threads
Threadpools für Goroutinen
Kommunikation über typisierte Channels
Channels nicht an Goroutinen gebunden
Google Go • NebenläufigkeitFrank Müller — Go to the Cloud — 18/49
Google Go • Einfache Nebenläufigkeit I
type Resource interface {...
}
type job struct {jobFunc JobFuncresultChan ResultChan
}
type JobFunc func(r Resource) *Resulttype ResultChan chan *Result
type Result struct {Payload interface{}Error os.Error
}
Frank Müller — Go to the Cloud — 19/49
Google Go • Einfache Nebenläufigkeit II
type Manager struct {resource ResourcejobChan chan *job
}
func NewManager(r Resource) *Manager {m := &Manager{r, make(chan *job)}
go m.backend()
return m}
func (m *Manager) backend() {for j := range m.jobChan {
j.resultChan <- j.jobFunc(m.resource)}
}
Frank Müller — Go to the Cloud — 20/49
Google Go • Einfache Nebenläufigkeit III
func (m Manager) Perform(jf JobFunc) ResultChan {j := &job{jf, make(ResultChan)}
go func() {m.jobChan <- j
}()
return j.resultChan}
func (m Manager) Stop() {close(m.jobChan)
}
Frank Müller — Go to the Cloud — 21/49
Google Go • Einfache Nebenläufigkeit IV
func AnyFunc(m Manager) (*AnyResult, os.Error) {rc := m.Perform(func(r Resource) *Result {
r.DoThis()r.DoThat()
return &Result{..., nil}})
... // Do something else.
result := <-rc
if result.Error != nil {return nil, result.Error
}
return result.Payload.(*AnyResult), nil}
Frank Müller — Go to the Cloud — 22/49
Umfangreiche Standardbibliothek● Netzwerk● Crypto● Zeichenketten● Marshalling und Encoding● I/O● Kompression● Bildverarbeitung● Reflection
Google Go • Organisation in PackagesFrank Müller — Go to the Cloud — 23/49
Formatierung
Testautomatisierung
Dokumentation
Installation externer Projekte
Zentrales Projektverzeichnis
Google Go • Reichhaltige WerkzeugeFrank Müller — Go to the Cloud — 24/49
Come Together
Come Together • Go und die App EngineFrank Müller — Go to the Cloud — 26/49
Come Together • HTTP Requests
package oop
import ("fmt""http". "appengine"
)
func init() {http.HandleFunc("/", greeting)
}
func greeting(rw http.ResponseWriter, r *http.Request) {fmt.Fprintf(rw, "Hello, OOP 2012!")
}
Frank Müller — Go to the Cloud — 27/49
Come Together • Rückgabe von JSON
type Address struct {...
}
func address(rw http.ResponseWriter, r *http.Request) {ctx := NewContext(r)
r.ParseForm()
id := r.FormValue("id")addr := ReadAddressById(ctx, id)
if b, err := json.Marshal(addr); err == nil {rw.Header().Set("Content-Type", "application/json")rw.Write(b)
}}
Frank Müller — Go to the Cloud — 28/49
Structs (Public / Annotation)
int(*), bool, string, float(*), []byte
Typen auf Basis dieser Typen
Eigene Typen für Zeit, *Key, BlobKey
Slices dieser Typen
Come Together • Nutzung des DatastoresFrank Müller — Go to the Cloud — 29/49
Come Together • Beispielstrukturen
type Address struct {Id stringStreet stringCity stringCountry stringPhotoKey appengine.BlobKey
}
type Customer struct {Id string `datastore:"CustomerId"`Name stringAddressKey *datastore.KeyOrderKeys []*datastore.KeyLastOrder datastore.TimeTurnover MoneyAvgTurnover Money `datastore:"-"`
}
Frank Müller — Go to the Cloud — 30/49
Come Together • Daten speichern
func StoreCustomerAddress(ctx Context, c *Customer, a *Address) os.Error {c.AddressKey = datastore.NewKey(ctx, "Address", a.Id,
0, nil)
if _, err := datastore.Put(ctx, c.AddressKey, a); err != nil {return err
}
kc := datastore.NewKey(ctx, "Customer", c.Id, 0, nil)
_, err := datastore.Put(ctx, kc, c)
return err}
Frank Müller — Go to the Cloud — 31/49
Come Together • Daten lesen
func ReadCustomerById(ctx Context, id string) (*Customer, *Address, os.Error) {k := datastore.NewKey(ctx, "Customer", id, 0, nil)c := new(Customer)a := new(Address)
if err := datastore.Get(ctx, k, c); err != nil {return nil, nil, err
}
if err := datastore.Get(ctx, c.AddressKey, a); err != nil {return nil, nil, err
}
return c, a, nil}
Frank Müller — Go to the Cloud — 32/49
Come Together • Transaktionen
func Book(ctx Context, fromAcc, toAcc string,amount Money) os.Error {b := func(c Context) os.Error {
if err := subtractAmount(c, fromAcc, amount); err != nil {return err
}
return addAmount(c, toAcc, amount)}
return datastore.RunInTransaction(ctx, b, nil)}
Frank Müller — Go to the Cloud — 33/49
x
Abfragetyp mit Filtern und Sortierung
Begrenzt auf eine Entität
Rückgabe der Daten oder Schlüssel
Abfrage der Anzahl
Alle Daten, Limitierung oder Iterator
Come Together • AbfragemöglichkeitenFrank Müller — Go to the Cloud — 34/49
Come Together • Daten abfragen
func QueryByTurnover(ctx Context, turnover Money, limit int) ([]*Customer, os.Error) {q := datastore.NewQuery("Customer").
Filter("Turnover >=", turnover).Order("-Turnover").Limit(limit)
cs := make([]*Customer, 0)
if _, err := q.GetAll(ctx, &cs); err != nil {return nil, err
}
return ts, nil}
Frank Müller — Go to the Cloud — 35/49
Verteilter Puffer im Hauptspeicher
Byte Slices und serialisierte Objekte
Ablauf kann festgelegt werden
Statistik zur Analyse
Come Together • CachingFrank Müller — Go to the Cloud — 36/49
Come Together • Cache lesen
func AllTagsCached(ctx Context) ([]*Tags, os.Error) {ts := make([]*Tags, 0)_, err := memcache.Gob.Get(ctx, "tags", &ts)
switch err {case memcache.ErrCacheMiss:
if ts, err = cacheTags(ctx); err != nil {return nil, err
}
return ts, nilcase nil:
return ts, nil}
return nil, err}
Frank Müller — Go to the Cloud — 37/49
Come Together • Cache schreiben
func cacheTags(ctx Context) ([]*Tags, os.Error) {if ts, err := ReadAllTags(ctx); err != nil {
return nil, err}
ci := &memcache.Item{Key: "tags",Object: ts,Expiration: 60,
}
if err = memcache.Gob.Set(ctx, ci); err != nil {return nil, err
}
return ts, nil}
Frank Müller — Go to the Cloud — 38/49
HTTP Requests ohne Antwort
Längere Verarbeitung möglich
Mehrere Warteschlangen
Versionierung der Tasks
Come Together • Task QueuesFrank Müller — Go to the Cloud — 39/49
Come Together • Task einstellen
func AsyncStoreDoc(ctx Context, d *Document) os.Error {if b, err := json.Marshall(d); err != nil {
return err}
task := &taskqueue.Task{Path: "/queues/store-doc",Payload: b,Header: make(http.Header),
}
task.Header.Set("Content-Type", "application/json")
_, err = taskqueue.Add(ctx, task, "store-doc")
return err}
Frank Müller — Go to the Cloud — 40/49
Come Together • Task verarbeiten
func storeDoc(rw http.ResponseWriter, r *http.Request) {var d Document
ctx := NewContext(r)b, err := ioutil.ReadAll(r.Body)
r.Body.Close()
if err != nil {ctx.Errorf("Can't read request body: %v", err)
} else if err = json.Unmarshal(b, &d); err != nil {ctx.Errorf("Can't unmarshal document: %v", err)
} else if err = StoreDoc(ctx, d); err != nil {ctx.Errorf("Can't store document: %v", err)
}}
Frank Müller — Go to the Cloud — 41/49
Come Together • Tasks ganz einfach
var delayedFunc = delay.Func("keyForFunc", myDelayedFunc)
func myDelayedFunc(ctx Context, ...) {...
}
func doSomething(rw http.ResponseWriter, r *http.Request) {ctx := NewContext(r)
...
delayedFunc.Call(ctx, arg1, arg2, ...)}
Frank Müller — Go to the Cloud — 42/49
Come Together • Google Accounts nutzen
func hello(rw http.ResponseWriter, r *http.Request) {ctx := NewContext(r)u := user.Current(ctx)
if u == nil {url := user.LoginURL(ctx, "/")
fmt.Fprintf(rw, `<a href="%s">Login</a>`, url)
return}
url := user.LogoutURL(ctx, "/")
fmt.Fprintf(rw, `<a href="%s">Logout</a>`, url)}
Frank Müller — Go to the Cloud — 43/49
Come Together • Ressourcen via HTTP laden
func fetcher(rw http.ResponseWriter, r *http.Request) {ctx := NewContext(r)client := urlfetch.Client(ctx)resp, err := client.Get("http://...")
if err != nil {http.Error(rw, err.String(),
http.StatusInternalServerError)
return}
...}
Frank Müller — Go to the Cloud — 44/49
Come Together • Mails senden
func mailer(rw http.ResponseWriter, r *http.Request) {ctx := NewContext(r)msg := &mail.Message{
Sender: "My App <[email protected]>",To: "[email protected]",Subject: "Thank you for your feedback",Body: feedbackText,
}
if err := mail.Send(ctx, msg); err != nil {http.Error(rw, err.String(),
http.StatusInternalServerError)
return}
}
Frank Müller — Go to the Cloud — 45/49
Fazit
Schneller Einstieg
Einfache und leistungsfähige API
Flexible Services
Produktive Programmiersprache
Transparente Skalierung
Fazit • VorteileFrank Müller — Go to the Cloud — 47/49
Weniger flexibel als IaaS, Rackspace oder Hosting
Einschränkungen in den Services und der API
Bindung an die Plattform im Code
Fazit • NachteileFrank Müller — Go to the Cloud — 48/49
Fragen?