我们使用phpredis Library从我们的服务机器连接到我们的64节点Redis集群。虽然我们使用持久连接,因为php不会跨请求重用对象,但每个请求首先对Redis群集进行 CLUSTER SLOTS 调用,然后进行数据提取。这被证明是非常昂贵的,因为这增加了API和Redis上的CPU,并且还增加了可以缓存的元信息(CLUSTER SLOTS)的网络使用。 基本上,我们希望在同一个php-fpm进程中跨多个请求重用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) {