乐趣区

关于redis:Redigo-Envoy代理Redis场景下的错误提示

Redigo issue 579

reply.go sliceHelper does not handle Redis errors within the slice#579

一、问题是什么

在应用了 Envoy 代理 Redis 的场景下,执行 MGET 获取数据,其中某台 Redis 服务呈现了问题,Envoy 返回了如下的谬误提醒
upstream failure

而通过 redigo 返回来的却是

redigo: unexpected element type for ByteSlices, got type redis.Error

显然封装的有问题,导致谬误提醒不够间接。

二、怎么解决的

详见 pr 580

2.1 ByteSlices 与 MGET

咱们看 issue 579 的示例代码,产生问题的调用就在这里:

values, err := redis.ByteSlices(conn.Do("MGET", params...))

那么问题本源出在哪里呢?

这就须要看下 redis.ByteSlices() 都做了什么。

我间接总结一下:遍历 MGET 返回的所有数据,进行类型断言,如果断言失败,返回错误信息。

那么问题就在于如下两点:

  1. 当 Envoy 代理 Redis 后,在 redis 没有响应或者其它状况下,Envoy 返回自定义的错误信息。(Envoy 文档 -upstream failure 谬误)
  2. Redigo 粗犷的判断,对返回的值进行类型断言 v.([]byte),切片断言失败,返回了自定义的谬误提醒,且谬误提醒中,没有带着 Envoy 返回的内容。

2.2 switch 与 v.(type)

if v.([]byte) 类型断言出是否为字节切片
革新为
switch v := v.(type) case []byte: case Error:

不再判断繁多的字节切片类型,而是断言出是哪种类型。

Error 是什么类型呢,其实就是 String,这种个性,咱们管它叫做“类型定义” type Error string

再有 Envoy 代理 Redis 返回错误信息 场景下返回的数据,类型断言就会进入到case Error

三、复现这个问题

装置 Envoy,代理 Redis,kill 掉 Redis,就可复现出“no upstream host”(虽不是 upstream failure,但同样是 String)。

四、扩大

4.1 文中提到的 Envoy 是什么?

Service Mesh 架构的实现框架

参考
容器设计模式 -sidcar

4.2 Envoy 和 Redis 怎么联合的?

在 Service Mesh 架构下,Envoy 对 多 Redis 集群进行代理。

参考
Envoy Redis 源码剖析

4.3 Go

4.3.1 类型别名、与类型定义

文中说到的 Error 其实 就是 String,即类型定义,须要留神的是不要和类型别名的概念混同。

// 将 NewInt 定义为 int 类型
type NewInt int

// 将 int 取一个别名叫 IntAlias
type IntAlias = int

参考
Go 语言 type 关键字(类型别名)
理解 Go 1.9 的类型别名

4.3.2 回调函数

redis.ByteSlices() 以及其它 fun 中都使用了回调函数

参考
cyent.github.io

退出移动版