Best practice to query large number of ndb entities from datastore

后端 未结 4 1136
有刺的猬
有刺的猬 2020-12-07 07:11

I have run into an interesting limit with the App Engine datastore. I am creating a handler to help us analyze some usage data on one of our production servers. To perform

4条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-07 07:57

    I have a similar problem and after working with Google support for few weeks I can confirm there is no magic solution at least as of December 2017.

    tl;dr: One can expect throughput from 220 entities/second for standard SDK running on B1 instance up to 900 entities/second for a patched SDK running on a B8 instance.

    The limitation is CPU related and changing the instanced type directly impacts performance. This is confirmed by similar results obtained on B4 and B4_1G instances

    The best throughput I got for an Expando entity with about 30 fields is:

    Standard GAE SDK

    • B1 instance: ~220 entities/second
    • B2 instance: ~250 entities/second
    • B4 instance: ~560 entities/second
    • B4_1G instance: ~560 entities/second
    • B8 instance: ~650 entities/second

    Patched GAE SDK

    • B1 instance: ~420 entities/second
    • B8 instance: ~900 entities/second

    For standard GAE SDK I tried various approaches including multi-threading but the best proved to be fetch_async with wait_any. Current NDB library already does a great job of using async and futures under the hood so any attempt to push that using threads only make it worse.

    I found two interesting approaches to optimize this:

    • Matt Faus - Speeding up GAE Datastore Reads with Protobuf Projection
    • Evan Jones - Tracing a Python performance bug on App Engine

    Matt Faus explains the problem very well:

    GAE SDK provides an API for reading and writing objects derived from your classes to the datastore. This saves you the boring work of validating raw data returned from the datastore and repackaging it into an easy-to-use object. In particular, GAE uses protocol buffers to transmit raw data from the store to the frontend machine that needs it. The SDK is then responsible for decoding this format and returning a clean object to your code. This utility is great, but sometimes it does a bit more work than you would like. [...] Using our profiling tool, I discovered that fully 50% of the time spent fetching these entities was during the protobuf-to-python-object decoding phase. This means that the CPU on the frontend server was a bottleneck in these datastore reads!

    GAE-data-access-web-request

    Both approaches try to reduce the time spent doing protobuf to Python decoding by reducing the number of fields decoded.

    I tried both approaches but I only succeed with Matt's. SDK internals changed since Evan published his solution. I had to change a bit the code published by Matt here, but is was pretty easy - if there is interest I can publish the final code.

    For a regular Expando entity with about 30 fields I used Matt's solution to decode only couple fields and obtained a significant improvement.

    In conclusion one need to plan accordingly and don't expect to be able to process much more than few hundreds entities in a "real-time" GAE request.

提交回复
热议问题