Redigo: Envoy代理Redis場景下的錯誤提示

sown發表於2022-03-25

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

相關文章