2013-08-30 43 views
1

我有一個相當CPU密集型的Web應用程序(它基本上是一個字典集合,但它們不只是簡單的字典,它們做了很多東西,無論如何,這是不重要 )。因此,在CPU密集型Web應用程序中,您遇到擴展問題,併發用戶過多,並且響應速度非常慢。服務器端緩存CPU密集型Web應用程序的AJAX請求

我的應用程序的流程是這樣的:

JS - > AJAX調用 - > PHP - > VB6的dll - > VB6代碼查詢字典,做CPU密集型的東西 - >回覆PHP - >回覆JS - > html div得到新內容的更新。顯然,在與IIS 7.5的Windows環境。 PHP只是一種訪問.dll的方式,除此之外別無其他。

回覆/顯示的內容是html格式的文本。 該應用程序有很多PHP文件,這些文件在.dll中調用不同的功能。

所以爲了避免VB6的DLL對於每個請求,這是CPU密集型部分的通話,我想這樣做的:

例如Ajax請求:

php file: displayconjugationofword.php 
parameter: word=lol&tense=2&voice=active 

所以當用戶在上述請求displayconjugationofword.php,我稱之爲VB6的dll,然後就回饋回覆給客戶之前,我可以在MySQL表中添加這樣的請求數據:

filename, request, content 
displayconjugationofword.php, word=blahblah&tense=2&voice=active, blahblahblah 

因此,下一次用戶使EXACT與ajax請求相同時,displayconjugationofword.php代碼(而不是調用vb6 dll)首先檢查mysql表以檢查請求是否存在,如果存在,則從那裏獲取它。

因此,這個MySQL表將逐漸增長,達到3-4萬行,隨着它增長的機會,要求在數據庫中的東西,也成長起來,理論上應該比做cpu密集的來電(每個任何地方從50到750毫秒長)。

您認爲這是實現我想要的一個好方法嗎?或者當mysql表達到3-4百萬個條目時,它也會變慢?

非常感謝您的意見。

編輯

我知道有關IIS輸出緩存,但我認爲,因爲它不是在我的情況非常有用:

1)AFAIK只緩存PHP文件時,它變成「熱」(多查詢)。

2)我確實有一些調用vb6的.php文件,但每次回覆都是隨機的。

+0

如何將HTML存儲爲flatfile並省略db? –

+0

@GerbenJacobs不可能,所有可能的請求的組合是數百萬。 – MIrrorMirror

+0

你有沒有考慮過使用類似'memcached'的東西?您可以爲每個緩存條目指定到期時間,並且在內存填滿時還會刪除舊條目。 – Barmar

回答

1

我喜歡這些情況/謎題!下面是我先問清楚,以確定哪些選項是可行的問題:

  1. 你有多少這樣的查詢將要在給定的時間被重複,一天中的任何想法/感,周? 因爲......'更常見的緩存技術'(即我所見過和/或讀過的技術最多)是使用APC之類的東西,或者爲了可伸縮性而使用Memcache之類的東西。然而,我所看到的是,這些通常用於12小時長的高速緩存中的<。這正是我所看到的。優點:自動清理未使用的物品。

  2. 你可以估計單個'任務'可能需要多長時間嗎? 因爲......這會讓你知道緩存是否變成非生產性的 - 也就是說,當緩存機制比任務慢時。

下面是我建議作爲一個解決方案 - 這一切都來自PHP(毫不奇怪)。在您的工作流程,這將是 PHP幾點:JS - > AJAX調用 - >PHP - > VB6的dll - > VB6代碼查詢字典,做CPU密集型的東西 - >回覆PHP - >回覆JS - > HTML DIV ...

事情是這樣的:

  1. 創建列的表:__id,按鍵,輸出,計數,修改

    1.1。列'__id'是自增列(例如,INT(11) AUTO_INCREMENT),因此也是PRIMARY INDEX

    1。2在MySQL中這樣創建'modified'列:modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

    1.3'key'= CHAR(32)這是MD5散列的字符串長度。 '鑰匙' 也具有UNIQUE INDEX(非常重要!!低於3.3)

    1.4 '輸出'= TEXT由於VB6代碼會比一點點

    1.5 '計數'= INT(8)左右

  2. 散列查詢字符串(「word = blahblah & tense = 2 & voice = active」)。我在想這樣的:$key = md5(var_export($_GET, TRUE));基本上,散列什麼會給一個獨特的輸出。從給出的例子中推導出來,如果案例無關緊要,也許最好是小寫'單詞'。

  3. 對鍵的SELECT的結果運行條件。在僞代碼中:

    3.1。 $結果= SELECT output, count FROM my_cache_table_name WHERE key = "$key"

    3.2。如果(空($結果)){
                $輸出=運行VB6的任務
                $計數= 1
         其他
             結果  $ count = $ result ['count'] + 1

    3.3。運行查詢'INSERT INTO my_cache_table_name (key, output, count) VALUES ($key, $output, $count) ON DUPLICATE KEY UPDATE count = $count'

    3.4。返回$輸出爲「回覆JS」

從長期來看,你不會只有一個緩存,但你也知道正在運行的查詢最少,如果需要,可以修剪它們。就我個人而言,我不認爲這樣的查詢將會非常耗時。當然,你可能會做些什麼來優化緩存/查詢(這超出了我)。

所以我不直接指出的是:上面的工作(和你的建議幾乎一樣)。通過添加「計數」列,您可以查看大量和/或少量的查詢,並可根據需要返回並修剪。

如果您想查看查詢的時間長度,您可以創建另一個包含'key','duration'和'modified'(如上所述)的表。在3.1和3.3之前,獲取microtime()。如果這是一個緩存命中,減去microtime()並存儲在這個新表中'key'= $ key和'duration'= 2nd microtime() - 1st microtime()。然後您可以稍後再回來,按'修改的DESC'進行排序,然後查看查詢的時間。如果你有一個TON的數據,並且最新的'持續時間'還不錯,你可以拉這個整個持續時間記錄機制。或者,如果無聊,只存儲$ key在一個字母結尾的時間(只是爲了減少它在服務器上的負載)

+0

大衛,謝謝你長期和詳細的答覆。我可以問一下第2步,是否有任何特殊的理由來散列查詢字符串? – MIrrorMirror

+0

我的想法是雙重的。 1,它讓你避免擁有一個巨大的「關鍵」字段,以適應任何查詢字符串。 2,MD5速度非常快,所以不會引入非常多的延遲......爲創建密鑰以及搜索該密鑰創造理想的「密鑰」。這對我爲什麼建議MD5哈希值有意義嗎? (對不起,以前忘了解釋一下) –

+0

是的,長度越小越好,我只是擔心潛在的罕見碰撞 – MIrrorMirror

1

我不是專家,但這是一個有趣的邏輯問題。希望下面列出的內容能夠幫助或至少激發評論,這些評論可能會或可能不會有用。

在某種程度上,答案將取決於您可能擁有多少查詢,一次有多少個,以及mysql索引是否比您的權威解決方案快。

然後幾個想法:

這將有可能轉嫁到另一臺服務器很容易,這將允許基本上無限縮放緩存請求。

人類就像它們一樣,大多數單詞請求可能只涉及幾千個單詞,因此您可能會發現所做的大部分工作都很快就會重複進行。這是有道理的,然後創建一個可索引數據庫。

散列在過去被認爲是加快數據索引的好方法。這是否有用一定程度上取決於答案的長度。

如果你非常聰明,你可以確定最多10000個左右的問題和回答,並將它們存儲在一個單獨的表格中,以便更快地做出迴應。 (Guru發表評論?)

你的dll是否已經對請求進行了緩存?如果是這樣,那麼進一步的工作可能會減慢你的服務。

此解決方案適用於使用JS或php進行簡單測試以生成多個請求,以使用或不使用緩存來測試響應速度。無論你決定,我認爲你應該用大量的樣本數據進行測試。

+0

感謝您的回覆Robert。通過「輕鬆地將緩存請求傳遞給另一臺服務器」,您是指我提出的緩存或其他類型的緩存?另外我不確定我是否理解「您的dll是否已經緩存了請求?」每次通過php調用dll,然後立即「死」。我認爲dll不可能以某種方式「記住」請求。 – MIrrorMirror

1

爲了獲得您的示例的最大性能,您需要遵循基本的緩存優化原則。我不確定你的應用程序邏輯是否允許它,但如果它是會給你一個巨大的好處:你需要區分可以被緩存的請求(靜態)和返回動態(隨機)響應的請求。使用一些文件命名規則或提供一些自定義http頭或請求參數 - 即可以用來判斷是否緩存的請求的任何部分。

加快靜態請求。這個想法是處理傳入的請求並儘早發回應答(理想情況下甚至在Web服務器進場之前)。我建議你使用輸出緩存,因爲它會以更高性能的方式在內部執行你想要做的事情。一些選項是:

  1. 使用IIS輸出緩存功能(快速搜索顯示它可以緩存基於請求的文件名和查詢字符串的查詢)。
  2. 在Web服務器前放置一個緩存層。 Varnish(https://www.varnish-cache.org/)是一款靈活而強大的開源工具,您可以根據數據大小(使用內存與磁盤,可以使用多少內存等)最佳配置緩存策略。

加快動態請求。如果它們在內部是完全隨機的(沒有可以被緩存的dll調用),那麼沒有太多的事情要做。如果有一些dll調用可以被緩存,就像你描述的那樣:從緩存中獲取數據,如果它存在,那麼你很好,如果沒有,從dll中獲取並保存到緩存。

但是使用更適合緩存任務的東西 - 像Redis或memcached那樣的鍵/值存儲是很好的。他們非常快。 Redis可能是一個更好的選擇,因爲數據可以持久化到磁盤(而memcached在重新啓動時會丟棄整個緩存,因此需要重新填充)。

+0

使用像清漆這樣的緩存逆向代理時,請記住使用緩存友好(idempotent)HTTP方法。所以,如果你不改變服務器狀態,那就使用GET。 –

+0

我想過IIS輸出緩存,但它不好,它只緩存「熱」或頻繁請求的查詢,這意味着一個不流行的請求不會被緩存,儘管它可能會很慢。我更喜歡緩存所有請求。清漆似乎是一個不錯的選擇,但恐怕它不能在Windows上運行 – MIrrorMirror

+0

同樣來自清漆網站:「清漆緩存通常會通過檢查HTTP主機標頭和URL來查找響應,清漆緩存會維護一個索引,一個哈希,並保存在緩存中的所有主機+網址組合。「我的理解是,它的緩存是PER主機,不是通用的。我希望用戶X完成的請求可以從用戶Y的緩存中提供。 – MIrrorMirror