2011-11-20 46 views
2

我不知道這是不是要問這樣的問題,正確的地方的任何性能優勢,但這裏有雲:使用Redis的使用Rails將提供這種特定類型的查詢

我有一個內聯網樣Rails 3應用程序管理大約20k用戶,它們是嵌套集(預訂樹 - http://en.wikipedia.org/wiki/Nested_set_model)。 這些用戶輸入統計信息(數據,只是純數值)。輸入的統計數據被分配給類別(我們稱之爲指針)和一個星期數字。

這些數據被進一步處理和計算,以結果。 有些是根據用戶活動+其他類別的結果計算的......等等。 用戶輸入的內容與他在報告中看到的內容並不總是相同的。

這些計算可能會非常棘手,有些種類有非常具體的公式。

但剩下的只是「給我所有輸入的值的總和此類別該用戶本星期/月/年」。

問題是那些統計需要也被求和用戶的下選擇的用戶的子集(因此它基本上爲所有用戶返回用戶下的所有值的總和,包括自我)。

這款應用程序已投入使用2年,它的工作相當出色......但越來越多的用戶對於服務器價格較高的報告也很慢,比如「給我所有用戶的列表在我自己和他們的統計數據中,其中一行由他們的小組彙總,一行爲他們的個人統計「)。當然,用戶希望(並且需要)他們的報告儘可能實際,5分鐘以反映新輸入的數據對他們來說太多了。這個特定的報告是他們最喜歡的:/ 要保持實時性,我們不能直接執行高密度的sqls ...這會殺死服務器。所以我只通過後臺進程計算它們,前端只是讀取結果。 那些sql語句是難以優化,我很高興我已經從這種做法感動......

當前的應用程序是這樣的(高速緩存是不是一種選擇,見下文。):

  • 前端:當用戶輸入新數據時,它被保存到簡單的mysql表中,如[user_id, pointer_id, date, value],並且還有插入隊列。

  • 後端:再有就是calc_daemon過程,每5秒檢查新「重新計算的請求」的隊列。我們彈出請求,確定還有哪些需要重新計算(指針有依賴關係......最簡單的情況是:當您更改星期統計信息時,我們必須重新計算月和年統計信息...)。它以簡單的方式完成這種重新計算。我們通過自定義的每個指針來選擇數據 - 由它們的類生成不同的sqls。

  • 這些計算結果被寫回的MySQL,但分區表(一個表每年)。該表中的一行與[user_id, pointer_id, month_value, w1_value, w2_value, w3_value, w4_value]相似。這樣,表格就有〜500k條記錄(我基本上減少了5倍的記錄)。
  • 當前端需要這些結果時,它對這些分區數據做了簡單的總結,並帶有2個連接(因爲嵌套集conds)。

問題是,那些簡單的sqls和sum,group-by-and-on-the-subtree可能每次需要200ms ......只是爲了一些記錄......我們需要運行很多這些sqls ...我認爲他們已經根據explain優化了他們所能做到的最好...但是它們太難了。

所以......這樣一個問題:

我可以重寫這個使用Redis的(或其他快速鍵 - 值存儲),看看從中任何好處時,我使用Ruby和Rails?正如我所看到的,如果我將它重寫爲使用redis,那麼我將不得不運行更多的查詢,而不是使用mysql,然後手動執行ruby中的數據...所以性能會受到影響相當...我真的不知道我是否可以使用redis編寫所有可能的查詢...將用戶加載到rails中,然後執行類似於「redis」的操作,爲用戶提供總計1,2,3, 4,5 ......「似乎並不是正確的想法......但是也許redis中有一些功能可以使這更簡單?)... 此外,樹結構需要像嵌套集,即它不能在redis中有一個條目,對於某些用戶(類似於children_for_user_10: [1,2,3]),因爲樹結構經常變化...所以我無法在這些分區表中獲得這些總和,因爲當樹變化,我將不得不重新計算一切..這就是爲什麼我實時執行這些總和。)

或者你會建議我將此應用重寫爲不同的語言(java?)並計算內存中的結果嗎? :)(我嘗試過使用SOA方式,但是它失敗了,因爲我在Ruby中以XXX兆字節的數據結束了這種或那種方式......特別是在生成報告時......並且gc只是殺死了它.. )(並且副作用是一個生成報告會阻止整個rails應用程序:/)

歡迎提出建議。

+1

從另一個問題http://stackoverflow.com/questions/4846243/redis-sum-of-scores-in-sorted-set它似乎總結在redis是一個不行。 – hellvinz

+0

感謝您的鏈接。看起來像使用鍵值存儲與紅寶石,這種應用程序要求它只是一個沒有去......我可以想象建立一個服務,處理和緩存這些數據在內存中,並將它們用於所有用戶(它會只保留最新的數據)..使用這樣的redis會更簡單,但它必須是快速的(即用php(bleh)或java(uhoh)編寫):(或者我將不得不選擇例如MongoDB ...這是另一種選擇,我應該更新問題以包含它嗎?在重寫之前,我需要一些真實的體驗......需要一週左右的時間:( –

+0

)我們在工作場所使用了Redis,並且我們發現如果你可以簡化你的數據關係到Redis可以解釋的東西,你可以獲得巨大的性能提升。也就是說,我們大多數涉及連接的查詢往往表明DB邏輯太多而無法卸載到Redis上(我們確實嘗試過,但是必須計算Postgres將會正常工作的額外開銷在我們的Rails應用程序中做的事情證明會讓事情變得更糟,而不是更好:P) –

回答

0

Redis會更快,它是一個內存數據庫,但是你可以將所有這些數據放在內存中嗎?正如註釋中所指出的那樣,不推薦使用redis鍵進行迭代,所以我不會使用它來存儲原始數據。但是,Redis通常用於存儲總和的結果(例如記錄事件的計數),例如它具有快速的INCR命令。

我猜你會通過使用存儲過程或比ruby更快的語言(例如C-inline或Go)來進行重新計算,從而獲得足夠的速度提升。你在重新計算中進行分組嗎?是否有可能將分組更改爲編碼結果集的代碼,然後手動檢查「組」更改的時間。例如,如果您按用戶循環並按循環在循環內分組,則將其更改爲按用戶和星期排序,併爲用戶和星期的當前值和先前值以及總和變量保留變量。

這是假設瓶頸是重新計算,您沒有真正提到哪個部分太慢。

相關問題