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返回的所有数据,进行类型断言,如果断言失败,返回错误信息。
那么问题就在于如下两点:
- 当 Envoy 代理 Redis 后,在 redis 没有响应或者其它情况下,Envoy 返回自定义的错误信息。(Envoy文档-upstream failure错误)
- 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 架构的实现框架
4.2 Envoy 和 Redis 怎么结合的?
在 Service Mesh 架构下,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中都运用了回调函数
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。