feat(loadtest): sync add real 500-session capacity harness
This commit is contained in:
parent
ac0566f779
commit
141f2f20c4
39 changed files with 4157 additions and 42 deletions
186
internal/mtprotoedge/runtime_metrics.go
Normal file
186
internal/mtprotoedge/runtime_metrics.go
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
package mtprotoedge
|
||||
|
||||
// RuntimeSnapshot is a point-in-time, identity-free view of the MTProto edge.
|
||||
// It deliberately exposes only bounded aggregate values so callers can publish
|
||||
// it through a metrics endpoint without leaking auth keys, sessions or remote
|
||||
// addresses. Values from independently locked components can differ by one
|
||||
// concurrent transition; every individual budget/count remains internally
|
||||
// consistent.
|
||||
type RuntimeSnapshot struct {
|
||||
RawConnections int64
|
||||
RawConnectionLimit int64
|
||||
Handshakes int64
|
||||
HandshakeLimit int64
|
||||
ActiveSessions int64
|
||||
ProvisionalSessions int64
|
||||
LogicalSessions int64
|
||||
OfflineLogicalSessions int64
|
||||
LogicalOutboxFrames int64
|
||||
LogicalOutboxBytes int64
|
||||
PendingPushBytes int64
|
||||
InboundRPCTasks int64
|
||||
InboundRPCBytes int64
|
||||
InboundRPCReadyConnections int64
|
||||
InboundRPCMaxTasks int64
|
||||
InboundRPCMaxBytes int64
|
||||
InboundFrameBytes int64
|
||||
InboundFrameMaxBytes int64
|
||||
OutboundTrackedBytes int64
|
||||
OutboundTrackedMaxBytes int64
|
||||
OutboundControlBytes int64
|
||||
OutboundControlMaxBytes int64
|
||||
OutboundWriteBytes int64
|
||||
OutboundWriteMaxBytes int64
|
||||
RPCResultOwners int64
|
||||
RPCResultReceipts int64
|
||||
RPCResultReceiptBytes int64
|
||||
RPCResultSubscribers int64
|
||||
}
|
||||
|
||||
type sessionManagerRuntimeSnapshot struct {
|
||||
active int64
|
||||
provisional int64
|
||||
logical int64
|
||||
offlineLogical int64
|
||||
frames int64
|
||||
bytes int64
|
||||
pendingBytes int64
|
||||
}
|
||||
|
||||
func (m *SessionManager) runtimeSnapshot() sessionManagerRuntimeSnapshot {
|
||||
if m == nil {
|
||||
return sessionManagerRuntimeSnapshot{}
|
||||
}
|
||||
|
||||
// Never hold SessionManager.mu while taking an outbound-state mutex. The
|
||||
// physical actor can publish/retire a Conn next to an outbox transition, and
|
||||
// metrics must not add a new cross-component lock order.
|
||||
m.mu.RLock()
|
||||
states := make([]*outboundState, 0, len(m.logicalSessions))
|
||||
result := sessionManagerRuntimeSnapshot{
|
||||
active: int64(len(m.bySession)),
|
||||
provisional: int64(len(m.claims)),
|
||||
logical: int64(len(m.logicalSessions)),
|
||||
}
|
||||
if m.pendingBudget != nil {
|
||||
result.pendingBytes = m.pendingBudget.snapshot()
|
||||
}
|
||||
for _, logical := range m.logicalSessions {
|
||||
if logical == nil {
|
||||
continue
|
||||
}
|
||||
if !logical.offlineAt.IsZero() {
|
||||
result.offlineLogical++
|
||||
}
|
||||
if logical.outbound != nil {
|
||||
states = append(states, logical.outbound)
|
||||
}
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
|
||||
for _, state := range states {
|
||||
state.mu.Lock()
|
||||
result.frames += int64(len(state.pending))
|
||||
result.bytes += int64(state.totalBytes)
|
||||
state.mu.Unlock()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type admissionRuntimeSnapshot struct {
|
||||
connections int64
|
||||
connectionLimit int64
|
||||
handshakes int64
|
||||
handshakeLimit int64
|
||||
}
|
||||
|
||||
func (a *admissionController) runtimeSnapshot() admissionRuntimeSnapshot {
|
||||
if a == nil {
|
||||
return admissionRuntimeSnapshot{}
|
||||
}
|
||||
a.mu.Lock()
|
||||
result := admissionRuntimeSnapshot{
|
||||
connections: int64(a.connections),
|
||||
connectionLimit: int64(a.maxConnections),
|
||||
}
|
||||
a.mu.Unlock()
|
||||
if a.handshakes != nil {
|
||||
result.handshakes = int64(len(a.handshakes))
|
||||
result.handshakeLimit = int64(cap(a.handshakes))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type inboundRPCRuntimeSnapshot struct {
|
||||
tasks int64
|
||||
bytes int64
|
||||
ready int64
|
||||
}
|
||||
|
||||
func (s *inboundRPCScheduler) runtimeSnapshot() inboundRPCRuntimeSnapshot {
|
||||
if s == nil {
|
||||
return inboundRPCRuntimeSnapshot{}
|
||||
}
|
||||
s.budgetMu.Lock()
|
||||
result := inboundRPCRuntimeSnapshot{tasks: int64(s.tasks), bytes: s.bytes}
|
||||
s.budgetMu.Unlock()
|
||||
s.readyMu.Lock()
|
||||
result.ready = int64(s.ready.Len())
|
||||
s.readyMu.Unlock()
|
||||
return result
|
||||
}
|
||||
|
||||
// RuntimeSnapshot returns aggregate MTProto ownership and capacity state.
|
||||
func (s *Server) RuntimeSnapshot() RuntimeSnapshot {
|
||||
if s == nil {
|
||||
return RuntimeSnapshot{}
|
||||
}
|
||||
sessions := s.conns.runtimeSnapshot()
|
||||
admission := s.admission.runtimeSnapshot()
|
||||
inbound := s.rpcScheduler.runtimeSnapshot()
|
||||
result := RuntimeSnapshot{
|
||||
RawConnections: admission.connections,
|
||||
RawConnectionLimit: admission.connectionLimit,
|
||||
Handshakes: admission.handshakes,
|
||||
HandshakeLimit: admission.handshakeLimit,
|
||||
ActiveSessions: sessions.active,
|
||||
ProvisionalSessions: sessions.provisional,
|
||||
LogicalSessions: sessions.logical,
|
||||
OfflineLogicalSessions: sessions.offlineLogical,
|
||||
LogicalOutboxFrames: sessions.frames,
|
||||
LogicalOutboxBytes: sessions.bytes,
|
||||
PendingPushBytes: sessions.pendingBytes,
|
||||
InboundRPCTasks: inbound.tasks,
|
||||
InboundRPCBytes: inbound.bytes,
|
||||
InboundRPCReadyConnections: inbound.ready,
|
||||
}
|
||||
if s.rpcScheduler != nil {
|
||||
result.InboundRPCMaxTasks = int64(s.rpcScheduler.maxTasks)
|
||||
result.InboundRPCMaxBytes = s.rpcScheduler.maxBytes
|
||||
}
|
||||
if s.frameBudget != nil {
|
||||
result.InboundFrameBytes = s.frameBudget.usedBytes()
|
||||
result.InboundFrameMaxBytes = s.frameBudget.max
|
||||
}
|
||||
if s.outboundTrackedBudget != nil {
|
||||
result.OutboundTrackedBytes = s.outboundTrackedBudget.snapshot()
|
||||
result.OutboundTrackedMaxBytes = s.outboundTrackedBudget.maxBytes
|
||||
}
|
||||
if s.outboundControlBudget != nil {
|
||||
result.OutboundControlBytes = s.outboundControlBudget.snapshot()
|
||||
result.OutboundControlMaxBytes = s.outboundControlBudget.maxBytes
|
||||
}
|
||||
if s.outboundScratchPool != nil && s.outboundScratchPool.budget != nil {
|
||||
result.OutboundWriteBytes = s.outboundScratchPool.snapshot()
|
||||
result.OutboundWriteMaxBytes = s.outboundScratchPool.budget.maxBytes
|
||||
}
|
||||
if s.rpcResults != nil {
|
||||
result.RPCResultOwners = s.rpcResults.flightLimit.snapshot()
|
||||
result.RPCResultReceipts = s.rpcResults.completedEntries.snapshot()
|
||||
result.RPCResultReceiptBytes = s.rpcResults.completedBytes.snapshot()
|
||||
if s.rpcResults.subscriberBudget != nil {
|
||||
result.RPCResultSubscribers = s.rpcResults.subscriberBudget.global.snapshot()
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue