头图

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

image.png


sown
149 声望268 粉丝

学习不能停