【问题标题】:Why are my datastore Writes per Entity Group per Second far over the stated limit?为什么我的每个实体组每秒的数据存储写入量远远超过规定的限制?
【发布时间】:2015-01-16 00:09:08
【问题描述】:

我在事务中使用 objectify 更新实体。我的猜测是,我每秒只能向同一个实体组写入 1 到 5 次。这将符合有关写入数据存储的文档和建议。但是在对以下代码进行了一些简单的负载测试后,我看到了

  • 单个实体每秒大约 90 次写入
  • 每秒对同一实体组中的随机实体进行大约 50 次写入。

为什么会这样?我的错在哪里?

// text => a random text, different for each request
public void update(final Key<SomeEntity> toLoad, String text) {
    final AtomicInteger attempts = new AtomicInteger(0);

    SomeEntity modified = ofy().transact(new Work<SomeEntity>() {
        public SomeEntity run() {
            // count every attempt
            attempts.incrementAndGet();

            SomeEntity toModify = ofy().load().key(toLoad).now();
            if (toModify != null) {

                // modifies the entity
                toModify.setText(text);

                ofy().save().entity(toModify).now();
            }

            return toModify;
        }
    });

    if (attempts.get() > 1) {
        logger.warning(attempts.get() + " attempts for update on " + modified);
    }
}

在 Cloud Console 日志查看器中报告了很多重试,大多数警告有 ~ 2 次尝试,一些事务有 5 次尝试,但已执行并更新了实体。在 GAE 上进行负载测试有什么特殊的策略吗?或者关于这个主题的任何一般性建议?

更新:

实体组结构和测试设置的简短描述。为了便于选择实体,键名反映了实体在其实体组中的位置。 “001-001-100”是实体组中的第二级实体,根实体为“100”,父实体为“001-100”。所以一个实体组看起来像这样:

- 100
  - 001-100
    - 001-001-100
    - 002-001-100
    - 003-001-100
    - ...
  - 002-100
  - 003-100
  - 004-100
  - 005-100
  - ...
- 101
- ...

我尝试了三个不同的版本。每个人都在 JMeter 中为更新请求使用另一个值。全部更新完全相同的实体“001-001-100”。

// Version A: text does not change during load test
vars.put("text", "Foo Bar");

// Version B: text changes every second during load test
var d = new Date();
vars.put("text", [d.getHours(), d.getMinutes(), d.getSeconds()].join("-")));

// Version B: text changes every request
vars.put("text", Math.random());
  • 版本 A:~ 110 个请求/秒
  • 版本 B:约 70 个请求/秒
  • 版本 C:~ 24 个请求/秒

但仍然:每秒对一个实体进行 24 次写入确实很高。所以我稍微重新设计了测试。

然后我稍微修改了测试。我现在不再只对一个实体发出请求,而是将它们分发到实体组的第二层。所以 JMeter 随机使用“001-001-100”、“002-001-100”、“003-001-100”、“004-001-100”或“005-001-100”。与我只选择一个实体的结果大致相同。

  • 版本 A:~ 110 个请求/秒
  • 版本 B:~ 100 个请求/秒
  • 版本 C:~ 20 个请求/秒

更新 2: 如果您只使用一个线程执行负载测试,则吞吐量约为每秒 2.5 次更新。这更接近建议的限制。如果我用 80 个线程运行测试,吞吐量会上升到我之前发布的数字。样本的响应时间不是最好的,但吞吐量一直很高:avg = 2100ms,median = 1350ms,90% = 5400ms,max = 18000ms。也许吞吐量可能不是数据存储限制的直观衡量标准?

【问题讨论】:

  • 您是否真的在修改实体,即每次都设置不同的文本?
  • 是的,文本是由 JMeter 随机生成的,如果我在负载测试期间加载实体,更改是可见的。
  • 如果没有更完整的测试,这很难回答。我的建议是将它封装在一个最小的 github 项目中,并邀请人们来看看。
  • 这里是这个例子的代码:gist.github.com/botic/7885fe0266ad0f97c99f

标签: google-app-engine google-cloud-datastore objectify


【解决方案1】:
  1. 您可以获得实体缓存(版本 A 和 B)的好处。它可能在 Objectify 的级别,或在 Datastore 的基础架构内。

  2. 每秒 5 个请求不是硬性限制。这是一个警告:

对单个实体组的写入由 App Engine 序列化 数据存储,因此您可以多快更新一个 实体组。一般来说,这在 1 到 5 之间 每秒更新;一个好的指导方针是你应该考虑 如果您期望实体组必须维持更多 在很长一段时间内每秒更新一次。

请注意:

(a) 一个简单的文本字符串几乎没有序列化开销。对于复杂的实体,情况并非如此。

(b) 警告包括“延长期限”一词。

【讨论】:

  • 在版本 A 和 B 中,缓存应该没有帮助,因为没有使用 Objectify 的全局缓存,并且会话缓存只存储读取的实体,但仍然需要在事务中更新它,这需要低级数据存储写入。会话缓存是针对每个 Objectify 实例的,因此两个单独的请求不会共享同一个缓存。感谢您提供简单文本序列化的提示。用更复杂的实体重复这一点会很有趣。
猜你喜欢
  • 2017-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-18
相关资源
最近更新 更多