GAE中的高端RPC调用是否正常?

我有几个问题希望能够巩固我对GAE“幕后”的理解。 目前在我的应用程序中,我需要检索一组258个实体大小的数据。 我已将indexed = False设置为此实体的Model类的相应属性。 我正在使用Nick Johnson博客描述的序列化/反序列化实体技术。 我为了示例的目的而将代码作为通用的:

def serialize_entities(models):
    if not models:
        return None
    elif isinstance(models, db.Model):
        return db.model_to_protobuf(models).Encode()
    else:
        return [db.model_to_protobuf(x).Encode() for x in models]

def deserialize_entities(data):
    if not data:
        return None
    elif isinstance(data, str):
        return db.model_from_protobuf(entity_pb.EntityProto(data))
    else:
        return [db.model_from_protobuf(entity_pb.EntityProto(x)) for x in data]

class BatchProcessor(object):
    kind = None
    filters = []
    def get_query(self):
        q = self.kind.all()
        for prop, value in self.filters:
            q.filter("%s" % prop, value)
        q.order("__key__")
        return q

    def run(self, batch_size=100):
        q = self.get_query()
        entities = q.fetch(batch_size)
        while entities:
            yield entities
            q = self.get_query()
            q.filter("__key__ >",entities[-1].key())
            entities = q.fetch(batch_size)

class MyKindHandler(webapp2.RequestHandler):
    def fill_cache(self, my_cache):
        entities = []
        if not my_cache:
            # retry in case of failure to retrieve data
            while not my_cache:
                batch_processor = BatchProcessor()
                batch_processor.kind = models.MyKind
                batch = batch_processor.run()
                my_cache = []

                for b in batch:
                    my_cache.extend(b)                    
            # Cache entities for 10 minutes
            memcache.set('MyKindEntityCache', serialize_entities(my_cache), 
                         600)
        for v in my_cache:
            # There is actually around 10 properties for this entity.
            entities.append({'one': v.one, 'two': v.two})

        mykind_json_str = simplejson.dumps({'entities':entities})
        # Don't set expiration - will be refreshed automatically when 
        # entity cache is.
        memcache.set('MyKindJsonCache', mykind_json_str)
        return mykind_json_str

    def get(self):
        my_cache = deserialize_entities(memcache.get('MyKindEntityCache'))
        if not my_cache:
            # Create entity & json cache
            self.fill_cache(my_cache)

        mykind_json_str = memcache.get('MyKindJsonCache')
        if not mykind_json_str:
            mykind_json_str = self.fill_cache(my_cache)
        self.response.write(mykind_json_str)

当我看看appstats时,它显示了对检索这些数据的处理程序的ajax调用花费了大量的时间。 当该处理程序需要刷新数据存储区中的数据时(每10分钟实体缓存过期),将调用434个RPC调用,否则将有2个RPC调用检索每个memcaches。 用于刷新数据的appstats是:

real=10295ms cpu=13544ms api=5956ms overhead=137ms (434 RPCs)
datastore_v3.Get       428
memcache.Get             2
memcache.Set             2
datastore_v3.RunQuery    2

我想我理解这些调用大部分都在做什么,但是,与datastore_v3.RunQuery关联的datastore_v3.Get调用会让我感到困惑,因为它们代表了我认为他们所做的事情。 它们是否意味着这些是对数据存储的单个.get()调用? 我认为当你调用.fetch(batch_size)时,你会收到一个带有1个调用的“批处理”......不仅如此,为什么这些调用的数量要比数据存储中的实体数量多150给定的种类?

作为一个方面说明,我在了解查询游标之前编写了BatchProcessor类,并尝试将它们交换出来以查看性能是否更好,但它不仅保持不变,而且因为将游标存储在memcache中而增加了RPC的数量。

任何对我可能忽略的东西的洞察力都非常感谢!


编辑 - 来自appstats的更多细节:

在测试这个并仔细检查appstats时,我发现在创建json响应字符串时,我对每个MyKind的.parent()调用都大大增加了RPC,并且每个MyKind都有2个ReferenceProperties,这些ReferenceProperties可变地具有或不具有有价值。 我使用这个.parent()调用来返回MyKind数据的响应中的公司名称,如果ReferenceProperties有值,我也可以获取它们的名称。 我没有意识到调用.parent().name,.refprop1.name和.refprop2.name会为每个数据存储的数据存储区执行一个单独的datastore_V3.Get。 我认为父母和引用属性的数据与MyKind对象的原始查询一起返回。 有没有办法实现这一点,或者我需要在MyKind中创建3个其他属性来有效访问这些名称属性?

链接地址: http://www.djcxy.com/p/23217.html

上一篇: High # of RPC calls in GAE, is this normal?

下一篇: Google App Engine: efficient large deletes (about 90000/day)