【问题标题】:Google App Engine (Python) handle large number of writing tasksGoogle App Engine (Python) 处理大量的写作任务
【发布时间】:2013-09-19 07:47:47
【问题描述】:

我正在从 API 提供程序读取大量数据。一旦得到响应,我需要扫描并重新打包数据并放入 App Engine 数据存储区。一个特定的大帐户将包含约 5 万个条目。

每次我从 API 中获取一些条目时,我都会将 500 个条目作为一个批次存储在临时表中,并将处理任务发送到队列中。万一太多任务卡在一个队列中,我一共使用了6个队列:

count = 0 
worker_number = 6
for folder, property in entries:
                    data[count] = {
                        # repackaging data here
                    }

                    count = (count + 1) % 500

                    if count == 0:
                        cache = ClientCache(parent=user_key, data=json.dumps(data))
                        cache.put()
                        params = {
                            'access_token': access_token,
                            'client_key': client.key.urlsafe(),
                            'user_key': user_key.urlsafe(),
                            'cache_key': cache.key.urlsafe(),
                        }
                        taskqueue.add(
                            url=task_url,
                            params=params,
                            target='dbworker',
                            queue_name='worker%d' % worker_number)
                        worker_number = (worker_number + 1) % 6

而task_url会导致如下:

logging.info('--------------------- Process File ---------------------')
        user_key = ndb.Key(urlsafe=self.request.get('user_key'))
        client_key = ndb.Key(urlsafe=self.request.get('client_key'))
        cache_key = ndb.Key(urlsafe=self.request.get('cache_key'))

        cache = cache_key.get()
        data = json.loads(cache.data)
        for property in data.values():
            logging.info(property)
            try:
                key_name = '%s%s' % (property['key1'], property['key2'])
                metadata = Metadata.get_or_insert(
                    key_name,
                    parent=user_key,
                    client_key=client_key,
                    # ... other info
                )
                metadata.put()
            except StandardError, e:
                logging.error(e.message)

所有任务都在后台运行。

有了这样的结构,它工作得很好。嗯……大部分时间。 但有时我会收到此错误:

2013-09-19 15:10:07.788
suspended generator transaction(context.py:938) raised TransactionFailedError(The transaction could not be committed. Please try again.)
W 2013-09-19 15:10:07.788
suspended generator internal_tasklet(model.py:3321) raised TransactionFailedError(The transaction could not be committed. Please try again.)
E 2013-09-19 15:10:07.789
The transaction could not be committed. Please try again.

似乎是写入datastore过于频繁的问题?我想知道如何平衡节奏并让工人顺利运行...... 还有其他方法可以进一步提高性能吗?我的队列配置是这样的:

- name: worker0
  rate: 120/s
  bucket_size: 100
  retry_parameters:
    task_retry_limit: 3

【问题讨论】:

    标签: python performance google-app-engine queue backend


    【解决方案1】:

    您一次编写单个实体。

    如何修改您的代码以使用ndb.put_multi 批量编写,这将减少每个事务的往返时间。

    为什么每次都覆盖记录时使用 get_or_insert 。你也可以只写。这两个都会大大减少工作量

    【讨论】:

    • 我刚刚尝试了 put_multi,看起来很有帮助!我使用 get_or_insert 的原因是为了避免数据重复。我通过 key_name 将每个条目识别为唯一的.. 除非您知道更好的方法来保留唯一属性。
    • 关于唯一 ID。如果实体列表中有重复项,put_multi 将如何处理?
    • 您可以轻松地从列表中删除重复项。但是,您将永远不会得到重复的记录,因为您使用的是键名,在这种情况下,您只会覆盖相同的实体。
    • 此外,get_or_insert 也很昂贵,因为它在事务中(涉及 get 和 put)。在你的情况下,你可以盲目地写。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    • 1970-01-01
    • 2013-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多