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),
|
NewRedisSentinelRestartCommand(dep, options),
|
||||||
NewRedisSentinelStopCommand(dep, options),
|
NewRedisSentinelStopCommand(dep, options),
|
||||||
NewRedisCachePenetrationCommand(dep, options),
|
NewRedisCachePenetrationCommand(dep, options),
|
||||||
|
NewRedisCacheLimitCommand(dep, options),
|
||||||
)
|
)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|
@ -105,6 +106,24 @@ func NewRedisCachePenetrationCommand(dep fx.Option, options *core.RedisCommand)
|
||||||
return cmd
|
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) {
|
func redisAttackF(chaos *chaosd.Server, options *core.RedisCommand) {
|
||||||
if err := options.Validate(); err != nil {
|
if err := options.Validate(); err != nil {
|
||||||
utils.ExitWithError(utils.ExitBadArgs, err)
|
utils.ExitWithError(utils.ExitBadArgs, err)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ const (
|
||||||
RedisSentinelRestartAction = "restart"
|
RedisSentinelRestartAction = "restart"
|
||||||
RedisSentinelStopAction = "stop"
|
RedisSentinelStopAction = "stop"
|
||||||
RedisCachePenetrationAction = "penetration"
|
RedisCachePenetrationAction = "penetration"
|
||||||
|
RedisCacheLimitAction = "cacheLimit"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ AttackConfig = &RedisCommand{}
|
var _ AttackConfig = &RedisCommand{}
|
||||||
|
|
@ -36,6 +37,10 @@ type RedisCommand struct {
|
||||||
FlushConfig bool `json:"flushConfig,omitempty"`
|
FlushConfig bool `json:"flushConfig,omitempty"`
|
||||||
RedisPath string `json:"redisPath,omitempty"`
|
RedisPath string `json:"redisPath,omitempty"`
|
||||||
RequestNum int `json:"requestNum,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 {
|
func (r *RedisCommand) Validate() error {
|
||||||
|
|
@ -50,6 +55,11 @@ func (r *RedisCommand) Validate() error {
|
||||||
if r.RequestNum == 0 {
|
if r.RequestNum == 0 {
|
||||||
return errors.New("request-num is required")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,10 @@
|
||||||
package chaosd
|
package chaosd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
"github.com/pingcap/errors"
|
"github.com/pingcap/errors"
|
||||||
|
|
@ -62,6 +65,38 @@ func (redisAttack) Attack(options core.AttackConfig, env Environment) error {
|
||||||
if err != redis.Nil {
|
if err != redis.Nil {
|
||||||
return errors.WithStack(err)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +111,20 @@ func (redisAttack) Recover(exp core.Experiment, env Environment) error {
|
||||||
switch attack.Action {
|
switch attack.Action {
|
||||||
case core.RedisSentinelStopAction:
|
case core.RedisSentinelStopAction:
|
||||||
return env.Chaos.recoverSentinelStop(attack)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue