forked from pingcap/tidb
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
…ase 6.4` rate limit (pingcap#155) * merge pr#130,pingcap#133 into 6.4 Signed-off-by: zeminzhou <zhouzemin@pingcap.com> * fix start limit rate Signed-off-by: zeminzhou <zhouzemin@pingcap.com> * default config Signed-off-by: zeminzhou <zhouzemin@pingcap.com> * keyspace: use `user_storage_size` instead of `storage_size` for ratelimit (pingcap#145) * use user_storage_size instead of storage_size for ratelimit Signed-off-by: zeminzhou <zhouzemin@pingcap.com> * update golang.org/x/text to 0.3.8 Signed-off-by: zeminzhou <zhouzemin@pingcap.com> * Fix error handle when loadKeyspace failed at startup (pingcap#143) Signed-off-by: yongman <yming0221@gmail.com> Signed-off-by: yongman <yming0221@gmail.com> * add keyspace-activate mode (pingcap#142) * fix loadkeyspace nil (pingcap#144) * fix loadkeyspace nil Signed-off-by: ystaticy <y_static_y@sina.com> * retry load keyspace Signed-off-by: David <8039876+AmoebaProtozoa@users.noreply.github.com> * address comments Signed-off-by: David <8039876+AmoebaProtozoa@users.noreply.github.com> Signed-off-by: ystaticy <y_static_y@sina.com> Signed-off-by: David <8039876+AmoebaProtozoa@users.noreply.github.com> Co-authored-by: David <8039876+AmoebaProtozoa@users.noreply.github.com> * Compatible with old pd Signed-off-by: zeminzhou <zhouzemin@pingcap.com> Signed-off-by: zeminzhou <zhouzemin@pingcap.com> Signed-off-by: yongman <yming0221@gmail.com> Signed-off-by: ystaticy <y_static_y@sina.com> Signed-off-by: David <8039876+AmoebaProtozoa@users.noreply.github.com> Co-authored-by: yongman <yming0221@gmail.com> Co-authored-by: better0332 <better0332@163.com> Co-authored-by: ystaticy <y_static_y@sina.com> Co-authored-by: David <8039876+AmoebaProtozoa@users.noreply.github.com> * make check Signed-off-by: zeminzhou <zhouzemin@pingcap.com> * fix confict Signed-off-by: zeminzhou <zhouzemin@pingcap.com> * make check Signed-off-by: zeminzhou <zhouzemin@pingcap.com> Signed-off-by: zeminzhou <zhouzemin@pingcap.com> Signed-off-by: yongman <yming0221@gmail.com> Signed-off-by: ystaticy <y_static_y@sina.com> Signed-off-by: David <8039876+AmoebaProtozoa@users.noreply.github.com> Co-authored-by: yongman <yming0221@gmail.com> Co-authored-by: better0332 <better0332@163.com> Co-authored-by: ystaticy <y_static_y@sina.com> Co-authored-by: David <8039876+AmoebaProtozoa@users.noreply.github.com>
- Loading branch information
1 parent
ca134e7
commit e11f56c
Showing
13 changed files
with
296 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package config | ||
|
||
// RatelimitConfig contains ratelimit configuration options. | ||
type RatelimitConfig struct { | ||
FullSpeed int `toml:"full-speed" json:"full-speed"` | ||
FullSpeedCapacity int `toml:"full-speed-capacity" json:"full-speed-capacity"` | ||
LowSpeed int `toml:"low-speed" json:"low-speed"` | ||
LowSpeedCapacity int `toml:"low-speed-capacity" json:"low-speed-capacity"` | ||
LowSpeedWatermark int64 `toml:"low-speed-watermark" json:"low-speed-watermark"` | ||
BlockWriteWatermark int64 `toml:"block-write-watermark" json:"block-write-watermark"` | ||
} | ||
|
||
// defaultRatelimitConfig creates a new RatelimitConfig. | ||
func defaultRatelimitConfig() RatelimitConfig { | ||
return RatelimitConfig{ | ||
FullSpeed: 1024 * 1024, // 1MiB/s | ||
FullSpeedCapacity: 10 * 1024 * 1024, // 10MiB | ||
LowSpeed: 1024 * 10, // 10KiB/s | ||
LowSpeedCapacity: 1024 * 1024, // 1MiB | ||
LowSpeedWatermark: 1024 * 1024 * 1024, // 1GiB | ||
BlockWriteWatermark: 2 * 1024 * 1024 * 1024, // 2GiB | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
package keyspace | ||
|
||
import ( | ||
"encoding/binary" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
"sync" | ||
"sync/atomic" | ||
"time" | ||
|
||
"github.com/pingcap/tidb/config" | ||
"github.com/pingcap/tidb/util" | ||
"github.com/pingcap/tidb/util/codec" | ||
"github.com/pingcap/tidb/util/logutil" | ||
"go.uber.org/zap" | ||
) | ||
|
||
type rateLimiter struct { | ||
sync.Mutex | ||
accumulateSpeed int | ||
maxToken int | ||
|
||
token int | ||
lastUpdate int64 | ||
dataSize int64 | ||
} | ||
|
||
func (r *rateLimiter) Usage() int64 { | ||
return atomic.LoadInt64(&r.dataSize) | ||
} | ||
|
||
func (r *rateLimiter) MaxToken() int { | ||
r.Lock() | ||
defer r.Unlock() | ||
return r.maxToken | ||
} | ||
|
||
func (r *rateLimiter) Consume(n int) (bool, time.Duration) { | ||
r.Lock() | ||
defer r.Unlock() | ||
|
||
now := time.Now().Unix() | ||
if now > r.lastUpdate { | ||
r.token += int(now-r.lastUpdate) * r.accumulateSpeed | ||
if r.token > r.maxToken { | ||
r.token = r.maxToken | ||
} | ||
r.lastUpdate = now | ||
} | ||
|
||
if n <= r.token { | ||
r.token -= n | ||
return true, 0 | ||
} | ||
if n > r.maxToken { | ||
return false, 0 | ||
} | ||
return false, time.Duration((n-r.token)/r.accumulateSpeed+1) * time.Second | ||
} | ||
|
||
func (r *rateLimiter) updateSpeed(dataSize int64) { | ||
r.Lock() | ||
defer r.Unlock() | ||
|
||
cfg := config.GetGlobalConfig().Ratelimit | ||
|
||
speed, max := cfg.FullSpeed, cfg.FullSpeedCapacity | ||
if dataSize > cfg.LowSpeedWatermark { | ||
speed, max = cfg.LowSpeed, cfg.LowSpeedCapacity | ||
} | ||
if dataSize > cfg.BlockWriteWatermark { | ||
speed, max = 10, cfg.LowSpeedCapacity/2 // set a minimal value, or tidb-server may fail to start. | ||
} | ||
|
||
if speed != r.accumulateSpeed || max != r.maxToken { | ||
logutil.BgLogger().Info("update rate limit speed", zap.Int("speed", speed), zap.Int("max", max)) | ||
} | ||
|
||
r.accumulateSpeed = speed | ||
r.maxToken = max | ||
if r.token > r.maxToken { | ||
r.token = r.maxToken | ||
} | ||
atomic.StoreInt64(&r.dataSize, dataSize) | ||
} | ||
|
||
func (r *rateLimiter) StartAdjustLimit(pdAddrs []string, keyspaceID uint32) { | ||
r.adjustLimit(pdAddrs, keyspaceID) | ||
go func() { | ||
ticker := time.NewTicker(time.Minute) | ||
defer ticker.Stop() | ||
for { | ||
<-ticker.C | ||
r.adjustLimit(pdAddrs, keyspaceID) | ||
} | ||
}() | ||
} | ||
|
||
// PDRegionStats is the json response from PD. | ||
type PDRegionStats struct { | ||
StorageSize *int64 `json:"storage_size"` | ||
UserStorageSize *int64 `json:"user_storage_size"` | ||
} | ||
|
||
func (r *rateLimiter) adjustLimit(pdAddrs []string, keyspaceID uint32) { | ||
start, end := r.keyspaceRange(keyspaceID) | ||
for _, addr := range pdAddrs { | ||
path := fmt.Sprintf("/pd/api/v1/stats/region?start_key=%s&end_key=%s", url.QueryEscape(string(start)), url.QueryEscape(string(end))) | ||
res, err := util.InternalHTTPClient().Get(util.ComposeURL(addr, path)) | ||
if err != nil { | ||
logutil.BgLogger().Warn("get region stats failed", zap.String("pd", addr), zap.Error(err)) | ||
continue | ||
} | ||
defer res.Body.Close() | ||
if res.StatusCode != http.StatusOK { | ||
logutil.BgLogger().Warn("get region stats failed", zap.String("pd", addr), zap.Int("status", res.StatusCode)) | ||
continue | ||
} | ||
var stats PDRegionStats | ||
err = json.NewDecoder(res.Body).Decode(&stats) | ||
if err != nil { | ||
logutil.BgLogger().Warn("decode region stats failed", zap.String("pd", addr), zap.Error(err)) | ||
continue | ||
} | ||
|
||
var userStorageSize int64 | ||
if stats.UserStorageSize != nil { | ||
userStorageSize = *(stats.UserStorageSize) | ||
} else if stats.StorageSize != nil { | ||
userStorageSize = *(stats.StorageSize) | ||
} | ||
r.updateSpeed(userStorageSize * 1024 * 1024) // storage size unit is MiB. | ||
return | ||
} | ||
logutil.BgLogger().Error("get region stats failed from all PDs") | ||
} | ||
|
||
func (r *rateLimiter) keyspaceRange(id uint32) ([]byte, []byte) { | ||
var start, end [4]byte | ||
binary.BigEndian.PutUint32(start[:], id) | ||
binary.BigEndian.PutUint32(end[:], id+1) | ||
start[0], end[0] = 'x', 'x' // we only care about txn data. | ||
if id == 0xffffff { | ||
end[0] = 'x' + 1 // handle overflow for max keyspace id. | ||
} | ||
return codec.EncodeBytes(nil, start[:]), codec.EncodeBytes(nil, end[:]) | ||
} | ||
|
||
// Limiter is an instance of rateLimiter | ||
var Limiter = &rateLimiter{ | ||
accumulateSpeed: 10 * 1024, | ||
maxToken: 1024 * 1024, | ||
token: 1024 * 1024, | ||
lastUpdate: time.Now().Unix(), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.