有個項目年前要作最後一次上線。項目中有用到 aliyun tablestore 的一個模塊我作了一次重構。git
這個模塊的主要功能爲從 Kafka 訂閱消息,作一個的格式化處理以後存儲到 aliyun 的 TableStore。而且提供接口根據查詢參數從 aliyun tablestore 查詢相關的數據。重構後查詢接口的部分代碼以下:github
func GetLimit(userID, deviceName string, messageID int64, limit int32) ([]*StoredMessage, error) { request := &tablestore.GetRangeRequest{} rangeRowQueryCriteria := &tablestore.RangeRowQueryCriteria{} rangeRowQueryCriteria.TableName = tableName startPK := new(tablestore.PrimaryKey) startPK.AddPrimaryKeyColumn(primaryUserID, userID) startPK.AddPrimaryKeyColumn(primaryDeviceName, deviceName) startPK.AddPrimaryKeyColumn(primaryMessageID, messageID) endPK := new(tablestore.PrimaryKey) endPK.AddPrimaryKeyColumn(primaryUserID, userID) endPK.AddPrimaryKeyColumn(primaryDeviceName, deviceName) endPK.AddPrimaryKeyColumn(primaryMessageID, math.MinInt64) rangeRowQueryCriteria.StartPrimaryKey = startPK rangeRowQueryCriteria.EndPrimaryKey = endPK rangeRowQueryCriteria.Direction = tablestore.BACKWARD rangeRowQueryCriteria.MaxVersion = 1 rangeRowQueryCriteria.Limit = limit request.RangeRowQueryCriteria = rangeRowQueryCriteria response, err := client.GetRange(request) if err != nil { return nil, err } ... }
項目更新上線以後,查詢接口失效了。從日誌系統沒有撈到錯誤日誌。這麼一想,多是 panic 了,從 daoker 容器直接去撈日誌。果真,發現了 panic 的信息。(因爲這個模塊的 panic 日誌沒有經過 syslog 發送出去,因此日誌系統查不到。萬惡的 panic)日誌
好了,分析問題(panic 日誌具體已經找不到了,我沒存下來)。問題在 client.GetRange
這個方法上,根據源碼進一步深刻,會發現下面的代碼:code
func NewPrimaryKeyColumn(name []byte, value interface{}, option PrimaryKeyOption) *PrimaryKeyColumnInner { if option == NONE { v := &PrimaryKeyColumnInner{} v.Name = name t := reflect.TypeOf(value) switch t.Kind() { case reflect.String: v.Type = otsprotocol.PrimaryKeyType_STRING case reflect.Int64: v.Type = otsprotocol.PrimaryKeyType_INTEGER case reflect.Slice: v.Type = otsprotocol.PrimaryKeyType_BINARY default: panic(errInvalidInput) } v.Value = value return v } else if option == AUTO_INCREMENT { return NewPrimaryKeyColumnAuto_Increment(name) } else if option == MIN { return NewPrimaryKeyColumnINF_MIN(name) } else { return NewPrimaryKeyColumnINF_MAX(name) } }
因此它的 PrimaryKeyColumn 的值類型只能是 string, int64 或者 slice 其中一種。而我傳遞的 math.MinInt64
是 untyped int。就直接 panic 了。接口
解決方法簡單,轉一下就好了。int64(math.MinInt64)
。rem
這個 sdk 的註釋真的很少,GetRange
的方法上也沒有註釋,真是讓人很容易用錯。最根本問題是,這種直接 panic 的代碼邏輯真的是害死人。因此啊 Don't use panic, use error!get
使用的 aliyun tablestore go client sdk 版本爲 v4.1.3。aliyun-tablestore-go-sdk@v4.1.3源碼