Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[chore/performance] Make sender multiplier configurable #1750

Merged
merged 1 commit into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions docs/configuration/advanced.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,36 @@ advanced-rate-limit-requests: 300
# Examples: [8, 4, 9, 0]
# Default: 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
```
32 changes: 32 additions & 0 deletions example/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -848,3 +848,35 @@ advanced-throttling-multiplier: 8
# Examples: [30s, 10s, 5s, 1m]
# Default: 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
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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."`
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."`
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 CacheConfiguration `name:"cache"`
Expand Down
1 change: 1 addition & 0 deletions internal/config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ var Defaults = Configuration{
AdvancedCookiesSamesite: "lax",
AdvancedRateLimitRequests: 300, // 1 per second per 5 minutes
AdvancedThrottlingMultiplier: 8, // 8 open requests per CPU
AdvancedSenderMultiplier: 2, // 2 senders per CPU

Cache: CacheConfiguration{
GTS: GTSCacheConfiguration{
Expand Down
1 change: 1 addition & 0 deletions internal/config/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ func (s *ConfigState) AddServerFlags(cmd *cobra.Command) {
cmd.Flags().Int(AdvancedRateLimitRequestsFlag(), cfg.AdvancedRateLimitRequests, fieldtag("AdvancedRateLimitRequests", "usage"))
cmd.Flags().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "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"))
})
Expand Down
25 changes: 25 additions & 0 deletions internal/config/helpers.gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -2124,6 +2124,31 @@ func GetAdvancedThrottlingRetryAfter() time.Duration { return global.GetAdvanced
// SetAdvancedThrottlingRetryAfter safely sets the value for global configuration 'AdvancedThrottlingRetryAfter' field
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
func (st *ConfigState) GetCacheGTSAccountMaxSize() (v int) {
st.mutex.Lock()
Expand Down
19 changes: 14 additions & 5 deletions internal/transport/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,19 @@ type controller struct {

// 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 {
applicationName := config.GetApplicationName()
host := config.GetHost()
proto := config.GetProtocol()
version := config.GetSoftwareVersion()
var (
applicationName = config.GetApplicationName()
host = config.GetHost()
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{
state: state,
Expand All @@ -69,7 +78,7 @@ func NewController(state *state.State, federatingDB federatingdb.DB, clock pub.C
client: client,
trspCache: cache.New[string, *transport](0, 100, 0),
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
Expand Down
2 changes: 2 additions & 0 deletions test/envparsing.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ EXPECT=$(cat <<"EOF"
"accounts-registration-open": true,
"advanced-cookies-samesite": "strict",
"advanced-rate-limit-requests": 6969,
"advanced-sender-multiplier": -1,
"advanced-throttling-multiplier": -1,
"advanced-throttling-retry-after": 10000000000,
"application-name": "gts",
Expand Down Expand Up @@ -241,6 +242,7 @@ GTS_SYSLOG_PROTOCOL='udp' \
GTS_SYSLOG_ADDRESS='127.0.0.1:6969' \
GTS_ADVANCED_COOKIES_SAMESITE='strict' \
GTS_ADVANCED_RATE_LIMIT_REQUESTS=6969 \
GTS_ADVANCED_SENDER_MULTIPLIER=-1 \
GTS_ADVANCED_THROTTLING_MULTIPLIER=-1 \
GTS_ADVANCED_THROTTLING_RETRY_AFTER='10s' \
GTS_REQUEST_ID_HEADER='X-Trace-Id' \
Expand Down
1 change: 1 addition & 0 deletions testrig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ var testDefaults = config.Configuration{
AdvancedCookiesSamesite: "lax",
AdvancedRateLimitRequests: 0, // disabled
AdvancedThrottlingMultiplier: 0, // disabled
AdvancedSenderMultiplier: 0, // 1 sender only, regardless of CPU

SoftwareVersion: "0.0.0-testrig",

Expand Down