2010-06-22 168 views
18

如何在PHP中存儲值而不讀取它的情況下如何檢查PHP?我不喜歡讀取它,因爲我設置的值都是1MB大小,讀取後我沒有用,所以我浪費資源。我在腳本中使用它來檢查某些鍵是否緩存在緩存中,如果不緩存,它會從緩慢的數據源中讀取它們並將它們設置在緩存中。檢查Memcache中是否存在一個密鑰

編輯:如果我使用Memcached::appendNULL附加到我檢查的密鑰上該怎麼辦?成功時返回TRUE或失敗時返回FALSE。如果密鑰不存在,則Memcached::getResultCode將返回Memcached::RES_NOTSTORED。這樣我檢查密鑰是否存在,它應該把密鑰放在LRU列表的頂部嗎?

謝謝。

回答

3

基本上你想要做的就是用你的數據填充memcached,對吧?

問題是,問一個關鍵是否存在沒有檢索值是沒有用的。看到這種情況下:

你問是否存在一個密鑰,它確實存在。就在你問了之後,密鑰的數據就從緩存中被逐出。雖然你的迴應是說日期在那裏,但事實是數據不存在。所以你花時間去問,因爲答案與現實不同。

我猜你想要做的是詢問一個密鑰是否存在,然後如果不存在,請填寫數據。你爲什麼不直接填寫所有的數據?順便說一句,你有沒有想過,當你用數據填充memcached時,你可能會驅逐剛纔插入的鍵?

+0

是的,但我首先需要確定它尚未設置。因爲如果它已經設置好了,那麼我會浪費從一個緩慢的來源讀取數據。如果我使用get()來檢查,那麼我將浪費網絡IO,因爲值爲1MB是大小。 – Matic 2010-06-22 07:41:13

+0

@Matic「問題」是memcached沒有設計網絡IO,所以我想這就是爲什麼這種功能被省略的原因。如果網絡IO是一個問題,那麼你最好使用kv數據庫。我明白,即使網絡IO不是問題,但有時候您不需要額外分配,但memcached無法實現這一點。 Redis有這樣的功能。 – themihai 2016-04-22 16:32:23

6

我不知道這是否是對你有些幫助,但你可以使用

Memcache::add ( string $key , mixed $var) 

它會返回false如果該鍵已經存在。

如果返回true,你可以使用

Memcache::delete ( string $key) 

刪除剛纔設置的關鍵。這樣你就不需要獲取數據。

+0

如果它返回true,不要忘記做一個Memcached ::刪除後 – 2010-06-22 07:37:45

+0

@Serty Oan:都寫同一時間:) – Thariama 2010-06-22 07:44:26

+0

偉大的思想想象一樣;) – 2010-06-22 07:53:12

0

從Memcached的角度來看,這沒有任何意義。如果您想避免緩慢的數據源(按預定作業,我假設?),請將數據保存到計劃作業中更快但穩定的數據源(例如文件)。當你需要這些數據時,首先嚐試從Memcached中讀取數據,如果讀取失敗,則讀取文件並將其保存到Memcached中。

Memcached不能給你一個很好的答案,因爲pakore已經回答了。架構並不意味着成爲一個穩定的數據源。

3

我已經通過使用Memcached :: append解決了這個問題。我嘗試追加值NULL,如果它返回TRUE,這意味着密鑰存在。如果它返回FALSE,則表示該鍵不存在。如果密鑰存在,它也會將其放在LRU列表的頂部。

+1

您需要確保'Memcached :: OPT_COMPRESSION'設置爲false,否則操作將始終失敗。另外,最好將空字符串*''*替換爲* NULL * .. – 2013-04-04 06:39:21

+0

對於那些使用'Memcache',而不是'Memcached':'append'方法只適用於後者。 – TheFrost 2014-01-10 01:51:36

2

我不喜歡添加/刪除建議,因爲它會插入無效的數據,您的應用程序可能依賴於有效。如果您的應用程序確實做出了這個假設,那麼會由於它引入的競爭條件而導致每隔一段時間發生一次微妙的錯誤。

一個解決方案是看看這個值,如果它的臨時數據假裝它不存在,但是這將需要所有的應用程序代碼使用相同的api,或者你需要更新應用程序本身,並且由於額外的複雜性而容易出錯。

如果這組鍵足夠小,您可以將它存儲在memcached中,並使用它來確定是否再次從源檢索數據。但是,如果它的值越大或越大,則此方法的性能越差,那麼只需從memcached中獲取整個值即可。

然後,您可以通過使用一個索引你的鑰匙分成較小的集解決新問題(當然是一個很好的方式來分片這個數據,因此每個桶是具有一定規模說起來容易,於是做了。)

該實現將包括使用memcached append或prepend來維護與一些主密鑰綁定的密鑰列表或指向指向密鑰本身的一組子密鑰的主密鑰:)

無論你如何製作應用程序越來越複雜,所以我只會建議如果確實存在瓶頸(比如需要經常通過網絡檢查密鑰的存在),或者如果使用usabil關注(延遲)。

在我的情況下,我不會這樣做,因爲我只打算通過本地主機訪問memcached,並將其用作我的應用程序的一個擴展,以緩存需要幾秒鐘才能正常加載的資源。

0

最簡單的方法是獲得給定的鍵並將其轉換爲布爾值。

(bool) Memcache::get(string $key) 
+1

正如OP所說,由於數據量很大,他不想「獲取」。 – 2013-04-04 06:41:41

1

根本不可能,不可能檢查只有鑰匙是否存在。 更好地創建具有真/假值的單獨的密鑰來檢查按鍵

0

的存在(有點晚了討論,但是)實際上,你可以訪問所有存儲在內存緩存,每個鍵/值:

$allSlabs = $memcache->getExtendedStats('slabs'); 
$items = $memcache->getExtendedStats('items'); 

foreach ($allSlabs as $server => $slabs) 
    foreach ($slabs as $slabId => $slabMeta) 
     foreach ($memcache->getExtendedStats('cachedump', (int) $slabId) as $entries) 
      if (!empty($entries)) 
       foreach ($entries as $key => $entry) 
+0

它會起作用,但它類似於使用大錘來破解核桃,每次只是爲了檢查密鑰是否存在而花費在開銷上,那麼簡單地獲取數據並檢查結果代碼將不那麼繁重。 – 2015-11-25 14:19:37

+0

@SteveChilds - 如果您不知道確切的關鍵值,它會變得很有用。例如 - 如果您在類似鍵(object_type-object_id#object_options)下存儲了memcache中的某些對象實例,並且想要重新加載object_type-object_id的所有實例。真的,這一切都取決於設置和代碼庫。 – eithed 2015-11-27 11:22:39

+0

啊,好的 - 是的,在你的用例中它確實有意義,但在OP的背景下,它的矯枉過正。 – 2015-11-28 09:50:13

4

我想知道爲什麼Memcached沒有特殊的方法。下面是一些考慮之後我想到的:

function has($key) 
{ 
    $m->get($key) 

    return \Memcached::RES_NOTFOUND !== $m->getResultCode(); 
} 
1

memcached現在有了cas命令。你可以用它獨特的一個CAS爲0,以獲得EXISTS或NOT_FOUND迴應:

$ telnet localhost 11211 
Trying 127.0.0.1... 
Connected to localhost. 
Escape character is '^]'. 
set hello 0 0 5 
12345 
STORED 
gets hello 
VALUE hello 0 5 6743 
12345 
END 
cas hello 0 0 0 0 

EXISTS 
cas foo 0 0 0 0 

NOT_FOUND 

在上面的成績單,我先用set命令設置一個關鍵你好值爲12345然後得到它回來,其中還返回一個cas獨特的6743.然後,我嘗試使用cas命令將值替換爲無,但因爲我使用的cas是0,所以我收回了EXISTS錯誤。

最後我嘗試用cas來設置一個不存在的鍵foo並返回NOT_FOUND錯誤。

因爲memcached爲cas唯一使用全局遞增值,所以使用0是安全的,它對您嘗試設置的項無效,如果它存在,您將返回EXISTS錯誤。

對不起,不熟悉php的memcache客戶端把它放在php代碼中。

0

我需要一個可靠的測試來知道是否使用memcache Set或memcache替換。

這是我結束了。

另一種選擇是爲memcache查詢設置一個網絡套接字,但最終它會做同樣的事情,並且這個連接已經存在,從而節省了製作和維護另一個連接的開銷,就像Joel Chen的回答。

$key = 'test'; 
$value = 'foobarbaz'; 
/** 
* Intricate dance to test if key exists. 
* If it doesn't exist flags will remain a boolean and we need to use the method set. 
* If it does exist it'll be set to integer indicating the compression and what not, then we need to use replace. 
*/ 
$storageFlag = (is_null($value) || is_bool($value) || is_int($value) || is_float($value) ? false : MEMCACHE_COMPRESSED); 
$flags = false; 
$memcache->get($key, $flags); 
if(false === $flags) { 
    $memcache->set($key, $value, storageFlag , $minutes); 
} 
else { 
    $memcache->replace($key, $value, storageFlag, $minutes); 
} 

現在,如果您有「大數據」,解決方案相當簡單。使用包含一些簡單的整數來檢查的聯合中的第二個鍵。總是一起使用它們,你沒有問題。

$key = 'test'; 
$value = 'foobarbaz'; 

$storageFlag = (is_null($value) || is_bool($value) || is_int($value) || is_float($value) ? false : MEMCACHE_COMPRESSED); 
$flags = false; 
$exist_key = $key.'_exists'; 

$memcache->get($exist_key, $flags); 
if(false === $flags) { 
    $memcache->set($key, $value, storageFlag , $minutes); 
    $memcache->set($exist_key, 42, false , $minutes); 
} 
else { 
    $memcache->replace($key, $value, storageFlag, $minutes); 
    $memcache->replace($exist_key, 42, false , $minutes); 
} 
相關問題