我们需要定期处理数以千计的时间序列实体,并且我们在从数据存储区读取大量数据时遇到性能问题,处理过程轻微且不会引起问题。我们创建了一个模拟真实服务器流量的综合测试,我们使用25k权限进行测试。
我们使用Java运行时和Objectify(5.1.1和5.1.8)来访问数据存储区。
实体
@Entity(name="logs")
@Cache
public class Log {
@Id
public Long id;
@Index
public Ref<User> user;
public String deviceId;
public String nonce;
public String version;
public String data;
@Index
public Date timestamp;
@OnSave
private void prePersist() {
if (timestamp == null) {
timestamp = new Date();
}
}
}
查询
query = ofy().load().type(Log.class).
filter("timestamp >", startDate).
order("timestamp").
limit(25000);
我们尝试了不同的实体加载。首先query.list()
然后ofy().load().keys(query.keys())
所以查找将通过GAE的内存缓存,但结果是相同的。检索25k实体需要大约8秒(通过System.nanoTime()
测量)。在query.list()
的情况下,该调用本身很快,但对实体的迭代很慢。看起来那个实体是在那个时刻从数据存储区中检索出来的,而不是query.list()
中的。所有这些都是F4前端实例上的一个简单的servlet,具有专用的memcache,没有任务。
阅读25k实体只是一个测试,以获得有关我们的服务器实现的性能的一些数字。在实际情况下,我们希望同时读取多达50万个实体,这是否可以在30-60秒内使用GAE的数据存储和专用内存缓存?在两年内,它可能是数百万个实体。
另一个问题是RAM有限,但可通过GAE的托管虚拟机或GCE解决。
问题是使用Objectify从Datastore +专用内存缓存中检索时间序列实体的最快方法。看起来memcache对我们的案例没有帮助Objectify。内存中有数万个Objectify项目,但加载时间与空内存缓存相同。 Objectify / Datastore的最佳实践是批量获取操作,如何实现? Objectify是用我们的实体和查询来做这件事还是我们必须改变一些东西?低级数据存储API可以帮助我们提高阅读性能吗?谢谢。
修改 我们已经在合并日志,因此每个日志实体将保存多个当前日志。这将为我们提供大约10倍的簧片改进,这仍然不足以成千上万的记录。
答案 0 :(得分:1)
此解决方案不太可能按照您希望的方式扩展。
查询@Cache实体默认为“混合”仅键查询(速度极快),然后是批量获取(相对较慢)。如果缓存很热,这可以很好地执行,但可能不是你所说的规模。最后,即使使用专用的内存缓存,缓存也会被重置 - 然后您的操作可能会超时并失败几次,直到缓存再次预热。
您可以禁用此混合功能:ofy().load().hybrid(false)
或仅删除@Cache注释。使用冷缓存时,常规查询的性能会明显提高。您也可以尝试将chunk()
尺寸更改为更大的尺寸。默认值小到20。
通过标准API对数据存储区进行托管VM访问(目前)明显慢于经典GAE中的访问。这可能会导致这种规模的问题。
数据存储通常不适合涉及大量实体的批量读取和写入的操作。为此目的,它也往往非常昂贵。您可以考虑将数据存储区用作可靠的“主”副本,并为使用聚簇索引的其他从属数据库中的数据编制索引。或者,根据您的耐久性要求,只需将辅助数据存储区用作主副本。