2012-02-05 106 views
6

APC允許您將數據存儲在密鑰中,但不能將這些密鑰分組。帶APC緩存的密鑰組

所以,如果我想有一個名爲「文章」組,該組內我會說拿文章ID我不能做到這一點很容易的形式鍵。

articles -> 5 -> cached data 
     -> 10 -> cached data 
     -> 17 -> cached data 

     ... 

我能前綴,如「集團」名稱的密鑰:

article_5 -> cached data 
article_10 -> cached data 
article_17 -> cached data 

... 

但是,這也使得它無法刪除整個組,如果我想:(

一個工作解決辦法是存儲多維數組(這就是我現在所做的),但我認爲這並不好,因爲當我想要訪問/或刪除緩存數據時,我需要首先獲取整個組。小組有一個十億篇文章,你可以想象什麼樣的數組我會迭代和se弓箭

你有什麼更好的想法,我怎麼能實現團體的事情?


編輯:找到另一種解決辦法,不知道它的要好得多,因爲我不知道是怎麼可靠呢。我添加了一個名爲 __paths的特殊鍵,它基本上是一個多維數組,其中包含緩存中所有其他條目的全部前綴鍵路徑。當我請求或刪除緩存時,我使用這個數組作爲參考,以快速找出我需要刪除的密鑰(或密鑰組),所以我不必存儲數組並重復遍歷所有密鑰...

回答

18

基於你的觀察,我看着底層的C實現APC的緩存模型(apc_cache.c)的,看看我能找到。

該源證實了您的觀察結果,即在後備數據存儲中不存在任何分組結構,因此任何鬆散分組的對象集合都需要根據某些名稱空間約束或對緩存層本身的修改來完成。我希望能夠通過鏈表找到一些依賴於鑰匙鏈的後門程序,但不幸的是,似乎碰撞是通過直接重新分配衝突插槽而不是chaining來調和的。

APC似乎對用戶條目使用了顯式緩存模型,從而防止它們老化掉。所以,the solution Emil Vikström provided那依靠LRU型號的memcached不幸的是,不會工作。

不修改APC本身的源代碼,這是我會做:

  1. 定義命名空間約束您的條目符合。正如你上面最初定義的那樣,這將是前綴到每個條目的article_

  2. 定義一個單獨的這個集合中的元素列表。實際上,這將是上面描述的51017方案,但在這種情況下,您可以使用某種數字類型使其比存儲大量字符串值更有效。

  3. 定義一個接口到更新此指針集合和與背襯存儲器高速緩存協調它們,包括(至少)的方法insertdelete,和clear。當調用clear時,遍歷每個指針,重新構建在後備數據存儲中使用的密鑰,並從緩存中清除每個指針。

什麼我主張這裏是一個定義明確的對象進行操作,你尋求有效。這與您的子緩存中的條目數成線性比例關係,但由於您對每個元素使用的是數字類型,因此在開始在約束條件下開始體驗真正的內存痛苦之前,您需要超過1億個條目,例如,幾百兆字節。


塔馬斯Imrei打我suggesting an alternate strategy我已經在記錄的過程,但是這有一些重大缺陷,我想討論。

如在所述背襯的C代碼所定義,APCIterator是在整個數據的線性時間的操作執行搜索時(使用它的構造,public __construct (string $cache [, mixed $search = null ...]]))設置

如果您要搜索的背景元素只佔總數據的一小部分,那麼這會非常不可取,因爲它會遍歷緩存中的每個元素以找到所需的元素。引用apc_cache.c

/* {{{ apc_cache_user_find */ 
apc_cache_entry_t* apc_cache_user_find(apc_cache_t* cache, char *strkey, \ 
    int keylen, time_t t TSRMLS_DC) 
{ 
    slot_t** slot; 
    ... 
    slot = &cache->slots[h % cache->num_slots]; 
    while (*slot) { 
     ... 
     slot = &(*slot)->next; 
    } 
} 

因此,我最強烈建議使用一個高效,基於指針的虛擬分組解決您的問題,因爲我在前面已經勾勒出來。儘管在嚴重限制內存的情況下,迭代器方法可能是最正確的,但是會以犧牲計算爲代價來節省儘可能多的內存。

祝您的應用程序好運。

+1

不錯的工作!我強烈建議閱讀這篇文章。 – 2012-04-14 10:03:12

+1

@EmilVikström謝謝!我很高興我的工作很有見地。 – MrGomez 2012-04-14 14:58:20

4

我與memcached的一次有這個問題,我在我的鑰匙使用的版本號,這樣解決了這個問題:

version -> 5 
article_5_5 -> cached data 
article_10_5 -> cached data 
article_17_5 -> cached data 

只要修改的版本號和組將有效地「水漲船高」!

memcached的使用,最近最少使用策略來刪除舊數據,所以舊版本化集團將從緩存中需要空間時被刪除。 我不知道APC是否具有相同的功能。根據MrGomez,這不適用於APC。請閱讀他的帖子,並記住我的帖子僅適用於其他使用最近最少使用策略(而非APC)的緩存系統。

+0

APC沒有LRU策略,但apc_add確實允許TTL,生存時間。因爲它的LRU,Memcache在這種情況下會是這種數據的更好選擇。 – 2012-04-16 13:24:26

3

您可以使用存在尤其是對於像這樣的任務,這似乎給APCIterator class

的APCIterator類可以更容易地遍歷大APC緩存。這是有幫助的,因爲它允許在迭代步驟中的大緩存...

1

不幸的是,APC不能這樣做。我希望自己能夠經常這樣做。所以我尋找替代品。

Zend_Cache有一個有趣的做法,但它只是使用緩存來緩存標記信息。這是一個可以反過來使用後端的組件(如apc)。如果你想更進一步,你可以安裝Redis。這個包含了所有原生包含的內容以及其他一些非常有趣的功能。這可能是最乾淨的解決方案。如果你能夠使用APC,你應該也可以使用Redis。