mirror of
https://github.com/zeromicro/go-zero.git
synced 2025-01-23 09:00:20 +08:00
feat: slow threshold customizable in redis (#1185)
* feat: slow threshold customizable in redis * chore: improve config robustness
This commit is contained in:
parent
b4d1c6da2c
commit
429f85a9de
16
core/conf/time.go
Normal file
16
core/conf/time.go
Normal file
@ -0,0 +1,16 @@
|
||||
package conf
|
||||
|
||||
import "time"
|
||||
|
||||
const minDuration = 100 * time.Microsecond
|
||||
|
||||
// CheckedDuration returns the duration that guaranteed to be greater than 100us.
|
||||
// Why we need this is because users sometimes intend to use 500 to represent 500ms.
|
||||
// In config, duration less than 100us should always be missing ms etc.
|
||||
func CheckedDuration(duration time.Duration) time.Duration {
|
||||
if duration > minDuration {
|
||||
return duration
|
||||
}
|
||||
|
||||
return duration * time.Millisecond
|
||||
}
|
14
core/conf/time_test.go
Normal file
14
core/conf/time_test.go
Normal file
@ -0,0 +1,14 @@
|
||||
package conf
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCheckedDuration(t *testing.T) {
|
||||
assert.Equal(t, time.Second, CheckedDuration(1000))
|
||||
assert.Equal(t, 2*time.Second, CheckedDuration(2000))
|
||||
assert.Equal(t, 2*time.Second, CheckedDuration(time.Second*2))
|
||||
}
|
@ -1,6 +1,11 @@
|
||||
package redis
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/tal-tech/go-zero/core/conf"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrEmptyHost is an error that indicates no redis host is set.
|
||||
@ -14,10 +19,11 @@ var (
|
||||
type (
|
||||
// A RedisConf is a redis config.
|
||||
RedisConf struct {
|
||||
Host string
|
||||
Type string `json:",default=node,options=node|cluster"`
|
||||
Pass string `json:",optional"`
|
||||
Tls bool `json:",default=false,options=true|false"`
|
||||
Host string
|
||||
Type string `json:",default=node,options=node|cluster"`
|
||||
Pass string `json:",optional"`
|
||||
Tls bool `json:",default=false,options=true|false"`
|
||||
SlowThreshold time.Duration `json:",default=100ms"`
|
||||
}
|
||||
|
||||
// A RedisKeyConf is a redis config with key.
|
||||
@ -36,6 +42,9 @@ func (rc RedisConf) NewRedis() *Redis {
|
||||
if len(rc.Pass) > 0 {
|
||||
opts = append(opts, WithPass(rc.Pass))
|
||||
}
|
||||
if rc.SlowThreshold > 0 {
|
||||
opts = append(opts, WithSlowThreshold(conf.CheckedDuration(rc.SlowThreshold)))
|
||||
}
|
||||
if rc.Tls {
|
||||
opts = append(opts, WithTLS())
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package redis
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
red "github.com/go-redis/redis"
|
||||
"github.com/tal-tech/go-zero/core/logx"
|
||||
@ -9,24 +10,26 @@ import (
|
||||
"github.com/tal-tech/go-zero/core/timex"
|
||||
)
|
||||
|
||||
func process(proc func(red.Cmder) error) func(red.Cmder) error {
|
||||
return func(cmd red.Cmder) error {
|
||||
start := timex.Now()
|
||||
func checkDuration(slowThreshold time.Duration) func(proc func(red.Cmder) error) func(red.Cmder) error {
|
||||
return func(proc func(red.Cmder) error) func(red.Cmder) error {
|
||||
return func(cmd red.Cmder) error {
|
||||
start := timex.Now()
|
||||
|
||||
defer func() {
|
||||
duration := timex.Since(start)
|
||||
if duration > slowThreshold {
|
||||
var buf strings.Builder
|
||||
for i, arg := range cmd.Args() {
|
||||
if i > 0 {
|
||||
buf.WriteByte(' ')
|
||||
defer func() {
|
||||
duration := timex.Since(start)
|
||||
if duration > slowThreshold {
|
||||
var buf strings.Builder
|
||||
for i, arg := range cmd.Args() {
|
||||
if i > 0 {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
buf.WriteString(mapping.Repr(arg))
|
||||
}
|
||||
buf.WriteString(mapping.Repr(arg))
|
||||
logx.WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
|
||||
}
|
||||
logx.WithDuration(duration).Slowf("[REDIS] slowcall on executing: %s", buf.String())
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return proc(cmd)
|
||||
return proc(cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,7 @@ const (
|
||||
|
||||
blockingQueryTimeout = 5 * time.Second
|
||||
readWriteTimeout = 2 * time.Second
|
||||
|
||||
slowThreshold = time.Millisecond * 100
|
||||
defaultSlowThreshold = time.Millisecond * 100
|
||||
)
|
||||
|
||||
// ErrNilNode is an error that indicates a nil redis node.
|
||||
@ -40,11 +39,12 @@ type (
|
||||
|
||||
// Redis defines a redis node/cluster. It is thread-safe.
|
||||
Redis struct {
|
||||
Addr string
|
||||
Type string
|
||||
Pass string
|
||||
tls bool
|
||||
brk breaker.Breaker
|
||||
Addr string
|
||||
Type string
|
||||
Pass string
|
||||
tls bool
|
||||
brk breaker.Breaker
|
||||
slowThreshold time.Duration
|
||||
}
|
||||
|
||||
// RedisNode interface represents a redis node.
|
||||
@ -78,9 +78,10 @@ type (
|
||||
// New returns a Redis with given options.
|
||||
func New(addr string, opts ...Option) *Redis {
|
||||
r := &Redis{
|
||||
Addr: addr,
|
||||
Type: NodeType,
|
||||
brk: breaker.NewBreaker(),
|
||||
Addr: addr,
|
||||
Type: NodeType,
|
||||
brk: breaker.NewBreaker(),
|
||||
slowThreshold: defaultSlowThreshold,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
@ -1765,6 +1766,13 @@ func WithPass(pass string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithSlowThreshold sets the slow threshold.
|
||||
func WithSlowThreshold(threshold time.Duration) Option {
|
||||
return func(r *Redis) {
|
||||
r.slowThreshold = threshold
|
||||
}
|
||||
}
|
||||
|
||||
// WithTLS customizes the given Redis with TLS enabled.
|
||||
func WithTLS() Option {
|
||||
return func(r *Redis) {
|
||||
|
@ -1115,7 +1115,7 @@ func runOnRedisTLS(t *testing.T, fn func(client *Redis)) {
|
||||
client.Close()
|
||||
}
|
||||
}()
|
||||
fn(New(s.Addr(), WithTLS()))
|
||||
fn(New(s.Addr(), WithTLS(), WithSlowThreshold(defaultSlowThreshold/2)))
|
||||
}
|
||||
|
||||
func badType() Option {
|
||||
|
@ -32,7 +32,7 @@ func getClient(r *Redis) (*red.Client, error) {
|
||||
MinIdleConns: idleConns,
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
store.WrapProcess(process)
|
||||
store.WrapProcess(checkDuration(r.slowThreshold))
|
||||
return store, nil
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -25,7 +25,7 @@ func getCluster(r *Redis) (*red.ClusterClient, error) {
|
||||
MinIdleConns: idleConns,
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
store.WrapProcess(process)
|
||||
store.WrapProcess(checkDuration(r.slowThreshold))
|
||||
|
||||
return store, nil
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user