refactor(mtproto): sync redesign RPC replay ownership

This commit is contained in:
iamxvbaba 2026-08-02 01:51:03 +08:00
parent 7e0f9d1e62
commit ac0566f779
28 changed files with 1304 additions and 343 deletions

View file

@ -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 {