Redigo:|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: Envoy代理Redis场景下的错误提示】而经过 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
Redigo:|Redigo: Envoy代理Redis场景下的错误提示
文章图片

    推荐阅读