Php Redis以TIME\u WAIT状态打开多个连接
我使用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中使用连接池,但没有成功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秒(使用
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()