Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php Redis以TIME\u WAIT状态打开多个连接_Php_Node.js_Redis_Tcp Ip_Netstat - Fatal编程技术网

Php Redis以TIME\u WAIT状态打开多个连接

Php Redis以TIME\u WAIT状态打开多个连接,php,node.js,redis,tcp-ip,netstat,Php,Node.js,Redis,Tcp Ip,Netstat,我使用common redis存储来自近60个系统的数据。这个common redis用于所有机器之间的通信。起初,一切似乎都很正常,但随着我将机器从60台增加到80台,到redis的连接数量增加了,此后它就不再接受任何连接,这导致了一个大问题 当我开始使用“netstat-na | grep6379”调试这个问题时,我发现无论何时连接到redis,它都会在特定端口打开一个TCP/IP连接,并且没有释放该连接,并且即使在调用$redis->quit()之后,该连接仍保持时间等待状态近60秒(使用

我使用common redis存储来自近60个系统的数据。这个common redis用于所有机器之间的通信。起初,一切似乎都很正常,但随着我将机器从60台增加到80台,到redis的连接数量增加了,此后它就不再接受任何连接,这导致了一个大问题

当我开始使用“netstat-na | grep6379”调试这个问题时,我发现无论何时连接到redis,它都会在特定端口打开一个TCP/IP连接,并且没有释放该连接,并且即使在调用$redis->quit()之后,该连接仍保持时间等待状态近60秒(使用PHP的predis库)

我试图克服这个问题的方法:

1) 我试图在/proc/sys/net/ipv4/tcp\u fin\u timeout中减少timewait秒数,但这不是正确的解决方案

2) 我从PHP转到了nodejs,并尝试在nodejs中使用连接池,但没有成功

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"});
        });
    });
}))

是否有任何方法可以有效地解决此问题,或者使用数据结构功能替代redis


任何帮助都将不胜感激。

问题是每次有人点击您的
/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"});
        });
    });
});

编辑:作为旁注,您的问题令人困惑,因为它涉及到PHP,但代码在Node.js中。

问题是每次有人点击您的
/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"});
        });
    });
});

编辑:作为旁注,您的问题令人困惑,因为它涉及PHP,但代码在Node.js中。

请尝试这种方式,它应该可以正常工作

==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
      })
    }
  })
}

请用这种方法试试,应该可以

==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
      })
    }
  })
}

这与TCP fin超时有关(Linux中默认为60秒)。可能您不是在重复使用连接,而是每次都打开一个新的连接,这很好。但是,如果您这样做的速度太快,可能会使用所有可用的端口。您应该使用此sysctl参数来减少tcp fin超时并启用tcp\u重用连接

net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 10 #value is in seconds
tcp\u tw\u重用 TCP重用允许Linux内核从处于TIME_WAIT状态的连接中回收连接插槽,并将其重新分配到新连接。重用套接字可以非常有效地降低服务器负载

tcp\u fin\u超时 确定TCP/IP释放关闭的连接并重用其资源之前必须经过的时间。在此等待状态期间,重新打开与客户端的连接的成本低于建立新连接的成本


参考资料:

这与TCP fin超时有关(Linux中默认为60秒)。可能您不是在重复使用连接,而是每次都打开一个新的连接,这很好。但是,如果您这样做的速度太快,可能会使用所有可用的端口。您应该使用此sysctl参数来减少tcp fin超时并启用tcp\u重用连接

net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 10 #value is in seconds
tcp\u tw\u重用 TCP重用允许Linux内核从处于TIME_WAIT状态的连接中回收连接插槽,并将其重新分配到新连接。重用套接字可以非常有效地降低服务器负载

tcp\u fin\u超时 确定TCP/IP释放关闭的连接并重用其资源之前必须经过的时间。在此等待状态期间,重新打开与客户端的连接的成本低于建立新连接的成本


参考资料:

也尝试过,但仍有多个连接打开了TIME\u WAIT状态。使用redis管道,您不需要打开这么多套接字。套接字处于等待时间并不一定是问题,只有在耗尽所有可用端口的情况下才是问题。不确定这里是否可以使用管道,因为我需要立即跟踪每个系统的响应。抱歉-我的意思是
节点redis
默认使用管道,我简单地阅读了
pool redis
文档,它建议它基于
节点redis
。您是否验证了更改后仍然存在问题?是的,我尝试了您所说的。另外,我遇到的一件奇怪的事情是,即使两个客户端在redis中设置了值,那么当我使用nodejs时,10-15个连接在TIME\u WAIT状态下也是打开的,但这在PHP中不是问题。我也尝试了,但仍然有多个连接处于TIME\u WAIT状态打开。使用redis管道,您不需要打开这么多套接字。套接字处于等待时间并不一定是问题,只有在耗尽所有可用端口的情况下才是问题。不确定这里是否可以使用管道,因为我需要立即跟踪每个系统的响应。抱歉-我的意思是
节点redis
默认使用管道,我简单地阅读了
pool redis
文档,它建议它基于
节点redis
。您是否验证了更改后仍然存在问题?是的,我尝试了您所说的。还有一件奇怪的事情是,即使两个客户端在redis中设置了值,当我使用nodejs时,10-15个连接也会在TIME_WAIT状态下打开,但这不是PHP中的问题。我读到您在predis库上使用了quit(),您是否尝试过
$client->disconnect()
?我使用的是phpredis,您也可以使用close(),我听说您在predis库中使用quit(),您是否尝试过
$client->disconnect()
?我使用的是phpredis,您也可以使用close()