2013-01-04 139 views
1

我看到一個非常普遍的需求,即更新特定實體類型的所有行的字段或值,並且它通常會跨越10分鐘的隊列限制。批量更新隊列

那麼,什麼是使用任務隊列,可以完成所有行的更新用運行cron作業的最佳方式?

一個我想是生火在cron作業的查詢,然後創建同樣大小的IDS的多個列表好比說每個列表包含100個IDS的方法。然後通過傳遞id列表爲每個列表掃描一個任務。然後在任務代碼geting實體行使用

pm.getObjectId然後處理它。

我仍然覺得這種方法有點手動,不智能。有什麼更好的方法來處理它?

+2

如果您必須對所有行執行操作,將ID集合分配到單個任務是完全合理的方法。什麼是「手動而不是智能」呢? – Amber

+0

那是我對它的感覺。我希望能夠像時間限制即將到來時那樣,以一種聰明的方式來實現它,可能只是關閉持久存儲管理器以保存數據,然後可以產生一個新線程從那裏恢復。我認爲spwaning的線程等仍然可行,但從它離開的地方恢復將使整體的東西變得智能化和更通用 – Vik

+0

如果您將某些東西分成多個批次,您可以並行運行它們,這是一個優秀的解決方案,可以線性運行它們,在事情停止的地方恢復「。 – Amber

回答

2

如果您有現金需要燃燒,請使用後端;他們沒有限制(儘管使用後端來處理一個大的請求是浪費的......只有考慮到這一點,如果你有其他工作,你可以卸載它)。

更可能的是,你真正想做的是分片。也就是說,把一個大的線性任務分解成一堆更小的,可並行化的任務。

一旦我常用的模式使用很多,就是有一個請求只是做派遣......也就是說,查詢你需要做的工作,收集一個鍵操作的列表,並開始批量的工作比如說,一次執行100個任務(發送儘可能多的數據以避免重新查詢,如果不需要的話)。

這樣,只有調度員必須瀏覽完整的數據集,而無需進行任何耗費時間的更新,並且只要它需要不到10分鐘,你應該是金色的。

現在,根據你的實體祖先的設置,你可能會遇到爭試圖更新並行成千上萬的實體(如果您的調度員太快它可以發生)。簡單的解決方案是設置.withCountDownMillis((latency + = 1000)),爲每個請求提供一秒呼吸空間(可能更多,取決於實體大小和每個索引的數量)。基準你的應用程序w/appstats,看看每個實際需要多長時間,並給他們額外的500毫秒以覆蓋標準偏差。

現在......我也有不知道有多少機構您正在使用10分鐘......您是否使用不夠長異步API的使用?批處理請求如何?如果您一次在一個實體上操作,並阻止每個實體的獲取/投入,您將輕鬆達到上限。

而是查看異步請求。使用異步技術,我能夠放出一個推杆,藏起未來,再發射更多,然後等到最終完成未來時,操作已經完成,並且我根據要求支付大約0毫米的牆壁時間。

即使您不能使用低級異步(仍然強烈推薦),請至少考慮使用批處理。也就是說,不要一次放一個,而應該使用一個列表,並且每50個實體進行一次put +清除(如果它們很小,則更多)。這允許appengine內部後端並行所有五十個,因此您需要爲每個實體序列化開銷花費1+時間。

將異步和批處理與非爭用實體相結合,我通常能夠每分鐘處理大約4000個實體。如果你必須做40,000多個實體,那麼你需要考慮正確的分片。爲此,請爲每個(任意選擇的)1000個實體獲取一個密鑰,並啓動從前一個密鑰(或空值)到下一個密鑰進行查詢的任務。這使您可以在短時間內儘可能多地運行多個實體,方法是做一份大的工作並將其轉化爲更小的工作。

+0

如果您有現金需要燃燒,請使用後端; ?那麼動態後端不是爲了不浪費現金而完美? –

+0

目前有7000個實體需要處理。對於我需要創建兩個額外實體的每個實體。所以,你可以說:7000個遍歷和14000個實體需要被創建。 – Vik

+0

添加我不能在這裏進行批處理,因爲我創建兩個實體作爲一個操作,第二個實體需要第一個實體的鍵作爲外鍵。因此,創建類型A的前50個實體,然後將它們與50個子實體相關聯會使其變得更加複雜。 – Vik

1

我用這個任務隊列10分鐘期限內更新數百萬條記錄:

  1. 創建一個循環,在每次迭代中運行一個query with cursor(不要使用offset())。在每次迭代中使用下一個遊標。通過這種方式,您將有效地走完整個目標實體。每次使用limit(1000)可獲得一批1000個實體。也可以使用set the prefetch size到1000來最小化網絡往返。

  2. 對於每個批次,更新屬性,然後執行async put