Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Google app engine 如何平衡Google App Engine的多个*动态*后端实例的负载?_Google App Engine_Architecture_Scalability_Backend_Software Design - Fatal编程技术网

Google app engine 如何平衡Google App Engine的多个*动态*后端实例的负载?

Google app engine 如何平衡Google App Engine的多个*动态*后端实例的负载?,google-app-engine,architecture,scalability,backend,software-design,Google App Engine,Architecture,Scalability,Backend,Software Design,我对StackOverflow比较陌生,不确定它是否适合提出设计问题。该网站给了我一个提示:“你所问的问题似乎是主观的,很可能会被关闭。”。也许应该继续问下去。请让我知道 无论如何。。我正在从事的项目之一是在线调查引擎。这是我在电视上的第一个大型商业项目 我需要你的建议,如何收集统计数据,并有效地记录在数据存储中,而不会让我破产。初步要求如下: 用户完成调查后,客户端发送配对列表[ID(int)+命中百分比(double)]。此列表显示此用户的答案与参考答案(由ID标识)的预定义答案的匹配程度

我对StackOverflow比较陌生,不确定它是否适合提出设计问题。该网站给了我一个提示:“你所问的问题似乎是主观的,很可能会被关闭。”。也许应该继续问下去。请让我知道

无论如何。。我正在从事的项目之一是在线调查引擎。这是我在电视上的第一个大型商业项目

我需要你的建议,如何收集统计数据,并有效地记录在数据存储中,而不会让我破产。初步要求如下:

  • 用户完成调查后,客户端发送配对列表[ID(int)+命中百分比(double)]。此列表显示此用户的答案与参考答案(由ID标识)的预定义答案的匹配程度。我称之为“目标ID”
  • 调查的创建者希望看到给定ID上一小时、特定时间段或调查开始时的聚合百分比
  • 一些调查可能有数千名目标/参考答案
所以我创建了实体

public class HitsStatsDO implements Serializable
{
    @Id
    transient private Long id;
    transient private Long version = (long) 0;

    transient private Long startDate;

    @Parent transient private Key parent;   // fake parent which contains target id
    @Transient int targetId;

    private double avgPercent;
    private long hitCount;
}
但是,为每个用户的每个目标编写HitsStatsDO将提供大量数据。例如,我进行了一项3000个目标的调查,在一周内约有400万人回答了这个问题,30万人在第一天进行了调查。即使我们假设他们在24小时内平均回答,我们每秒也会写1040次。显然,它达到了数据存储的并发写入限制

我决定收集一小时的数据并保存,这就是为什么
HitsStatsDO
中有
avgPercent
hitCount
。GAE实例是无状态的,所以我必须使用

这里我有这样的东西:

// Contains stats for one hour
private class Shard
{
    ReadWriteLock lock = new ReentrantReadWriteLock();
    Map<Integer, HitsStatsDO> map = new HashMap<Integer, HitsStatsDO>(); // Key is target ID

    public void saveToDatastore();
    public void updateStats(Long startDate, Map<Integer, Double> hits);
}
//包含一小时的统计信息
私有类碎片
{
ReadWriteLock lock=new ReentrantReadWriteLock();
Map Map=new HashMap();//键是目标ID
public void saveToDatastore();
公共无效更新状态(长起始日期、地图点击次数);
}
并使用当前小时和前一小时的碎片进行映射(不会在这里停留太久)

private HashMap shards=new HashMap();//钥匙是HitsStatsDO.startDate
所以每小时我会将前一个小时的碎片转储到数据存储中一次

另外,我还有
类生命状态
,它将
映射
保存在memcached中,其中映射键是目标ID

在我的数据库中,我也会将未完成小时的统计数据转储到数据存储中

这里只有一个主要问题-我只有一个后端实例:)它提出了以下问题,我想听听您的意见:

  • 我可以在不使用后端实例的情况下执行此操作吗
  • 如果一个实例还不够呢
  • 如何在多个动态后端实例之间拆分数据?这很难,因为我不知道我有多少,因为随着负载的增加,谷歌会创建一个新的
  • 我知道我可以启动确切数量的常驻后端实例。但是有多少?2, 5, 10 ? 如果我一个星期都没有工作怎么办。持续运行10个后端实例太贵了
  • 当后端实例死机/重新启动时,如何处理来自客户端的数据
需要注意的一点是,我不能改变客户太多。目前,它的JavaScript嵌入到客户的网页中。我可以用某种方式改变RPC,但在架构上我不能用Google文档表单代替客户端


非常感谢您的想法。

开发者不应回避将离线资源、谷歌网站和谷歌数据api与gae集成

你可以建立一个谷歌网站,引导你的调查表格

目标受访者会将他们的答案输入到你的表格中,谷歌网站会在一个谷歌文档电子表格中收集他们的答案

然后使用离线系统(不是gae),通过谷歌数据api定期/每小时访问“电子表格”以下载数据

谷歌文档将为您提供数据输入的时间,而您的表单设计应允许受访者编制索引。这样,您将能够只下载“电子表格”的部分

您需要熟悉OAuth,也许还需要熟悉google federated login/openid consumer

您可以探索将受访者的登录名与您的表单集成

事实上,您甚至不必使用gae

您应该能够使用google sites api更新页面,更新要显示的统计信息,将表单切换到新的电子表格

然后仅使用gae生成特定于用户的页面


或者,如果您的afinity对于gae来说太棒了,您可以使用它生成调查页面,然后使用数据api将结果存储在google文档中,但是,请使用您自己的脱机资源来执行统计计算。

您所描述的模型上遇到并发写入限制的唯一原因是,您正在将所有实例作为同一父实体的子实体。仅当出于事务目的需要同一实体组中的实体时,才有必要这样做,但此处的情况并非如此。删除父属性并将所有实体存储为顶级实体,您就不必再担心更新率。

我的服务上线了,我想分享一下我是如何实现它的

所以,我决定在多个动态后端实例中收集数据,并每隔10分钟从每个实例更新数据存储中当前一小时的碎片,而不是在单个后端实例的内存中收集一小时的数据。类
Shard
保持不变,除了
saveToDatastore()
之外,我现在在事务循环中更新
HitsStatsDOs
,以确保即使另一个后端实例此时更改了Shard,它也会被更新

为了快速获取HitsStatsDO,我决定将目标ID放在假父密钥和时间戳中,如果主ID像这样难以识别的话

public class HitsStatsDO implements Serializable
{
    @Id
    transient private Long id;  // always equals to "startDate"
    @Unindexed
    transient private Long version = (long) 0;

    transient private Long startDate;

    @Parent
    transient private Key targetIdKey;   // fake parent which contains target id

    @Unindexed
    private double avgPercent;
    @Unindexed
    private long hitCount;

    public Key<HitsStatsDO> createKey()
    {
        return new Key<HitsStatsDO>(targetIdKey, HitsStatsDO.class, startDate);
    }

    public HitsStatsDO(Long startDate, long targetId)
    {
        this.id = this.startDate = startDate;
        this.targetIdKey = new Key(Long.class, targetId);
    }
}
public class HitsStatsTotalDO implements Serializable
{
    @Id
    private Long targetId;
    @Unindexed
    transient private Long version = (long) 0;

    @Unindexed
    private double avgPercent;
    @Unindexed
    private long hitCount;
}
同样的事情-2次写入存储/更新

服务
public class HitsStatsTotalDO implements Serializable
{
    @Id
    private Long targetId;
    @Unindexed
    transient private Long version = (long) 0;

    @Unindexed
    private double avgPercent;
    @Unindexed
    private long hitCount;
}