共计 1269 个字符,预计需要花费 4 分钟才能阅读完成。
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 取一个别名叫 IntAlias
type IntAlias = int
参考
Go 语言 type 关键字(类型别名)
理解 Go 1.9 的类型别名
4.3.2 回调函数
redis.ByteSlices() 以及其它 fun 中都使用了回调函数
参考
cyent.github.io