mirror of
https://github.com/alibaba/higress.git
synced 2026-05-29 23:27:28 +08:00
216 lines
5.7 KiB
Markdown
216 lines
5.7 KiB
Markdown
# Redis Client Reference
|
|
|
|
## Initialization
|
|
|
|
```go
|
|
type MyConfig struct {
|
|
redis wrapper.RedisClient
|
|
qpm int
|
|
}
|
|
|
|
func parseConfig(json gjson.Result, config *MyConfig) error {
|
|
serviceName := json.Get("serviceName").String()
|
|
servicePort := json.Get("servicePort").Int()
|
|
if servicePort == 0 {
|
|
servicePort = 6379
|
|
}
|
|
|
|
config.redis = wrapper.NewRedisClusterClient(wrapper.FQDNCluster{
|
|
FQDN: serviceName,
|
|
Port: servicePort,
|
|
})
|
|
|
|
return config.redis.Init(
|
|
json.Get("username").String(),
|
|
json.Get("password").String(),
|
|
json.Get("timeout").Int(), // milliseconds
|
|
// Optional settings:
|
|
// wrapper.WithDataBase(1),
|
|
// wrapper.WithBufferFlushTimeout(3*time.Millisecond),
|
|
// wrapper.WithMaxBufferSizeBeforeFlush(1024),
|
|
// wrapper.WithDisableBuffer(), // For latency-sensitive scenarios
|
|
)
|
|
}
|
|
```
|
|
|
|
## Callback Signature
|
|
|
|
```go
|
|
func(response resp.Value)
|
|
|
|
// Check for errors
|
|
if response.Error() != nil {
|
|
// Handle error
|
|
}
|
|
|
|
// Get values
|
|
response.Integer() // int
|
|
response.String() // string
|
|
response.Bool() // bool
|
|
response.Array() // []resp.Value
|
|
response.Bytes() // []byte
|
|
```
|
|
|
|
## Available Commands
|
|
|
|
### Key Operations
|
|
|
|
```go
|
|
redis.Del(key, callback)
|
|
redis.Exists(key, callback)
|
|
redis.Expire(key, ttlSeconds, callback)
|
|
redis.Persist(key, callback)
|
|
```
|
|
|
|
### String Operations
|
|
|
|
```go
|
|
redis.Get(key, callback)
|
|
redis.Set(key, value, callback)
|
|
redis.SetEx(key, value, ttlSeconds, callback)
|
|
redis.SetNX(key, value, ttlSeconds, callback) // ttl=0 means no expiry
|
|
redis.MGet(keys, callback)
|
|
redis.MSet(kvMap, callback)
|
|
redis.Incr(key, callback)
|
|
redis.Decr(key, callback)
|
|
redis.IncrBy(key, delta, callback)
|
|
redis.DecrBy(key, delta, callback)
|
|
```
|
|
|
|
### List Operations
|
|
|
|
```go
|
|
redis.LLen(key, callback)
|
|
redis.RPush(key, values, callback)
|
|
redis.RPop(key, callback)
|
|
redis.LPush(key, values, callback)
|
|
redis.LPop(key, callback)
|
|
redis.LIndex(key, index, callback)
|
|
redis.LRange(key, start, stop, callback)
|
|
redis.LRem(key, count, value, callback)
|
|
redis.LInsertBefore(key, pivot, value, callback)
|
|
redis.LInsertAfter(key, pivot, value, callback)
|
|
```
|
|
|
|
### Hash Operations
|
|
|
|
```go
|
|
redis.HExists(key, field, callback)
|
|
redis.HDel(key, fields, callback)
|
|
redis.HLen(key, callback)
|
|
redis.HGet(key, field, callback)
|
|
redis.HSet(key, field, value, callback)
|
|
redis.HMGet(key, fields, callback)
|
|
redis.HMSet(key, kvMap, callback)
|
|
redis.HKeys(key, callback)
|
|
redis.HVals(key, callback)
|
|
redis.HGetAll(key, callback)
|
|
redis.HIncrBy(key, field, delta, callback)
|
|
redis.HIncrByFloat(key, field, delta, callback)
|
|
```
|
|
|
|
### Set Operations
|
|
|
|
```go
|
|
redis.SCard(key, callback)
|
|
redis.SAdd(key, values, callback)
|
|
redis.SRem(key, values, callback)
|
|
redis.SIsMember(key, value, callback)
|
|
redis.SMembers(key, callback)
|
|
redis.SDiff(key1, key2, callback)
|
|
redis.SDiffStore(dest, key1, key2, callback)
|
|
redis.SInter(key1, key2, callback)
|
|
redis.SInterStore(dest, key1, key2, callback)
|
|
redis.SUnion(key1, key2, callback)
|
|
redis.SUnionStore(dest, key1, key2, callback)
|
|
```
|
|
|
|
### Sorted Set Operations
|
|
|
|
```go
|
|
redis.ZCard(key, callback)
|
|
redis.ZAdd(key, memberScoreMap, callback)
|
|
redis.ZCount(key, min, max, callback)
|
|
redis.ZIncrBy(key, member, delta, callback)
|
|
redis.ZScore(key, member, callback)
|
|
redis.ZRank(key, member, callback)
|
|
redis.ZRevRank(key, member, callback)
|
|
redis.ZRem(key, members, callback)
|
|
redis.ZRange(key, start, stop, callback)
|
|
redis.ZRevRange(key, start, stop, callback)
|
|
```
|
|
|
|
### Lua Script
|
|
|
|
```go
|
|
redis.Eval(script, numkeys, keys, args, callback)
|
|
```
|
|
|
|
### Raw Command
|
|
|
|
```go
|
|
redis.Command([]interface{}{"SET", "key", "value"}, callback)
|
|
```
|
|
|
|
## Rate Limiting Example
|
|
|
|
```go
|
|
func onHttpRequestHeaders(ctx wrapper.HttpContext, config MyConfig) types.Action {
|
|
now := time.Now()
|
|
minuteAligned := now.Truncate(time.Minute)
|
|
timeStamp := strconv.FormatInt(minuteAligned.Unix(), 10)
|
|
|
|
err := config.redis.Incr(timeStamp, func(response resp.Value) {
|
|
if response.Error() != nil {
|
|
log.Errorf("redis error: %v", response.Error())
|
|
proxywasm.ResumeHttpRequest()
|
|
return
|
|
}
|
|
|
|
count := response.Integer()
|
|
ctx.SetContext("timeStamp", timeStamp)
|
|
ctx.SetContext("callTimeLeft", strconv.Itoa(config.qpm - count))
|
|
|
|
if count == 1 {
|
|
// First request in this minute, set expiry
|
|
config.redis.Expire(timeStamp, 60, func(response resp.Value) {
|
|
if response.Error() != nil {
|
|
log.Errorf("expire error: %v", response.Error())
|
|
}
|
|
proxywasm.ResumeHttpRequest()
|
|
})
|
|
} else if count > config.qpm {
|
|
proxywasm.SendHttpResponse(429, [][2]string{
|
|
{"timeStamp", timeStamp},
|
|
{"callTimeLeft", "0"},
|
|
}, []byte("Too many requests\n"), -1)
|
|
} else {
|
|
proxywasm.ResumeHttpRequest()
|
|
}
|
|
})
|
|
|
|
if err != nil {
|
|
log.Errorf("redis call failed: %v", err)
|
|
return types.HeaderContinue
|
|
}
|
|
return types.HeaderStopAllIterationAndWatermark
|
|
}
|
|
|
|
func onHttpResponseHeaders(ctx wrapper.HttpContext, config MyConfig) types.Action {
|
|
if ts := ctx.GetContext("timeStamp"); ts != nil {
|
|
proxywasm.AddHttpResponseHeader("timeStamp", ts.(string))
|
|
}
|
|
if left := ctx.GetContext("callTimeLeft"); left != nil {
|
|
proxywasm.AddHttpResponseHeader("callTimeLeft", left.(string))
|
|
}
|
|
return types.HeaderContinue
|
|
}
|
|
```
|
|
|
|
## Important Notes
|
|
|
|
1. **Check Ready()** - `redis.Ready()` returns false if init failed
|
|
2. **Auto-reconnect** - Client handles NOAUTH errors and re-authenticates automatically
|
|
3. **Buffering** - Default 3ms flush timeout and 1024 byte buffer; use `WithDisableBuffer()` for latency-sensitive scenarios
|
|
4. **Error handling** - Always check `response.Error()` in callbacks
|