mirror of https://github.com/chaos-mesh/chaosd.git
redisChaos: add cache limit (#163)
* add cache limit Signed-off-by: FingerLeader <wanxfinger@gmail.com> * add a comment Signed-off-by: FingerLeader <wanxfinger@gmail.com> * redis cache limit add a flag percent Signed-off-by: FingerLeader <wanxfinger@gmail.com> * edit some details Signed-off-by: FingerLeader <wanxfinger@gmail.com> * fix ci Signed-off-by: FingerLeader <wanxfinger@gmail.com>
This commit is contained in:
parent
3cb3a334f6
commit
f1df7d3f15
|
|
@ -44,6 +44,7 @@ func NewRedisAttackCommand(uid *string) *cobra.Command {
|
|||
NewRedisSentinelRestartCommand(dep, options),
|
||||
NewRedisSentinelStopCommand(dep, options),
|
||||
NewRedisCachePenetrationCommand(dep, options),
|
||||
NewRedisCacheLimitCommand(dep, options),
|
||||
)
|
||||
|
||||
return cmd
|
||||
|
|
@ -105,6 +106,24 @@ func NewRedisCachePenetrationCommand(dep fx.Option, options *core.RedisCommand)
|
|||
return cmd
|
||||
}
|
||||
|
||||
func NewRedisCacheLimitCommand(dep fx.Option, options *core.RedisCommand) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "cache-limit",
|
||||
Short: "set maxmemory of Redis",
|
||||
Run: func(*cobra.Command, []string) {
|
||||
options.Action = core.RedisCacheLimitAction
|
||||
utils.FxNewAppWithoutLog(dep, fx.Invoke(redisAttackF)).Run()
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&options.Addr, "addr", "a", "", "")
|
||||
cmd.Flags().StringVarP(&options.Password, "password", "p", "", "The password of server")
|
||||
cmd.Flags().StringVarP(&options.CacheSize, "size", "s", "0", "The size of cache")
|
||||
cmd.Flags().StringVarP(&options.Percent, "percent", "", "", "The percentage of maxmemory")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func redisAttackF(chaos *chaosd.Server, options *core.RedisCommand) {
|
||||
if err := options.Validate(); err != nil {
|
||||
utils.ExitWithError(utils.ExitBadArgs, err)
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ const (
|
|||
RedisSentinelRestartAction = "restart"
|
||||
RedisSentinelStopAction = "stop"
|
||||
RedisCachePenetrationAction = "penetration"
|
||||
RedisCacheLimitAction = "cacheLimit"
|
||||
)
|
||||
|
||||
var _ AttackConfig = &RedisCommand{}
|
||||
|
|
@ -36,6 +37,10 @@ type RedisCommand struct {
|
|||
FlushConfig bool `json:"flushConfig,omitempty"`
|
||||
RedisPath string `json:"redisPath,omitempty"`
|
||||
RequestNum int `json:"requestNum,omitempty"`
|
||||
CacheSize string `json:"cacheSize,omitempty"`
|
||||
Percent string `json:"percent,omitempty"`
|
||||
|
||||
OriginCacheSize string `json:"originCacheSize,omitempty"`
|
||||
}
|
||||
|
||||
func (r *RedisCommand) Validate() error {
|
||||
|
|
@ -50,6 +55,11 @@ func (r *RedisCommand) Validate() error {
|
|||
if r.RequestNum == 0 {
|
||||
return errors.New("request-num is required")
|
||||
}
|
||||
|
||||
case RedisCacheLimitAction:
|
||||
if r.CacheSize != "0" && r.Percent != "" {
|
||||
return errors.New("only one of cachesize and percent can be set")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,10 @@
|
|||
package chaosd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/pingcap/errors"
|
||||
|
|
@ -62,6 +65,38 @@ func (redisAttack) Attack(options core.AttackConfig, env Environment) error {
|
|||
if err != redis.Nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
case core.RedisCacheLimitAction:
|
||||
// `maxmemory` is an interface listwith content similar to `[maxmemory 1024]`
|
||||
maxmemory, err := cli.ConfigGet(cli.Context(), "maxmemory").Result()
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
// Get the value of maxmemory
|
||||
attack.OriginCacheSize = fmt.Sprint(maxmemory[1])
|
||||
|
||||
var cacheSize string
|
||||
if attack.Percent != "" {
|
||||
percentage, err := strconv.ParseFloat(attack.Percent[0:len(attack.Percent)-1], 64)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
originCacheSize, err := strconv.ParseFloat(attack.OriginCacheSize, 64)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
cacheSize = fmt.Sprint(int(math.Floor(originCacheSize / 100.0 * percentage)))
|
||||
} else {
|
||||
cacheSize = attack.CacheSize
|
||||
}
|
||||
|
||||
result, err := cli.ConfigSet(cli.Context(), "maxmemory", cacheSize).Result()
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
if result != STATUSOK {
|
||||
return errors.WithStack(errors.Errorf("redis command status is %s", result))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -76,6 +111,20 @@ func (redisAttack) Recover(exp core.Experiment, env Environment) error {
|
|||
switch attack.Action {
|
||||
case core.RedisSentinelStopAction:
|
||||
return env.Chaos.recoverSentinelStop(attack)
|
||||
|
||||
case core.RedisCacheLimitAction:
|
||||
cli := redis.NewClient(&redis.Options{
|
||||
Addr: attack.Addr,
|
||||
Password: attack.Password,
|
||||
})
|
||||
|
||||
result, err := cli.ConfigSet(cli.Context(), "maxmemory", attack.OriginCacheSize).Result()
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
if result != STATUSOK {
|
||||
return errors.WithStack(errors.Errorf("redis command status is %s", result))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue