2017-10-10 107 views
1

我們使用phpredis庫從我們的服務機器連接到我們的64節點Redis集羣。儘管我們使用持久連接,但由於php不會跨請求重用對象,因此每個請求都會首先調用Redis羣集,然後進行數據提取。由於這增加了API和Redis上的CPU,並且還增加了可以被緩存的元信息(CLUSTER SLOTS)的網絡使用,這證明是非常昂貴的。 基本上,我們希望Redis集羣連接對象在同一個php-fpm進程中跨多個請求重用。有關如何做到這一點的任何建議?phpredis Redis集羣連接對象跨請求重用

更新:我試圖在cluster_library.c代碼中的以下差異,但這似乎是導致在php中的隨機運行時異常。

index 3e532b7..b2cbf16 100644 
--- a/cluster_library.c 
+++ b/cluster_library.c 
@@ -7,6 +7,10 @@ 
#include <zend_exceptions.h> 

extern zend_class_entry *redis_cluster_exception_ce; 
+int cache_count = 0; 
+//Cache the cluster slots value for every n requests/calls, n being 100 for now 
+int CACHE_COUNT_VAL = 10; 
+clusterReply *permSlots=NULL; 

/* Debugging methods/ 
static void cluster_dump_nodes(redisCluster *c) { 
@@ -939,7 +943,18 @@ PHP_REDIS_API int cluster_map_keyspace(redisCluster *c TSRMLS_DC) { 
     } 

     // Parse out cluster nodes. Flag mapped if we are valid 
-  slots = cluster_get_slots(seed TSRMLS_CC); 
+ if (permSlots && cache_count <= CACHE_COUNT_VAL) { 
+   slots = permSlots; 
+   cache_count++; 
+ } 
+ else { 
+   slots = cluster_get_slots(seed TSRMLS_CC); 
+ } 
+ 
     if (slots) { 
      mapped = !cluster_map_slots(c, slots); 
      // Bin anything mapped, if we failed somewhere 
@@ -951,8 +966,16 @@ PHP_REDIS_API int cluster_map_keyspace(redisCluster *c TSRMLS_DC) { 
     if (mapped) break; 
    } ZEND_HASH_FOREACH_END(); 

+ if((!permSlots && mapped && slots) || 
+    cache_count >= CACHE_COUNT_VAL) { 
+ permSlots = slots; 
+ cache_count = 0; 
+ } 
+ 
    // Clean up slots reply if we got one 
- if(slots) cluster_free_reply(slots, 1); 
+ // if(slots) cluster_free_reply(slots, 1); 

    // Throw an exception if we couldn't map 
    if(!mapped) { 

回答

2

這裏是phpredis的開發者。目前,這是對phpredis的限制/缺陷,因爲它必須爲每個新請求發出CLUSTER SLOTS命令。據我所知,唯一的方法是避免將phpredis指向CodisCorvis這樣的代理服務器,但我沒有任何使用它們的個人經驗。

這就是說,我沒有在this分支中實現對此功能的實驗性支持。它使用PHP的persistent_list緩存跨請求的插槽信息。

由於Redis集羣的採用似乎在不斷增加,我將盡快將這個版本納入主線開發分支,並可能進入下一個穩定版本!

乾杯, 麥克

+0

感謝麥克,但是,我試圖通過改變cluster_map_keyspace命令不調用cluster_get_slots(種子TSRMLS_CC)一個簡單的解決方案;每次都緩存全局變量中的插槽。我還評論了cluster_free_reply(插槽,1)呼籲它不釋放插槽內存。它在獨立場景中工作,但在php-fpm + nginx安裝程序中失敗。任何想法爲什麼發生這種情況? – sreeraag

+0

是的,因爲Zend框架提供了自己的分配器,如果你忘記釋放一個變量,它將在你之後清理。這就是爲什麼你必須使用諸如persistent_list或類似的東西來保留請求之間的上下文。你可以嘗試分配永久內存(pemalloc),但我不推薦它。 :) –

+0

不知道這個!謝謝邁克!但是這個工作在一個獨立的php程序的測試腳本中,但是在一個nginx + phpfpm設置中失敗了,這很奇怪。你爲什麼不推薦pemalloc?此外,我正在考慮序列化羣集插槽每次回覆文件並從文件中提取。你認爲這是一個好主意嗎?或者使用persistent_list的分支,我不認爲是開箱即用緩存CLUSTER SLOTS。我如何啓用它? – sreeraag