[chore/performance] Make sender multiplier configurable (#1750)

This commit is contained in:
tobi 2023-05-08 19:03:38 +02:00 committed by GitHub
parent 37b4d9d179
commit cbb9e2d3f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 109 additions and 5 deletions

View file

@ -79,4 +79,36 @@ advanced-rate-limit-requests: 300
# Examples: [8, 4, 9, 0] # Examples: [8, 4, 9, 0]
# Default: 8 # Default: 8
advanced-throttling-multiplier: 8 advanced-throttling-multiplier: 8
# Int. CPU multiplier for the amount of goroutines to spawn in order to send messages via ActivityPub.
# Messages will be batched so that at most multiplier * CPU count messages will be sent out at once.
# This can be tuned to limit concurrent POSTing to remote inboxes, preventing your instance CPU
# usage from skyrocketing when an account with many followers posts a new status.
#
# Messages are split among available senders, and each sender processes its assigned messages in serial.
# For example, say a user with 1000 followers is on an instance with 2 CPUs. With the default multiplier
# of 2, this means 4 senders would be in process at once on this instance. When the user creates a new post,
# each sender would end up iterating through about 250 Create messages + delivering them to remote instances.
#
# If you set this to 0 or less, only 1 sender will be used regardless of CPU count. This may be
# useful in cases where you are working with very tight network or CPU constraints.
#
# Example values for multiplier 2 (default):
#
# 1 cpu = 2 concurrent senders
# 2 cpu = 4 concurrent senders
# 4 cpu = 8 concurrent senders
#
# Example values for multiplier 4:
#
# 1 cpu = 4 concurrent senders
# 2 cpu = 8 concurrent senders
# 4 cpu = 16 concurrent senders
#
# Example values for multiplier <1:
#
# 1 cpu = 1 concurrent sender
# 2 cpu = 1 concurrent sender
# 4 cpu = 1 concurrent sender
advanced-sender-multiplier: 2
``` ```

View file

@ -848,3 +848,35 @@ advanced-throttling-multiplier: 8
# Examples: [30s, 10s, 5s, 1m] # Examples: [30s, 10s, 5s, 1m]
# Default: 30s # Default: 30s
advanced-throttling-retry-after: "30s" advanced-throttling-retry-after: "30s"
# Int. CPU multiplier for the amount of goroutines to spawn in order to send messages via ActivityPub.
# Messages will be batched so that at most multiplier * CPU count messages will be sent out at once.
# This can be tuned to limit concurrent POSTing to remote inboxes, preventing your instance CPU
# usage from skyrocketing when an account with many followers posts a new status.
#
# Messages are split among available senders, and each sender processes its assigned messages in serial.
# For example, say a user with 1000 followers is on an instance with 2 CPUs. With the default multiplier
# of 2, this means 4 senders would be in process at once on this instance. When the user creates a new post,
# each sender would end up iterating through about 250 Create messages + delivering them to remote instances.
#
# If you set this to 0 or less, only 1 sender will be used regardless of CPU count. This may be
# useful in cases where you are working with very tight network or CPU constraints.
#
# Example values for multiplier 2 (default):
#
# 1 cpu = 2 concurrent senders
# 2 cpu = 4 concurrent senders
# 4 cpu = 8 concurrent senders
#
# Example values for multiplier 4:
#
# 1 cpu = 4 concurrent senders
# 2 cpu = 8 concurrent senders
# 4 cpu = 16 concurrent senders
#
# Example values for multiplier <1:
#
# 1 cpu = 1 concurrent sender
# 2 cpu = 1 concurrent sender
# 4 cpu = 1 concurrent sender
advanced-sender-multiplier: 2

View file

@ -141,6 +141,7 @@ type Configuration struct {
AdvancedRateLimitRequests int `name:"advanced-rate-limit-requests" usage:"Amount of HTTP requests to permit within a 5 minute window. 0 or less turns rate limiting off."` AdvancedRateLimitRequests int `name:"advanced-rate-limit-requests" usage:"Amount of HTTP requests to permit within a 5 minute window. 0 or less turns rate limiting off."`
AdvancedThrottlingMultiplier int `name:"advanced-throttling-multiplier" usage:"Multiplier to use per cpu for http request throttling. 0 or less turns throttling off."` AdvancedThrottlingMultiplier int `name:"advanced-throttling-multiplier" usage:"Multiplier to use per cpu for http request throttling. 0 or less turns throttling off."`
AdvancedThrottlingRetryAfter time.Duration `name:"advanced-throttling-retry-after" usage:"Retry-After duration response to send for throttled requests."` AdvancedThrottlingRetryAfter time.Duration `name:"advanced-throttling-retry-after" usage:"Retry-After duration response to send for throttled requests."`
AdvancedSenderMultiplier int `name:"advanced-sender-multiplier" usage:"Multiplier to use per cpu for batching outgoing fedi messages. 0 or less turns batching off (not recommended)."`
// Cache configuration vars. // Cache configuration vars.
Cache CacheConfiguration `name:"cache"` Cache CacheConfiguration `name:"cache"`

View file

@ -116,6 +116,7 @@ var Defaults = Configuration{
AdvancedCookiesSamesite: "lax", AdvancedCookiesSamesite: "lax",
AdvancedRateLimitRequests: 300, // 1 per second per 5 minutes AdvancedRateLimitRequests: 300, // 1 per second per 5 minutes
AdvancedThrottlingMultiplier: 8, // 8 open requests per CPU AdvancedThrottlingMultiplier: 8, // 8 open requests per CPU
AdvancedSenderMultiplier: 2, // 2 senders per CPU
Cache: CacheConfiguration{ Cache: CacheConfiguration{
GTS: GTSCacheConfiguration{ GTS: GTSCacheConfiguration{

View file

@ -144,6 +144,7 @@ func (s *ConfigState) AddServerFlags(cmd *cobra.Command) {
cmd.Flags().Int(AdvancedRateLimitRequestsFlag(), cfg.AdvancedRateLimitRequests, fieldtag("AdvancedRateLimitRequests", "usage")) cmd.Flags().Int(AdvancedRateLimitRequestsFlag(), cfg.AdvancedRateLimitRequests, fieldtag("AdvancedRateLimitRequests", "usage"))
cmd.Flags().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "usage")) cmd.Flags().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "usage"))
cmd.Flags().Duration(AdvancedThrottlingRetryAfterFlag(), cfg.AdvancedThrottlingRetryAfter, fieldtag("AdvancedThrottlingRetryAfter", "usage")) cmd.Flags().Duration(AdvancedThrottlingRetryAfterFlag(), cfg.AdvancedThrottlingRetryAfter, fieldtag("AdvancedThrottlingRetryAfter", "usage"))
cmd.Flags().Int(AdvancedSenderMultiplierFlag(), cfg.AdvancedSenderMultiplier, fieldtag("AdvancedSenderMultiplier", "usage"))
cmd.Flags().String(RequestIDHeaderFlag(), cfg.RequestIDHeader, fieldtag("RequestIDHeader", "usage")) cmd.Flags().String(RequestIDHeaderFlag(), cfg.RequestIDHeader, fieldtag("RequestIDHeader", "usage"))
}) })

View file

@ -2124,6 +2124,31 @@ func GetAdvancedThrottlingRetryAfter() time.Duration { return global.GetAdvanced
// SetAdvancedThrottlingRetryAfter safely sets the value for global configuration 'AdvancedThrottlingRetryAfter' field // SetAdvancedThrottlingRetryAfter safely sets the value for global configuration 'AdvancedThrottlingRetryAfter' field
func SetAdvancedThrottlingRetryAfter(v time.Duration) { global.SetAdvancedThrottlingRetryAfter(v) } func SetAdvancedThrottlingRetryAfter(v time.Duration) { global.SetAdvancedThrottlingRetryAfter(v) }
// GetAdvancedSenderMultiplier safely fetches the Configuration value for state's 'AdvancedSenderMultiplier' field
func (st *ConfigState) GetAdvancedSenderMultiplier() (v int) {
st.mutex.Lock()
v = st.config.AdvancedSenderMultiplier
st.mutex.Unlock()
return
}
// SetAdvancedSenderMultiplier safely sets the Configuration value for state's 'AdvancedSenderMultiplier' field
func (st *ConfigState) SetAdvancedSenderMultiplier(v int) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.AdvancedSenderMultiplier = v
st.reloadToViper()
}
// AdvancedSenderMultiplierFlag returns the flag name for the 'AdvancedSenderMultiplier' field
func AdvancedSenderMultiplierFlag() string { return "advanced-sender-multiplier" }
// GetAdvancedSenderMultiplier safely fetches the value for global configuration 'AdvancedSenderMultiplier' field
func GetAdvancedSenderMultiplier() int { return global.GetAdvancedSenderMultiplier() }
// SetAdvancedSenderMultiplier safely sets the value for global configuration 'AdvancedSenderMultiplier' field
func SetAdvancedSenderMultiplier(v int) { global.SetAdvancedSenderMultiplier(v) }
// GetCacheGTSAccountMaxSize safely fetches the Configuration value for state's 'Cache.GTS.AccountMaxSize' field // GetCacheGTSAccountMaxSize safely fetches the Configuration value for state's 'Cache.GTS.AccountMaxSize' field
func (st *ConfigState) GetCacheGTSAccountMaxSize() (v int) { func (st *ConfigState) GetCacheGTSAccountMaxSize() (v int) {
st.mutex.Lock() st.mutex.Lock()

View file

@ -57,10 +57,19 @@ type controller struct {
// NewController returns an implementation of the Controller interface for creating new transports // NewController returns an implementation of the Controller interface for creating new transports
func NewController(state *state.State, federatingDB federatingdb.DB, clock pub.Clock, client httpclient.SigningClient) Controller { func NewController(state *state.State, federatingDB federatingdb.DB, clock pub.Clock, client httpclient.SigningClient) Controller {
applicationName := config.GetApplicationName() var (
host := config.GetHost() applicationName = config.GetApplicationName()
proto := config.GetProtocol() host = config.GetHost()
version := config.GetSoftwareVersion() proto = config.GetProtocol()
version = config.GetSoftwareVersion()
senderMultiplier = config.GetAdvancedSenderMultiplier()
)
senders := senderMultiplier * runtime.GOMAXPROCS(0)
if senders < 1 {
// Clamp senders to 1.
senders = 1
}
c := &controller{ c := &controller{
state: state, state: state,
@ -69,7 +78,7 @@ func NewController(state *state.State, federatingDB federatingdb.DB, clock pub.C
client: client, client: client,
trspCache: cache.New[string, *transport](0, 100, 0), trspCache: cache.New[string, *transport](0, 100, 0),
userAgent: fmt.Sprintf("%s (+%s://%s) gotosocial/%s", applicationName, proto, host, version), userAgent: fmt.Sprintf("%s (+%s://%s) gotosocial/%s", applicationName, proto, host, version),
senders: 2 * runtime.GOMAXPROCS(0), // on batch delivery, only ever send 2*GOMAXPROCS at a time. senders: senders,
} }
return c return c

View file

@ -11,6 +11,7 @@ EXPECT=$(cat <<"EOF"
"accounts-registration-open": true, "accounts-registration-open": true,
"advanced-cookies-samesite": "strict", "advanced-cookies-samesite": "strict",
"advanced-rate-limit-requests": 6969, "advanced-rate-limit-requests": 6969,
"advanced-sender-multiplier": -1,
"advanced-throttling-multiplier": -1, "advanced-throttling-multiplier": -1,
"advanced-throttling-retry-after": 10000000000, "advanced-throttling-retry-after": 10000000000,
"application-name": "gts", "application-name": "gts",
@ -241,6 +242,7 @@ GTS_SYSLOG_PROTOCOL='udp' \
GTS_SYSLOG_ADDRESS='127.0.0.1:6969' \ GTS_SYSLOG_ADDRESS='127.0.0.1:6969' \
GTS_ADVANCED_COOKIES_SAMESITE='strict' \ GTS_ADVANCED_COOKIES_SAMESITE='strict' \
GTS_ADVANCED_RATE_LIMIT_REQUESTS=6969 \ GTS_ADVANCED_RATE_LIMIT_REQUESTS=6969 \
GTS_ADVANCED_SENDER_MULTIPLIER=-1 \
GTS_ADVANCED_THROTTLING_MULTIPLIER=-1 \ GTS_ADVANCED_THROTTLING_MULTIPLIER=-1 \
GTS_ADVANCED_THROTTLING_RETRY_AFTER='10s' \ GTS_ADVANCED_THROTTLING_RETRY_AFTER='10s' \
GTS_REQUEST_ID_HEADER='X-Trace-Id' \ GTS_REQUEST_ID_HEADER='X-Trace-Id' \

View file

@ -120,6 +120,7 @@ var testDefaults = config.Configuration{
AdvancedCookiesSamesite: "lax", AdvancedCookiesSamesite: "lax",
AdvancedRateLimitRequests: 0, // disabled AdvancedRateLimitRequests: 0, // disabled
AdvancedThrottlingMultiplier: 0, // disabled AdvancedThrottlingMultiplier: 0, // disabled
AdvancedSenderMultiplier: 0, // 1 sender only, regardless of CPU
SoftwareVersion: "0.0.0-testrig", SoftwareVersion: "0.0.0-testrig",