使用Node.JS连接到Kubernetes中的redis pod的正确方法
我正在设置一个新的k8s环境,其中有多个pod运行以node.js编写的微服务。其中一些服务连接到redis缓存。
这大部分时间都在工作,但我在访问redis时收到间歇性错误,这让我相信我没有正确连接,最常见的是:
RedisServerException: READONLY You can't write against a read only slave.
如果我再试一次,经过两三次尝试后我经常会成功。
这是我的redis部署:
RESOURCES: ==> v1/Service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE cache-redis-ha-announce-0 ClusterIP 100.xxx.xxx.xxx <none> 6379/TCP,26379/TCP 163m cache-redis-ha-announce-1 ClusterIP 100.xxx.xxx.xxx <none> 6379/TCP,26379/TCP 163m cache-redis-ha-announce-2 ClusterIP 100.xxx.xxx.xxx <none> 6379/TCP,26379/TCP 163m cache-redis-ha ClusterIP None <none> 6379/TCP,26379/TCP 163m ==> v1/StatefulSet NAME DESIRED CURRENT AGE cache-redis-ha-server 3 3 94s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE cache-redis-ha-server-0 2/2 Running 0 94s cache-redis-ha-server-1 2/2 Running 0 64s cache-redis-ha-server-2 2/2 Running 0 36s ==> v1/ConfigMap NAME DATA AGE cache-redis-ha-configmap 3 163m cache-redis-ha-probes 2 163m NOTES: Redis can be accessed via port 6379 and Sentinel can be accessed via port 26379 on the following DNS name from within your cluster: cache-redis-ha.devtest.svc.cluster.local
在我的服务中,我连接到redis:
this.client = redis.createClient(6379, "cache-redis-ha.devtest.svc.cluster.local");
this.delAsync = promisify(this.client.del).bind(this.client);
async flush(matchPattern: string): Promise<CacheResult> {
let result: CacheResult = { matchPattern: matchPattern, reply: true };
return await this.keysAsync(matchPattern).then(async (keys) => {
result.matchedKeys = keys;
if (keys.length) {
return await this.delAsync(keys).then((reply) => {
result.reply = reply;
return result;
});
}
return result;
});
}
我试图连接到createClient中的Sentinel端口,但这不起作用。
我的实施中有明显的错误吗?
回答如下:在Redis群集中,您有一个主机是R / W,而几个从机是RO。
当您为所有Redis pod使用单个服务时,您的连接将循环到所有可用的pod,而K8不知道哪个是主要的,这就是您有时遇到该错误的原因。当您与服务的连接终止于RO从站而不是RW主站时,就会发生这种情况。
您需要额外的服务以及类似控制器或其他自动化的服务器,这些服务器会将服务指向一个现在是主服务器的右侧服务器。
此外,您可以使用discovery从Sentel获取该信息:
Sentinels与其他Sentinels保持联系,以便相互检查彼此的可用性,并交换消息。但是,您不需要在运行的每个Sentinel实例中配置其他Sentinel地址的列表,因为Sentinel使用Redis实例发布/订阅功能来发现监视相同主服务器和从服务器的其他Sentinel。
通过将hello消息发送到名为sentinel:hello的通道中来实现此功能。
同样,您不需要配置附加到主服务器的从服务器列表,因为Sentinel将自动发现查询Redis的此列表。
每个Sentinel都会向每个受监控的主/从Pub / Sub通道发送一条消息:hello,每两秒一次,通过ip,port,runid宣布其存在。
每个Sentinel都订阅了Pub / Sub通道sentinel:hello of each master and slave,寻找未知的哨兵。当检测到新的哨兵时,它们被添加为该桅杆的哨兵。
Hello消息还包括主服务器的完整当前配置。如果接收Sentinel具有给定主机的配置,该配置早于接收的主机,则会立即更新为新配置。
在向主服务器添加新的标记之前,Sentinel始终检查是否已存在具有相同runid或相同地址(ip和端口对)的标记。在这种情况下,将删除所有匹配的标记,并添加新的标记。
此外,您可以在任何节点上使用call sentinel master mymaster
来获取当前主节点。
因此,最后您需要获取Redis主服务器地址(或ID)并使用它的服务(在您的安装中为cache-redis-ha-announce-*
)连接到当前主服务器。