High Performance Apps with Go on App Engine
Google I/O, May 2013
David Symonds
Software Engineer, Google
David Symonds
Software Engineer, Google
This talk was presented at Google I/O in May 2013.
2appengine/taskqueue
or appengine/delay
to move non-critical work outside the request scopemail.Send
with quick taskqueue.Add
Import "appengine/delay"
and transform
sendReceipt(c, user.Current(c).Email, b.String())
func sendReceipt(c appengine.Context, dst, body string) {
into
sendReceipt.Call(c, user.Current(c).Email, b.String())
var sendReceipt = delay.Func("send-receipt", func(c appengine.Context, dst, body string) {
GetMulti
instead of Get
, PutMulti
instead of Put
, etc.var items []*Item for _, key := range keys { item := new(Item) if err := datastore.Get(c, key, item); err != nil { // ... } items = append(items, item) }
items := make([]Item, len(keys)) if err := datastore.GetMulti(c, keys, items); err != nil { // ... }
datastore.Get | O(20ms) |
memcache.Get | O(1ms) |
RAM | O(1µs) |
var lists []List var items []Item _, err := datastore.NewQuery("List").GetAll(c, &lists) if err != nil { /* ... */ } _, err := datastore.NewQuery("Item").GetAll(c, &items) if err != nil { /* ... */ } // write response
var lists []List var items []Item errc := make(chan error) go func() { _, err := datastore.NewQuery("List").GetAll(c, &lists) errc <- err }() go func() { _, err := datastore.NewQuery("Item").GetAll(c, &items) errc <- err }() err1, err2 := <-errc, <-errc if err1 != nil || err2 != nil { /* ... */ } // write response
"The Tail at Scale", Dean, Barroso; Commun. ACM 56, 2
24func myHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) // ... // regular request handling // ... go memcache.Set(c, &memcache.Item{ Key: key, Value: data, }) }
func myHandler(w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) // ... // regular request handling // ... // Save to memcache, but only wait up to 3ms. done := make(chan bool, 1) // NB: buffered go func() { memcache.Set(c, &memcache.Item{ Key: key, Value: data, }) done <- true }() select { case <-done: case <-time.After(3 * time.Millisecond): } }
Baseline:
Defer work:
Batching:
More Go things: