2017-10-10 14 views
1

phpredisライブラリを使用して、サービングマシンから64ノードRedisクラスタに接続します。私たちは永続的な接続を利用していますが、phpは要求を渡ってオブジェクトを再利用しないので、すべての要求は最初にを呼び出してデータフェッチを行います。これは、APIとRedisの両方でCPUを増やし、キャッシュされる可能性のあるメタ情報(CLUSTER SLOTS)のネットワーク使用量を増加させるため、非常にコストがかかることがわかります。 基本的には、同じphp-fpmプロセスで複数のリクエストにわたってRedisクラスタ接続オブジェクトを再利用したいと考えています。これを行う方法に関する提案はありますか?phpredis Redisクラスタ接続オブジェクトの再利用

更新:cluster_library.cコードで次のdiffを試しましたが、これは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の開発者はここになります。現在のところ、新しいリクエストごとにCLUSTER SLOTSコマンドを発行しなければならないので、これはphpredisの制限/欠陥です。私が知る限り、これを避ける唯一の方法は、CodisまたはCorvisのようなプロキシにphpredisを指すことですが、私はそれらを使って個人的な経験をしていません。

つまり、私はthisブランチでこの機能の実験的サポートを実装しました。 PHPのpersistent_listを使用してリクエスト間のスロット情報をキャッシュします。

Redis Clusterの採用が急増しているように見えるので、私はこれをメインラインの開発ブランチにすぐに、そしておそらく次の安定版に入れるつもりです!

乾杯、

マイクマイクは、しかし、私はcluster_get_slots(シードTSRMLS_CC)をコールしないようにcluster_map_keyspaceコマンドを変更することにより単純化溶液を試み
+0

おかげ。毎回スロットをグローバル変数にキャッシュします。私はまた、cluster_free_reply(slots、1)がスロットメモリを解放しないように呼び出すとコメントしました。それはスタンドアロンのシナリオでは動作しますが、php-fpm + nginxセットアップでは失敗します。なぜこれが起こっているのかについての考えはありますか? – sreeraag

+0

はい、Zendフレームワークには独自のアロケータが用意されているため、変数を解放することを忘れた場合には後から取り除かれます。そのため、リクエスト間のコンテキストを保持するために、persistent_listなどのようなものを使用する必要があります。あなたは永続メモリ(pemalloc)を割り当てることができますが、私はそれをお勧めしません。 :) –

+0

これについて考えていなかった!ありがとうマイク!しかし、これはスタンドアロンのPHPプロセスを使ったテストスクリプトでは動作しますが、nginx + phpfpmセットアップでは失敗しました。これは奇妙です。なぜあなたはpemallocを勧めないでしょうか?また、私は、ファイルへのクラスタスロット応答のシリアライズと毎回ファイルからのフェッチについて考えていました。これは良い考えだと思いますか?または、persistent_listを使用するブランチでは、CLUSTER SLOTSをキャッシュしていないと思います。それを有効にするには? – sreeraag

関連する問題