2

我對StackOverflow比較陌生,不確定它是否適合提問設計問題。網站給我一個提示「你問的問題看起來很主觀,很可能會被關閉」。也許應該詢問programmers.stackexchange.com。請告訴我。如何平衡Google App Engine的多個* dynamic *後端實例的負載?

無論如何..我正在進行的項目之一是在線調查引擎。這是我在GAE上的第一個大型商業項目。

我需要你的建議,以便如何收集統計數據並有效地將它們記錄在DataStore中而不會破壞我的數據。最初的要求是:

  • 用戶完成調查後,客戶端發送對[ID(int)+ PercentHit(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個寫/秒。顯然,它達到了Datastore的併發寫入限制。

我決定收集一小時的數據,除此之外,這就是爲什麼avgPercenthitCountHitsStatsDO。 GAE實例是無狀態的,因此我必須使用dynamic backend instance

在那裏,我有這樣的事情:

// 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); 
} 

,並與碎片對當前小時和前一小時(不留在這裏長期)

private HashMap<Long, Shard> shards = new HashMap<Long, Shard>(); // Key is HitsStatsDO.startDate 

所以每小時一次我映射將前一小時的碎片轉儲到數據存儲。

另外我還有class LifetimeStats它將Map<Integer, HitsStatsDO>保留在memcached中,其中map-key是目標ID。

同樣在我的backend shutdown hook method我將未完成小時的狀態轉儲到數據存儲。

只有一個在這裏主要的問題 - 我只有一個後端實例 :)它提出了以下關於這一點我想聽聽你的意見的問題:在不使用後端

  • 我能做到這一點實例?
  • 如果一個實例不夠,該怎麼辦?
  • 如何在多個動態後端實例之間拆分數據?這很難,因爲我不知道我有多少人,因爲隨着負載的增加Google會創建新的。
  • 我知道我可以啓動居民後端實例的確切數量。但有多少? 2,5,10?如果我一週沒有任何負擔,該怎麼辦?不斷運行10個後端實例太昂貴了。
  • 在後端實例死機/重新啓動時,如何處理來自客戶端的數據?

有一點要注意的是我不能更改客戶端。目前,JavaScript嵌入到客戶的網頁中。我可以通過某種方式更改RPC,但在體系結構上,我無法用Google文檔格式替換客戶端。

非常感謝你的想法。

回答

0

我的服務開始了,我想分享我是如何實現它的。

因此,不是在一個小時內收集單個後端實例的內存中的數據,而是決定將它收集到多個動態後端實例中,並在每個實例每隔10分鐘更新Datastore中當前小時的分片。類Shard保持不變,但saveToDatastore()除外,我現在在事務循環中更新HitsStatsDOs,以確保即使另一個後端實例此刻更改分片,也會更新它。

爲了獲取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); 
    } 
} 

這個實體僅需2寫入存儲。寫入量永遠不會超過每小時([後端實例數量] * 2 * 6),這並不壞。此外,我可以在我的代碼中預先創建密鑰,並從Datastore進行批量獲取。

同樣我改變了HitsStatsTotalDO其中包含調查開始的統計數據。它看起來像這樣

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寫入存儲/更新。

服務於3天前上線。迄今爲止最大負載爲230 QPS。我正在使用動態B1類型的實例。在配置中,我現在設置了最多4個實例,但對於我的樂趣,GAE從未實例化過多個實例。令人驚訝的是,我還沒有併發異常。

讓我知道如果您有任何問題或想我錯過了什麼。

謝謝大家的幫助。 StackOverflow是非常棒的社區。

1

開發人員不應該回避將離線資源,谷歌網站和Google數據API與gae集成在一起。

您可以設置一個導致您的調查表單的谷歌網站。

目標受訪者會將自己的答案輸入到您的表單中,並且Google網站會將其收集到單個Google文檔電子表格中。

然後,您可以使用一個離線系統(而不是gae)來定期/每小時訪問一次「電子表格」並通過google數據API來下載數據。

Google文檔會爲您提供輸入數據的時間,而您的表單設計應該能夠讓受訪者進行索引。這樣,您將只能下載「電子表格」的各個部分。

您需要熟悉OAuth以及Google聯合登錄/ openid使用者。

您可以探索將受訪者的登錄與您的表單集成在一起。

事實上,你甚至可能不需要使用gae。

你應該可以使用谷歌網站API來更新你的頁面,更新要顯示的統計信息,將表格切換到新的電子表格。

然後使用gae僅用於生成用戶特定的頁面。

或者,如果您對gae有太大的親和力,您可以使用它來生成調查頁面,然後使用數據api將結果存儲在Google文檔中,但使用您自己的離線資源執行統計計算。

+0

謝謝您的反饋!不幸的是,我無法徹底改變客戶。我應該在原帖中提及它。我更新了它。再次感謝! – expert

+1

文檔格式不會擴展到一百萬個受訪者。 –

+0

「文檔表單不會擴展到一百萬個受訪者」 - Google說的是什麼?像谷歌博客頁面不會擴展到一百萬讀者?請記住,匿名無法擊敗亞馬遜。會有一百萬用戶關閉一個谷歌頁面嗎? –

0

您在描述的模型上遇到併發寫入限制的唯一原因是因爲您正在創建同一父級的所有實例子實體。只有當您需要同一個實體組中的實體出於交易目的時才需要這樣做,但在此情況並非如此。刪除父級屬性並將所有實體存儲爲頂級屬性,並且不再需要擔心更新率。

+0

讓我來粗略計算成本。所以我想我會有6個寫操作每個實體(2爲實體+2爲索引的targetId + 2爲索引的時間戳)。然後調查3K目標和4M用戶將給我12'000'000'000新的HitsStatsDO實體。這是72B寫($ 0.1/100K)+ 12B小($ 0.01/100K),分別是$ 72K + $ 1200。對於一個受歡迎的調查來說,73.2美元是相當苛刻的價格:( – expert

+0

@ruslan在這種情況下,「3k目標」是什麼? –

+0

這些參考答案是與用戶的答案進行比較的,例如它可能是關於政治/社交/經濟偏好,3000名政治家參與調查,然後公衆也接受調查,現在你可以看到哪個候選人更接近大多數人的觀點,更簡單的例子是太陽鏡網上商店,你不知道你想買什麼。 10個問題,它給你什麼太陽鏡是最適合你的。:)類似的東西:) – expert