refactor(mtproto): sync redesign RPC replay ownership
This commit is contained in:
parent
7e0f9d1e62
commit
ac0566f779
28 changed files with 1304 additions and 343 deletions
|
|
@ -60,14 +60,12 @@ type Config struct {
|
|||
MTProtoRPCGlobalWorkers int
|
||||
MTProtoRPCGlobalMaxTasks int
|
||||
MTProtoRPCGlobalMaxBytes int64
|
||||
// Pending ownership and completed rpc_result replay state share a three-level
|
||||
// global/raw-auth/session budget over the full MTProto duplicate horizon.
|
||||
// Pending ownership and compact completed receipts share three-level
|
||||
// global/raw-auth/session entry accounting. Result bodies are never cached
|
||||
// here; the logical-session outbox owns unacknowledged wire bytes.
|
||||
MTProtoRPCResultCacheMaxEntries int
|
||||
MTProtoRPCResultCacheMaxBytes int64
|
||||
MTProtoRPCResultCacheAuthMaxEntries int
|
||||
MTProtoRPCResultCacheAuthMaxBytes int64
|
||||
MTProtoRPCResultCacheSessionMaxEntries int
|
||||
MTProtoRPCResultCacheSessionMaxBytes int64
|
||||
MTProtoRPCResultPendingPerAuth int
|
||||
// MTProtoInboundFrameGlobalMaxBytes 是 transport wire + 最大解密 plaintext 的
|
||||
// 进程级在途预算;frame 长度读出后、payload 分配前预留。
|
||||
|
|
@ -571,6 +569,9 @@ func Load() (Config, error) {
|
|||
envInt64Or := fileEnv.envInt64Or
|
||||
envDurationOr := fileEnv.envDurationOr
|
||||
envAllowEmptyOr := fileEnv.envAllowEmptyOr
|
||||
if err := validateStrictMTProtoCapacityEnv(fileEnv); err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
publicBaseURL, err := links.ValidateBaseURL(envOr("TELESRV_PUBLIC_BASE_URL", links.DefaultPublicBaseURL))
|
||||
if err != nil {
|
||||
|
|
@ -629,15 +630,10 @@ func Load() (Config, error) {
|
|||
MTProtoRPCGlobalMaxTasks: envIntOr("TELESRV_MTPROTO_RPC_GLOBAL_MAX_TASKS", 8192),
|
||||
MTProtoRPCGlobalMaxBytes: envInt64Or("TELESRV_MTPROTO_RPC_GLOBAL_MAX_BYTES", 512<<20),
|
||||
MTProtoRPCResultCacheMaxEntries: envIntOr("TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES", 1<<18),
|
||||
MTProtoRPCResultCacheMaxBytes: envInt64Or("TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_BYTES", 64<<20),
|
||||
MTProtoRPCResultCacheAuthMaxEntries: envIntOr("TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_ENTRIES", 1<<15),
|
||||
MTProtoRPCResultCacheAuthMaxBytes: envInt64Or("TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_BYTES", 32<<20),
|
||||
MTProtoRPCResultCacheSessionMaxEntries: envIntOr(
|
||||
"TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_ENTRIES", 1<<14,
|
||||
),
|
||||
MTProtoRPCResultCacheSessionMaxBytes: envInt64Or(
|
||||
"TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_BYTES", 16<<20,
|
||||
),
|
||||
MTProtoRPCResultPendingPerAuth: envIntOr("TELESRV_MTPROTO_RPC_RESULT_PENDING_PER_AUTH", 1<<11),
|
||||
MTProtoInboundFrameGlobalMaxBytes: envInt64Or("TELESRV_MTPROTO_INBOUND_FRAME_GLOBAL_MAX_BYTES", 512<<20),
|
||||
MTProtoOutboundQueueSize: envIntOr("TELESRV_MTPROTO_OUTBOUND_QUEUE_SIZE", 128),
|
||||
|
|
@ -1211,8 +1207,6 @@ func validateCollectibleUsernameConfig(cfg Config) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
const mtProtoRPCResultMinBytes = int64((1 << 24) - (2 << 10))
|
||||
|
||||
func validateRPCResultCacheConfig(cfg Config) error {
|
||||
if cfg.MTProtoRPCResultCacheMaxEntries <= 0 || cfg.MTProtoRPCResultCacheAuthMaxEntries <= 0 ||
|
||||
cfg.MTProtoRPCResultCacheSessionMaxEntries <= 0 {
|
||||
|
|
@ -1223,18 +1217,6 @@ func validateRPCResultCacheConfig(cfg Config) error {
|
|||
return fmt.Errorf("MTProto rpc_result entry hierarchy must satisfy global >= auth >= session: %d/%d/%d",
|
||||
cfg.MTProtoRPCResultCacheMaxEntries, cfg.MTProtoRPCResultCacheAuthMaxEntries, cfg.MTProtoRPCResultCacheSessionMaxEntries)
|
||||
}
|
||||
if cfg.MTProtoRPCResultCacheMaxBytes < mtProtoRPCResultMinBytes ||
|
||||
cfg.MTProtoRPCResultCacheAuthMaxBytes < mtProtoRPCResultMinBytes ||
|
||||
cfg.MTProtoRPCResultCacheSessionMaxBytes < mtProtoRPCResultMinBytes {
|
||||
return fmt.Errorf("MTProto rpc_result byte limits must each be at least %d: %d/%d/%d",
|
||||
mtProtoRPCResultMinBytes, cfg.MTProtoRPCResultCacheMaxBytes,
|
||||
cfg.MTProtoRPCResultCacheAuthMaxBytes, cfg.MTProtoRPCResultCacheSessionMaxBytes)
|
||||
}
|
||||
if cfg.MTProtoRPCResultCacheMaxBytes < cfg.MTProtoRPCResultCacheAuthMaxBytes ||
|
||||
cfg.MTProtoRPCResultCacheAuthMaxBytes < cfg.MTProtoRPCResultCacheSessionMaxBytes {
|
||||
return fmt.Errorf("MTProto rpc_result byte hierarchy must satisfy global >= auth >= session: %d/%d/%d",
|
||||
cfg.MTProtoRPCResultCacheMaxBytes, cfg.MTProtoRPCResultCacheAuthMaxBytes, cfg.MTProtoRPCResultCacheSessionMaxBytes)
|
||||
}
|
||||
if cfg.MTProtoRPCGlobalMaxTasks <= 0 || cfg.MTProtoRPCResultPendingPerAuth <= 0 ||
|
||||
cfg.MTProtoRPCResultPendingPerAuth > cfg.MTProtoRPCGlobalMaxTasks ||
|
||||
cfg.MTProtoRPCResultPendingPerAuth > cfg.MTProtoRPCResultCacheAuthMaxEntries {
|
||||
|
|
@ -1525,6 +1507,43 @@ func (e envSource) envIntOr(key string, def int) int {
|
|||
return def
|
||||
}
|
||||
|
||||
func validateStrictMTProtoCapacityEnv(e envSource) error {
|
||||
for _, key := range []string{
|
||||
"TELESRV_MTPROTO_MAX_CONNECTIONS",
|
||||
"TELESRV_MTPROTO_MAX_CONNECTIONS_PER_IP",
|
||||
"TELESRV_MTPROTO_MAX_CONCURRENT_HANDSHAKES",
|
||||
"TELESRV_MTPROTO_RPC_MAX_INFLIGHT",
|
||||
"TELESRV_MTPROTO_RPC_QUEUE_SIZE",
|
||||
"TELESRV_MTPROTO_RPC_GLOBAL_WORKERS",
|
||||
"TELESRV_MTPROTO_RPC_GLOBAL_MAX_TASKS",
|
||||
"TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES",
|
||||
"TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_ENTRIES",
|
||||
"TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_ENTRIES",
|
||||
"TELESRV_MTPROTO_RPC_RESULT_PENDING_PER_AUTH",
|
||||
"TELESRV_MTPROTO_OUTBOUND_QUEUE_SIZE",
|
||||
"TELESRV_MTPROTO_OUTBOUND_CONTROL_QUEUE_SIZE",
|
||||
} {
|
||||
if raw := e.envOr(key, ""); raw != "" {
|
||||
if _, err := strconv.Atoi(raw); err != nil {
|
||||
return fmt.Errorf("%s must be a base-10 integer: %w", key, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, key := range []string{
|
||||
"TELESRV_MTPROTO_RPC_GLOBAL_MAX_BYTES",
|
||||
"TELESRV_MTPROTO_INBOUND_FRAME_GLOBAL_MAX_BYTES",
|
||||
"TELESRV_MTPROTO_OUTBOUND_TRACKED_GLOBAL_MAX_BYTES",
|
||||
"TELESRV_MTPROTO_OUTBOUND_WRITE_GLOBAL_MAX_BYTES",
|
||||
} {
|
||||
if raw := e.envOr(key, ""); raw != "" {
|
||||
if _, err := strconv.ParseInt(raw, 10, 64); err != nil {
|
||||
return fmt.Errorf("%s must be a base-10 int64: %w", key, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e envSource) envInt64Or(key string, def int64) int64 {
|
||||
if v := e.envOr(key, ""); v != "" {
|
||||
if n, err := strconv.ParseInt(v, 10, 64); err == nil {
|
||||
|
|
|
|||
|
|
@ -151,11 +151,8 @@ func TestLoadMTProtoAdmissionAndRPCBudgets(t *testing.T) {
|
|||
t.Setenv("TELESRV_MTPROTO_RPC_GLOBAL_MAX_TASKS", "444")
|
||||
t.Setenv("TELESRV_MTPROTO_RPC_GLOBAL_MAX_BYTES", "555555")
|
||||
t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES", "555")
|
||||
t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_BYTES", "70000000")
|
||||
t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_ENTRIES", "444")
|
||||
t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_BYTES", "40000000")
|
||||
t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_ENTRIES", "333")
|
||||
t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_BYTES", "20000000")
|
||||
t.Setenv("TELESRV_MTPROTO_RPC_RESULT_PENDING_PER_AUTH", "222")
|
||||
t.Setenv("TELESRV_MTPROTO_INBOUND_FRAME_GLOBAL_MAX_BYTES", "777777")
|
||||
t.Setenv("TELESRV_MTPROTO_OUTBOUND_QUEUE_SIZE", "88")
|
||||
|
|
@ -177,14 +174,14 @@ func TestLoadMTProtoAdmissionAndRPCBudgets(t *testing.T) {
|
|||
cfg.MTProtoRPCGlobalWorkers != 33 || cfg.MTProtoRPCGlobalMaxTasks != 444 || cfg.MTProtoRPCGlobalMaxBytes != 555555 {
|
||||
t.Fatalf("rpc budget config = %d/%d/%v/%d/%d/%d", cfg.MTProtoRPCMaxInflight, cfg.MTProtoRPCQueueSize, cfg.MTProtoRPCTimeout, cfg.MTProtoRPCGlobalWorkers, cfg.MTProtoRPCGlobalMaxTasks, cfg.MTProtoRPCGlobalMaxBytes)
|
||||
}
|
||||
if cfg.MTProtoRPCResultCacheMaxEntries != 555 || cfg.MTProtoRPCResultCacheMaxBytes != 70000000 ||
|
||||
cfg.MTProtoRPCResultCacheAuthMaxEntries != 444 || cfg.MTProtoRPCResultCacheAuthMaxBytes != 40000000 ||
|
||||
cfg.MTProtoRPCResultCacheSessionMaxEntries != 333 || cfg.MTProtoRPCResultCacheSessionMaxBytes != 20000000 ||
|
||||
if cfg.MTProtoRPCResultCacheMaxEntries != 555 ||
|
||||
cfg.MTProtoRPCResultCacheAuthMaxEntries != 444 ||
|
||||
cfg.MTProtoRPCResultCacheSessionMaxEntries != 333 ||
|
||||
cfg.MTProtoRPCResultPendingPerAuth != 222 {
|
||||
t.Fatalf("rpc result cache config = global:%d/%d auth:%d/%d session:%d/%d pending/auth:%d",
|
||||
cfg.MTProtoRPCResultCacheMaxEntries, cfg.MTProtoRPCResultCacheMaxBytes,
|
||||
cfg.MTProtoRPCResultCacheAuthMaxEntries, cfg.MTProtoRPCResultCacheAuthMaxBytes,
|
||||
cfg.MTProtoRPCResultCacheSessionMaxEntries, cfg.MTProtoRPCResultCacheSessionMaxBytes,
|
||||
t.Fatalf("rpc result receipt config = global:%d auth:%d session:%d pending/auth:%d",
|
||||
cfg.MTProtoRPCResultCacheMaxEntries,
|
||||
cfg.MTProtoRPCResultCacheAuthMaxEntries,
|
||||
cfg.MTProtoRPCResultCacheSessionMaxEntries,
|
||||
cfg.MTProtoRPCResultPendingPerAuth)
|
||||
}
|
||||
if cfg.MTProtoInboundFrameGlobalMaxBytes != 777777 {
|
||||
|
|
@ -204,14 +201,14 @@ func TestLoadRPCResultFairBudgetDefaults(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if cfg.MTProtoRPCResultCacheMaxEntries != 1<<18 || cfg.MTProtoRPCResultCacheMaxBytes != 64<<20 ||
|
||||
cfg.MTProtoRPCResultCacheAuthMaxEntries != 1<<15 || cfg.MTProtoRPCResultCacheAuthMaxBytes != 32<<20 ||
|
||||
cfg.MTProtoRPCResultCacheSessionMaxEntries != 1<<14 || cfg.MTProtoRPCResultCacheSessionMaxBytes != 16<<20 ||
|
||||
if cfg.MTProtoRPCResultCacheMaxEntries != 1<<18 ||
|
||||
cfg.MTProtoRPCResultCacheAuthMaxEntries != 1<<15 ||
|
||||
cfg.MTProtoRPCResultCacheSessionMaxEntries != 1<<14 ||
|
||||
cfg.MTProtoRPCResultPendingPerAuth != 1<<11 {
|
||||
t.Fatalf("rpc_result fair defaults = global:%d/%d auth:%d/%d session:%d/%d pending/auth:%d",
|
||||
cfg.MTProtoRPCResultCacheMaxEntries, cfg.MTProtoRPCResultCacheMaxBytes,
|
||||
cfg.MTProtoRPCResultCacheAuthMaxEntries, cfg.MTProtoRPCResultCacheAuthMaxBytes,
|
||||
cfg.MTProtoRPCResultCacheSessionMaxEntries, cfg.MTProtoRPCResultCacheSessionMaxBytes,
|
||||
t.Fatalf("rpc_result receipt defaults = global:%d auth:%d session:%d pending/auth:%d",
|
||||
cfg.MTProtoRPCResultCacheMaxEntries,
|
||||
cfg.MTProtoRPCResultCacheAuthMaxEntries,
|
||||
cfg.MTProtoRPCResultCacheSessionMaxEntries,
|
||||
cfg.MTProtoRPCResultPendingPerAuth)
|
||||
}
|
||||
}
|
||||
|
|
@ -223,8 +220,6 @@ func TestLoadRejectsInvalidRPCResultFairBudgets(t *testing.T) {
|
|||
value string
|
||||
}{
|
||||
{name: "entry hierarchy", key: "TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES", value: "1024"},
|
||||
{name: "byte below outbound body", key: "TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_BYTES", value: "16700000"},
|
||||
{name: "byte hierarchy", key: "TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_BYTES", value: "70000000"},
|
||||
{name: "pending hierarchy", key: "TELESRV_MTPROTO_RPC_RESULT_PENDING_PER_AUTH", value: "9000"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
|
|
@ -238,6 +233,27 @@ func TestLoadRejectsInvalidRPCResultFairBudgets(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestLoadRejectsMalformedMTProtoCapacity(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
key string
|
||||
value string
|
||||
}{
|
||||
{name: "worker tasks malformed", key: "TELESRV_MTPROTO_RPC_GLOBAL_MAX_TASKS", value: "lots"},
|
||||
{name: "receipt entries overflow", key: "TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES", value: "999999999999999999999999"},
|
||||
{name: "tracked bytes overflow", key: "TELESRV_MTPROTO_OUTBOUND_TRACKED_GLOBAL_MAX_BYTES", value: "999999999999999999999999"},
|
||||
{name: "outbound queue malformed", key: "TELESRV_MTPROTO_OUTBOUND_QUEUE_SIZE", value: "many"},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
disableDefaultConfigFile(t)
|
||||
t.Setenv(test.key, test.value)
|
||||
if _, err := Load(); err == nil {
|
||||
t.Fatalf("Load accepted %s=%q", test.key, test.value)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadOutboxPoisonPolicy(t *testing.T) {
|
||||
disableDefaultConfigFile(t)
|
||||
t.Setenv("TELESRV_OUTBOX_POISON_RETENTION", "2m")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue