我正在建立一个新的k8s环境,其中包含运行以node.js编写的微服务的多个Pod。其中一些服务连接到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端口,但这没有用。
我的实现中是否存在明显的错误?
答案 0 :(得分:1)
在Redis集群中,您有一个主控器(即R / W)和多个从属器(即RO)。
当您对所有Redis Pod使用单一服务时,您的连接将循环到所有可用Pod,而K8不知道其中哪个是主Pod,这就是为什么有时会遇到该错误的原因。当您与服务的连接在RO从属设备而不是RW主设备上终止时,就会发生这种情况。
您需要其他服务,以及诸如控制器或其他自动化设备之类的东西,它将使该服务指向现在是主服务器的正确吊舱。
此外,您可以使用discovery从Sentel获取该信息:
哨兵与其他哨兵保持联系,以相互检查彼此的可用性并交换消息。但是,您无需在运行的每个Sentinel实例中配置其他Sentinel地址的列表,因为Sentinel使用Redis实例的发布/订阅功能来发现监视相同主服务器和从服务器的其他Sentinel。
此功能是通过将问候消息发送到名为 sentinel :hello的频道中来实现的。
类似地,您不需要配置连接到主服务器的从服务器的列表是什么,因为Sentinel会通过查询Redis自动发现此列表。
每个Sentinel都会向每一个受监视的主/从属发布/订阅通道 sentinel :hello每两秒钟发布一条消息,并通过ip,port,runid宣布其存在。
每个哨兵都订阅了发布/订阅频道哨兵:每个主从节点的hello,以查找未知的哨兵。当检测到新的标记时,会将它们添加为该主标记的标记。
Hello消息还包括主服务器的完整当前配置。如果接收方Sentinel的给定主控配置早于接收方的配置,它将立即更新为新配置。
在将新的哨兵添加到主机之前,Sentinel始终检查是否已经存在具有相同runid或相同地址(ip和端口对)的哨兵。在这种情况下,将删除所有匹配的标记,并添加新的标记。
此外,您可以在任何节点上call sentinel master mymaster
来获取当前的主服务器。
因此,最后,您需要获取Redis主服务器地址(或ID)并使用其服务(在您的安装中为cache-redis-ha-announce-*
)连接到当前主服务器。