Skip to content

LuminScope 1.0

Latest

Choose a tag to compare

@Titanius69 Titanius69 released this 22 Jul 13:00

LuminScope 1.0.0

First release.

Your proxy sits between every player and every backend, which makes it the only
component on your network that can see both halves of a round trip at the same
moment. LuminScope measures that layer and tells you what it means.


What it does

Names the plugin stalling your proxy. When the I/O threads block, the whole
network blocks with them and the log says nothing. LuminScope samples the thread
stacks during the stall, finds the topmost frame belonging to a plugin, and maps
it back to that plugin's id.

/luminscope blocking

3 stall(s) sampled.
 SomeEconomyPlugin  caught 14x at  EconomyStorage.loadBalance:88
 AnotherPlugin      caught 2x at   WebhookSender.post:41

Answers "why is it lagging" in sentences, not numbers. About a dozen rules run
over the collected metrics and produce a conclusion plus the next thing to try.
Exporting metrics is the easy half and the less useful one.

Splits latency three ways — player to proxy, proxy to backend, and the server
switch broken into connect and total phases. All percentiles, never averages.

Watches the JVM properly — GC pause counts rather than totals, heap, thread
counts, and off-heap buffer usage for catching Netty leaks.

Can drain an unresponsive backend from routing and ease it back gradually.
Off by default.


Also included

  • Prometheus / OpenMetrics endpoint, bearer token supported, localhost-bound by
    default
  • Discord webhook alerts with per-finding cooldowns
  • SpigotMC update checker, disabled until you set a resource id

Requirements

Velocity 3.3.0+, Java 17+.

No backend plugin. No database. No shaded dependencies — everything comes
from the JDK or is already on the Velocity classpath, so there is nothing here
that can conflict with the rest of your stack.


Installing

Drop the jar in plugins/, restart, run /luminscope.

Nothing needs configuring. The rule engine stays quiet for the first two minutes
of uptime, because a proxy that has just started has cold JIT and an unsettled
garbage collector, and every metric looks alarming during that window.


Worth doing on day one

Run /luminscope latency and /luminscope jvm on a healthy day at a busy hour
and write the numbers down. During an incident, "p99 backend RTT is 140 ms" means
nothing on its own and everything if you know it is normally 12 ms.


Known limitations

  • Event loop timing may be approximate. On some Velocity builds the probe
    cannot reach the real I/O executors and falls back to scheduler timing. It says
    so on /luminscope jvm rather than pretending. Trends stay useful; absolute
    thresholds are less reliable.
  • No backend TPS or MSPT. There is no companion plugin. LuminScope will tell
    you the problem is on a backend; run Spark there to find out what.
  • Plugin attribution blames the caller. A plugin calling a library that blocks
    gets named, not the library. That is the right answer — it chose to make that
    call on that thread.
  • Self-healing is untested at scale. It is deliberately conservative and off
    by default. Read the wiki page before enabling it on a production network.

Overhead

Under 1% of one core on a 500-player network. Stack sampling only during stalls,
fixed-bucket histograms at roughly 6 KB each, asynchronous pings, nothing on the
I/O threads but a no-op probe.

An observability tool that slows down what it observes has failed. Verify it
yourself with /luminscope jvm before and after.


Feedback

Bug reports with console output get fixed. If it concerns blocking detection,
include /luminscope blocking and /luminscope jvm output — that is the
difference between a fix and a guess.

MIT licensed.