我正在构建一个连接到redis的nodejs应用程序。我在本地的redis实例中使用了这个。现在,我正在使用ioredis
从我的nodejs应用程序连接到AWS中k8s中的redis集群。这是我的东西。
const Redis = require("ioredis");
this.redis = new Redis({
port: 6379, // Redis port
host: rhost, // Redis host
password: password
});
this.redis.on('connect', () => {
console.log('connected to redis')
})
当消息connected to redis
在日志中打印出来时,我似乎成功地连接到了集群。然而,每次我尝试使用我的redis对象时,我都会收到一个MOVED错误:
UnhandledPromiseRejectionWarning: ReplyError: MOVED 5011 <ip address>:6379
at parseError (/node_modules/ioredis/node_modules/redis-parser/lib/parser.js:179:12)
at parseType (/node_modules/ioredis/node_modules/redis-parser/lib/parser.js:302:14)
连接在我的本地上有效。然而,在AWS中则不然。我尝试使用Redis.Cluster
对象而不是Redis
进行交换,但在部署应用程序后,应用程序挂起,连接事件从未触发。close
和reconnecting
事件似乎在无限循环。
根据我的理解,这是集群中节点之间重定向的问题。也许这是主/从配置的问题。该错误是AWS中的配置问题吗?我需要使用Redis.Cluster
对象而不是普通的Redis
实例吗?修复MOVED错误的最佳方法是什么?
MOVED
错误是直接使用Redis客户端和ElastiCache的配置端点(Redis Cluster Mode(引起的。这可以通过使用知道多个碎片的new Redis.Cluster([{ host: <cfg-endpoint>])
来解决。
否则,请禁用Redis群集模式,并使用ElastiCache群集的主(主(dns名称。即使没有Redis群集模式,仍然有故障切换策略(AWS将在主节点发生故障时替换它(,并且您可以将节点部署到多个可用区域中。
此外,当您启用加密时,您将需要连接到启用TLS的AWS ElastiCache(ioredis的tls: {}
选项(。
https://aws.amazon.com/blogs/database/work-with-cluster-mode-on-amazon-elasticache-for-redis/
您可以在此处阅读有关MOVE错误的更多信息:https://redis.io/topics/cluster-spec#moved-重定向"MOVED重定向Redis客户端可以免费向集群中的每个节点发送查询,包括从属节点。节点将分析查询,如果它是可接受的(即,查询中只提到一个密钥,或者提到的多个密钥都属于同一个哈希槽(,它将查找哪个节点负责密钥所属的哈希槽。
如果哈希槽由节点提供服务,则简单地处理查询,否则节点将检查其内部哈希槽到节点的映射,并用MOVED错误回复客户端,如以下示例所示:
获取x-移动3999 127.0.0.1:6381错误包括密钥(3999(的哈希槽和可以为查询提供服务的实例的ip:port。客户端需要将查询重新发布到指定节点的IP地址和端口。请注意,即使客户端在重新发布查询之前等待了很长时间,并且在此期间群集配置发生了更改,如果哈希槽3999现在由另一个节点提供服务,则目标节点也会再次回复MOVED错误。如果联系的节点没有更新的信息,也会发生同样的情况">
ioredis支持redis集群。所以你应该像这样创建redis集群:
new Redis.Cluster([{
host: process.env.REDIS_ENDPOINT, // Configuration endpoint address from Elasticache
port: process.env.REDIS_PORT
}]);
ioredis将处理MOVE重定向错误。
const Redis = require("ioredis");
const connection = await new Redis.Cluster(
[redisHost,redisPort],
{
scaleReads: "all",
redisOptions: {
username: redisUserName,
password: redisPassword,
enableAutoPipelining: true,
}
);
上面的配置解决了我的问题,我使用的是ioredis而不是"redis"。
如果这没有帮助:
const Redis = require('ioredis');
const ioCluster = new Redis.Cluster([redisConfig.redis]);
const slackQueue = new Queue('slack notifications', {
prefix: '{slack}' ,
createClient: () => ioCluster
});
const emailQueue = new Queue('email notifications', {
prefix: '{email}' ,
createClient: () => ioCluster
});
我会不使用ioredis,或者尝试将redis引擎降级为4.x