2017-10-10 104 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