Skip to content

Use secondary ring buffer for service log metadata. #685

@hpidcock

Description

@hpidcock

When developing the service log, we tried to be memory conscious to ensure that
buffering of logs would have an upper bound on memory consumption while also
being kind to the garbage collector by reusing memory.

Following this strategy, the implementation arrived at using a ring buffer per
service with metadata about each log line being stored as text. This made the
buffering and consumption of a single service very natural.

But in recent work highlighted in #673, performance issues with service log
parsing was brought to the surface. Since the blending of logs from multiple
ring buffers requires the parsing of log line metadata, it incurs unnecessary
cost to deserialise log lines to enable this blending.

Here it is proposed that the metadata from the service log is removed from the
ring buffer. The metadata is instead placed in either a structured double buffer
or a structured ring buffer.

// Entry is a parsed log entry.
type Entry struct {
    // Time of the log entry.
    Time    time.Time
    // Message is the start position in the [RingBuffer] for the log line.
    Message RingPos
}

// ServiceLog is a collection of 
type ServiceLog struct {
    // buffers is a double buffer of log entries.
    buffers [2][]Entry

    // Service is the name of the service emitted for this log.
    Service string

    // RingBuffer contains the message bytes for each log entry.
    RingBuffer RingBuffer
}

Currently the memory burden per service is at least 100KiB due to the size of
the RingBuffer created for that service. This change will increase the memory
burden by at least unsafe.Sizeof([1 or 2][N]Entry); for 10k log lines this
is an additional 32kB/64kB. This burden can be offset by reducing the size of
the RingBuffer to have a net change in cost of 0b.

The most obvious deficiency of this change is the dual limit on the length of
log history. Previously a limit of 100KiB, with some of the limit attributed to
metadata of the log lines. This proposal would limit on buffered message length
and limit on number of log lines. Worst case is either one very long line or N
small log lines. Desired average case may require analysis of real workloads or
the introduction of dynamic balancing of the ring buffer and log entry buffer to
minimise the number of buffered bytes or lines that are already detached from
each other (either the buffered bytes or the log entry are beyond the buffer).

This proposal offers an opportunity to simplify the RingBuffer implementation
by moving the iterator implementation over to the new service log buffer. It can
instead facilitate a per-log-entry iteration and the waiting for new entries.
The iterator can also be reduced in complexity, as the emitting of truncation
messages can be simplified.

Metadata

Metadata

Assignees

No one assigned

    Labels

    performancePerformance-oriented item

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions