2016-06-14 26 views
1

私は、ほぼ60システムからのデータを格納するために共通のredisを使用しています。この共通のredisは、すべてのマシン間の通信に使用されます。最初はすべてが正常に動作していたようですが、マシンを60から80に増やすと、再接続への接続数が増え、その後大きな問題を引き起こす接続を受け入れなくなりました。TIME_WAIT状態で開かれた複数の接続を再開する

「netstat -na |」を使用して問題をデバッグし始めたとき、 grep 6379 'redisに接続するたびに、特定のポートでTCP/IP接続を開き、その接続を解放せず、$ redis-> quit()を呼び出した後でもTIME_WAIT状態でほぼ60秒間その接続を保持していたことがわかりました。私はこの問題を克服しようとした

メソッド(PHPのpredisライブラリを使用して):

1)Iは、/ proc/sys/net/IPv4の/ tcp_fin_timeoutでTIMEWAIT秒を減少しようとしたが、それは正しい解決策ではありませんでした。

2)I)はnodejsにPHPからシフトしnodejsに接続プーリングを試みたが、何success.Hereサンプルコード

app.get('/setinredis',function(req,res){ 

var poolRedis = require('pool-redis')({ 
    'host': 'localhost', 
    'password': '', 
    'maxConnections': 5 
    }); 

    poolRedis.getClient(function(client, done) { 

     client.get('somekey', function(err, value) { 
      console.log('value from redis is:', value); 
      done(); 
      res.send({message:"Done"}); 
     }); 
    }); 

}ではありません。

この問題を効率的に解決する方法はありませんか、またはデータ構造機能を持つ任意の代替方法がありますか。

ご協力いただければ幸いです。

+0

私はあなたがpredisライブラリ上)(終了使用していたことを読んだことがある '$クライアント - > disconnect() '?私はphpredisを使用していますが、close()を使用することもできます。 – Efx

答えて

0

問題は、誰かがあなたの/setinredisエンドポイントに当たるたびにプールを作成していることです。つまり、そのエンドポイントに1000回ヒットした場合は、1000個のプールが作成されます。ルートの外にプールの作成を移動:

var poolRedis = require('pool-redis')({ 
    'host': 'localhost', 
    'password': '', 
    'maxConnections': 5 
}); 

app.get('/setinredis',function(req,res){ 
    poolRedis.getClient(function(client, done) { 
     client.get('somekey', function(err, value) { 
      console.log('value from redis is:', value); 
      done(); 
      res.send({message:"Done"}); 
     }); 
    }); 
}); 

編集:それはコードがNode.js.である、まだPHPを指すサイドノートとして、あなたの質問は混乱しています

+0

でもTIME_WAIT状態を開いた状態で複数の接続を試みました。 – Vibhas

+0

redisパイプライニングでは、たくさんのソケットを開く必要はありません。 TIME_WAITにあるソケットは、使用可能なすべてのポートを使い果たした場合に限り、必ずしも問題ではありません。 – MrWillihog

+0

私は即座に各システムの応答を追跡する必要があるため、ここでパイプライン処理が機能するかどうかはわかりません。 – Vibhas

0

この方法で試してください。正常に動作するはずです。

=== === controller.js

const user = require('./user')() 

user.getUser('12345') 
    .then(user => { 
    console.log(user.xxxx) 
    }) 

=== === user.jsの

const redis = require('redis'), 
     Promise = require('bluebird') 

function getUser(id) { 
    return redis.getAsync(id) 
    .then(user => JSON.parse(user)) 
} 

module.exports =() => { 
    Promise.promisifyAll(redis.RedisClient.prototype) 
    Promise.promisifyAll(redis.Multi.prototype) 

    return new Promise((resolve, reject) => { 
    const client = redis.createClient(REDIS_SERVER) 
    client.on('connect', onConnect) 
    client.on('error', err => { 
     throw err 
    }) 

    function onConnect() { 
     return resolve({ 
     getUser 
     }) 
    } 
    }) 
} 
0

これは、LinuxにおけるTCPフィンタイムアウト(デフォルト60秒とは何かであります)。おそらく、あなたは接続を再利用していないのですが、毎回新しいものを開くことは間違いありません。しかし、このように高速に処理している場合は、使用可能なすべてのポートを使用する危険性があります。このsysctlパラメータを使用してtcp finタイムアウトを減らし、tcp_reuse接続を有効にする必要があります。

net.ipv4.tcp_tw_reuse = 1 
net.ipv4.tcp_fin_timeout = 10 #value is in seconds 

TCPの再利用tcp_tw_reuse LinuxカーネルはTIME_WAIT状態にある接続から接続スロットを再利用し、新しい接続にそれを再割り当てすることができます。ソケットを再利用することは、サーバーの負荷を軽減する上で非常に効果的です。 tcp_fin_timeout

は、TCP/IPは、閉じられた接続を解放し、そのリソースを再利用できるようになるまでに経過しなければならない時間を決定します。このTIME_WAIT状態の時には、クライアントへの接続を再開することは

が参考に新しい接続を確立するよりも少ないコスト:あなたがしようとした持ち、http://www.speedguide.net/articles/linux-broadband-tweaks-121

関連する問題