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 架构的实现框架
参考
容器设计模式-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取一个别名叫IntAliastype IntAlias = int
参考
Go语言type关键字(类型别名)
理解 Go 1.9 的类型别名
4.3.2 回调函数
redis.ByteSlices() 以及其它fun中都使用了回调函数
参考
cyent.github.io