Cloud Datastore 活用術

7 June 2016

Profile

Cloud Datastore Update

Indexの数は考慮されず、操作したEntityの数のみがカウントされるように変更

Entity Reads   : $0.06 per 100,000 entities
Entity Writes  : $0.18 per 100,000 entities
Entity Deletes : $0.02 per 100,000 entities

Cloud Datastoreらしい構成

Kind 設計

Key 設計

type User struct {
    ID          int // key value
    AccountName string
    NickName    string
    Email       string // uniqueにするのが難しい
}

// Login時に利用するKind
type EmailToUser struct {
    Email    string // key value
    UserID   int
    Password string
}

タブレットサーバの分割問題

pagenationは苦手

q := datastore.NewQuery("Item").Order("-UpdatedAt").Limit(limit)
if len(cursorParam) > 0 {
    cursor, err := datastore.DecodeCursor(cursorParam)
    if err == nil {
        q = q.Start(cursor)
    }
}

Query

Query Price

Datastore Write Ops

Datastore Read Ops

Datastoer Smaill Ops

Keys Only Query ?

q := datastore.NewQuery("Item").KeysOnly()

Indexの節約

Queryに使わないIndexはoffに

type Item struct {
    Title     string    `json:"title" datastore:",noindex"`
}

InMemory Filter & Sort

Custom Index or Kind分割 (1)

type Item struct {
    KeyStr    string    `json:"key" datastore:"-"`
    Title     string    `json:"title" datastore:",noindex"`
    Category  string    `json:"category"`
    DelFlg    bool      `json:"delFlg"`
    CreatedAt time.Time `json:"createdAt"`
    UpdatedAt time.Time `json:"updatedAt"`
}

Custom Index or Kind分割 (2)

type Item struct {
    KeyStr    string    `json:"key" datastore:"-"`
    Title     string    `json:"title" datastore:",noindex"`
    Category  string    `json:"category"`
    CreatedAt time.Time `json:"createdAt"`
    UpdatedAt time.Time `json:"updatedAt"`
}

Batch操作

Batch操作 Bad !

for key := range keys {
    err := datastore.Get(ctx, key, dst)
}

Batch操作 Good !

err := datastore.GetMulti(ctx, keys, dst)

集計

集計はMemcacheやPull Queueを活用する

集計はputされる時に、やることが多い。

集計 Bad !

集計 Good ! (1)

集計 Good ! (2)

Task Queueの活用

重たい処理はUser Requestの外で

自作IndexをTQで作る

大量のデータ更新もTQで

非同期処理

非同期処理

Example

同期で呼んだ場合 (code)

var entries []Entry
var comments []Comment
var friends []Friend
var footprint []Footprint
_, err := datastore.NewQuery("Entry").GetAll(ctx, &entries)
_, err = datastore.NewQuery("Comment").GetAll(ctx, &comments)
_, err = datastore.NewQuery("Friend").GetAll(ctx, &friends)
_, err = datastore.NewQuery("Footprint").GetAll(ctx, &footprint)

同期で呼んだ場合 (trace)

非同期で呼んだ場合 (code)

var entries []Entry
var comments []Comment
var friends []Friend
var footprint []Footprint
errc := make(chan error)
go func() {
    _, err := datastore.NewQuery("Entry").GetAll(ctx, &entries)
    errc <- err
}()
go func() {
    _, err := datastore.NewQuery("Comment").GetAll(ctx, &comments)
    errc <- err
}()
go func() {
    _, err := datastore.NewQuery("Friend").GetAll(ctx, &friends)
    errc <- err
}()
go func() {
    _, err := datastore.NewQuery("Footprint").GetAll(ctx, &footprint)
    errc <- err
}()
err1, err2, err3, err4 := <-errc, <-errc, <-errc, <-errc

非同期で呼んだ場合 (trace)

Advanced Technic

Keyに全てを

datastore.NewKey(c, "Item", fmt.Sprintf("%s-_-%s-_-%s", uuid.New(), title, category) , 0, nil)

1 Entityに集約

Advertise

Resource

Thank you

TOPGATE GAEマイスター