memcache.GetMulti and parallelism

108 views
Skip to first unread message

Martin Bruse

unread,
Aug 3, 2013, 8:24:47 AM8/3/13
to google-ap...@googlegroups.com
Hello group,

I am trying to collate data from several hundred memcache keys into a web view, and when I look at the app stats (http://imgur.com/JKNtTzW) I see that it executes serial requests using memcache.Get.

Is there a way to parallelize this more? I wonder if it would be more efficient if I spawned a few goroutines and did this in parallel. What is the best way to speed this up?

best regards,
Martin

David Symonds

unread,
Aug 4, 2013, 6:27:02 PM8/4/13
to Martin Bruse, google-ap...@googlegroups.com
memcache.GetMulti does a single RPC; have you tried using that?

Martin Bruse

unread,
Aug 5, 2013, 1:32:21 AM8/5/13
to David Symonds, google-ap...@googlegroups.com

memcache.GetMulti is what I used..

Look at the screenshots, the stack trace shows it.

David Symonds

unread,
Aug 5, 2013, 1:36:30 AM8/5/13
to Martin Bruse, google-appengine-go
That's odd. memcache.GetMulti makes a single RPC. Are you referring to
the 37ms/53ms/42ms RPCs? How many keys are you getting?

Martin Bruse

unread,
Aug 5, 2013, 1:57:05 AM8/5/13
to David Symonds, google-appengine-go

I only do GetMulti, sometimes with a single key, and sometimes with a few hundred of them..

Are you sure that GetMulti isn't implemented as a series of Get?

Matt Jibson

unread,
Aug 5, 2013, 2:03:54 AM8/5/13
to Martin Bruse, David Symonds, google-appengine-go
Are you sure there's not other code running here? In the appstats details page, examine the keys fetched by the Get call (hit the + next to one of them). Are they what you expect?


--
You received this message because you are subscribed to the Google Groups "google-appengine-go" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-appengin...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

David Symonds

unread,
Aug 5, 2013, 2:14:59 AM8/5/13
to Martin Bruse, google-appengine-go
On 5 August 2013 15:57, Martin Bruse <zond...@gmail.com> wrote:

> I only do GetMulti, sometimes with a single key, and sometimes with a few
> hundred of them..
>
> Are you sure that GetMulti isn't implemented as a series of Get?

https://code.google.com/p/appengine-go/source/browse/appengine/memcache/memcache.go#121

Martin Bruse

unread,
Aug 5, 2013, 2:15:48 AM8/5/13
to Matt Jibson, David Symonds, google-appengine-go
Oh, damn, I looked at the image I linked, and noticed that yeah I
forgot one of them.

Here is the link I intended to send: http://imgur.com/a/FEqog

Look at the second image - in the stack trace you see a
memcache.GetMulti, but the RPC call being logged is a memcache.Get.

David Symonds

unread,
Aug 5, 2013, 2:42:58 AM8/5/13
to Martin Bruse, Matt Jibson, google-appengine-go
On 5 August 2013 16:15, Martin Bruse <zond...@gmail.com> wrote:

> Oh, damn, I looked at the image I linked, and noticed that yeah I
> forgot one of them.
>
> Here is the link I intended to send: http://imgur.com/a/FEqog
>
> Look at the second image - in the stack trace you see a
> memcache.GetMulti, but the RPC call being logged is a memcache.Get.

That's expected. The underlying RPC is indeed called "memcache.Get".
The screenshot shows an expanded RPC that has a single key.

Martin Bruse

unread,
Aug 5, 2013, 2:56:06 AM8/5/13
to David Symonds, google-appengine-go
That is what I expected when I started out...

I now logged a bit more.

Here is what my log says (somewhat abbreviated at [...]):

-----8<----
### doing memcache.GetMulti([ILpYgFifD4a1o8dQFVYkNdNiM9k=
zUKjn+JzC3RdApe4YhbO684/gD8= o3c/FyBzMVHbPrpQsxaJF182DnY= [...]
ospEqFtMA9ZjbfFYJjg7dKbLr68...(length 8962)
----8<----

When I added a log output like:

----8<----
c.Infof("### doing memcache.GetMulti(%v)", keys)
itemHash, err := memcache.GetMulti(c, keys)
----8<----

And the appstats page for the first key shows:

----8<----
@236.15738ms memcache.Get real=7.599035ms cost=0


#### (1)
Request: key:"ILpYgFifD4a1o8dQFVYkNdNiM9k="
key:"zUKjn+JzC3RdApe4YhbO684/gD8=" key:"o3c/FyBzMVHbPrpQsxaJF182DnY="
key:"OB8iOmADx8Y9oWWBFIbIi7b08SM=" key:"ypnJR... #### (3)
Response: Item{key:"ILpYgFifD4a1o8dQFVYkNdNiM9k="
value:"p\020\264\001\005ColorD\264\002\035ConfirmationEmailBodyTemplateD\264\003\"ConfirmationEmailBodyTemplat...
Stack:
go/src/pkg/appengine/memcache/memcache.go:134
common/common.go:302 memGetMulti: itemHash, err :=
memcache.GetMulti(c, keys)

#### (2)
common/common.go:352 MemoizeMulti: items, errors := memGetMulti(c,
keyHashes, destPs)
event/event.go:271 preProcess: exists := common.MemoizeMulti(c,
cacheKeys, values, funcs)
event/event.go:761 GetEventsBetween: preProcess(c, preResult)
event/event.go:847 GetAllowedEventsBetween: })
web/events_controller.go:329 getEvents: common.MustEncodeJSON(w,
event.GetAllowedEventsBetween(data.context, data.user.Id,
data.authorizer, data.domain, start, end, r.Form["locations"],
r.Form["kinds"], r.Form["types"]))
github.com/mjibson/appstats/appstats.go:255
com/mjibson/appstats.Handler.ServeHTTP: h.f(c, rw, r)
github.com/gorilla/mux/mux.go:86
com/gorilla/mux.(*Router).ServeHTTP: handler.ServeHTTP(w, req)
go/src/pkg/net/http/server.go:1416
go/src/pkg/appengine_internal/api_prod.go:249
go/src/pkg/appengine_internal/api_prod.go:198
go/src/pkg/reflect/value.go:474
go/src/pkg/reflect/value.go:345
_.go:316
go/src/pkg/runtime/proc.c:280
----8<----

Note (1) that the header of the appstats op is memcache.Get while the
stacktrace (2) shows memcache.GetMulti and the 'key' (3) attribute of
the request contains multiple values.

So far so good.

But the next operation that happens i my fallback when the GetMulti
fails to find a value for the 18th key in the GetMulti operation. I
now realized that the fallback is the same thing that happens when I
try to find a single value - which first does a memcache.GetMulti
(with a single value) and then looks in the datastore.

This is, then, the reason I get so many memcache.Get operations in the
appstats log.

But then I notice that it is always (at least 4 out of 4 times when I
looked now) the 18th key in the first GetMulti that fails. And all
keys after that.

Is there a max key length or max value length in memcache.GetMulti,
that makes only my first 17 keys possible to fetch? I get no
ErrCacheMiss or anything like that from key #18 and up.

The plot thickens...

David Symonds

unread,
Aug 5, 2013, 3:09:58 AM8/5/13
to Martin Bruse, google-appengine-go
On 5 August 2013 16:56, Martin Bruse <zond...@gmail.com> wrote:

> Is there a max key length or max value length in memcache.GetMulti,
> that makes only my first 17 keys possible to fetch? I get no
> ErrCacheMiss or anything like that from key #18 and up.

https://developers.google.com/appengine/docs/go/memcache/#Go_Limits

Martin Bruse

unread,
Aug 5, 2013, 4:02:19 AM8/5/13
to David Symonds, google-appengine-go
I think I am narrowing my bug down to (not unexpectedly) my own
mistakes... it looks like I fail to cache empty or nil sets, and thus
force the code to try again...

I might be back for more advice, but thank you for your help so far :)
Reply all
Reply to author
Forward
0 new messages