High Performance Apps with Go on App Engine

Google I/O, May 2013

David Symonds

Software Engineer, Google

Video

This talk was presented at Google I/O in May 2013.

2

Overview

3

Why Go + App Engine

4

History

5

Turkey doodle (Nov 2011)

go.dev/s/turkey-doodle

6

Santa Tracker (Dec 2012)

7

Gopher Mart

8

Gopher Mart

9

Gopher Mart

10

Gopher Mart

11

Finding performance bottlenecks

12

Appstats

13

Performance Techniques

14

Defer work

15

Defer work II

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) {
16

Batching

    var items []*Item
    for _, key := range keys {
        item := new(Item)
        if err := datastore.Get(c, key, item); err != nil {
            // ...
        }
        items = append(items, item)
    }
17

Batching II

    items := make([]Item, len(keys))
    if err := datastore.GetMulti(c, keys, items); err != nil {
        // ...
    }
18

Caching

Small reads
datastore.Get O(20ms)
memcache.Get O(1ms)
RAM O(1µs)
19

Concurrency

20

Concurrency II

    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
21

Concurrency III

    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
22

Control variance

23

Control variance II

"The Tail at Scale", Dean, Barroso; Commun. ACM 56, 2

24

Control variance III

func myHandler(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    // ...
    // regular request handling
    // ...

    go memcache.Set(c, &memcache.Item{
        Key:   key,
        Value: data,
    })
}
25

Control variance IV

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):
    }
}
26

Before and After

Baseline:

Defer work:

Batching:

27

Summary

28

Finally...

More Go things:

29

Thank you

David Symonds

Software Engineer, Google

Use the left and right arrow keys or click the left and right edges of the page to navigate between slides.
(Press 'H' or navigate to hide this message.)