Skip to content

Performance and scaling

On October 27, 2026, one Go server handled 10,000 authenticated WebSpace WebSocket connections and delivered all 100,000 expected events. A mixed SQLite3 test also completed 1,000 writes and 10,000 reads while keeping 10,000 connections open.

Download the validation results and measurements for each run (JSON). These tests used the dedicated WebSpace real-time route, separate from Workspace chat.

Test environment and settings

ItemTest conditions
DateOctober 27, 2026, Korea Standard Time
ServerIntel Core i9-14900K, 32 logical CPUs, about 62.6 GiB RAM, one Go process
StorageNVMe SSD (SHPP41-2000GM), WSL2 virtual disk (ext4), Ubuntu 26.04
Load generatorsFour Node processes on the same machine, four loopback source IPs, one authenticated account
TransportLocal loopback; no WAN, TLS, or production proxy
SQLite3WAL, synchronous=NORMAL, 5-second busy timeout, up to eight read connections, one write queue per DB
WebSocket limits12,000 per server and per DB, 10,000 per IP, 10,000 messages per second per connection
HTTP limitsRead, mutation, and handshake: each 20,000 requests/second per IP, burst 30,000

A dedicated development build bypassed license tier checks. Authentication, permissions, and Origin checks ran through the normal WebSpace route. Databases were stored on disk-backed ext4, not a memory filesystem (tmpfs). The generators applied no read request pacing or limit on writes in flight.

HTTP limits were applied at startup through requestsPerSecond and burst under webspace.rateLimits.read, webspace.rateLimits.mutation, and webspace.rateLimits.handshake. These test settings differ from the defaults. Manage real-time connection limits under Services and capacity.

Connections and delivery from 5,000 to 10,000

Each connection received ten events, with three runs at each scale. Every run had zero missing, duplicate, or cross-room deliveries.

Authenticated connectionsDelivered / expected per runAll connections readyEvent delivery p95
5,00050,000 / 50,0001.25 s110 ms
7,50075,000 / 75,0001.77 s183 ms
10,000100,000 / 100,0002.66 s312 ms

Times are medians of three runs. Connection readiness includes generator startup, the connection ramp, authentication, and subscription completion. Delivery p95 is the 95th percentile of the time from sending an event to receiving it; the table shows the median of the three run-level p95 values. The September test timed completion of all ten events per connection, so its latency figures are not directly comparable.

1,000 SQLite3 writes and 10,000 reads

With 10,000 authenticated connections open, the generators issued 1,000 state changes to a shared resource alongside 10,000 HTTP reads. Each database serialized writes through its queue.

HTTP read concurrency settingRunsSuccessful writesSuccessful readsMixed workload completion
12831,000 / 1,000 per run10,000 / 10,000 per runMedian 2.69 s
10,00011,000 / 1,00010,000 / 10,0003.11 s

Completion covers the read/write phase after connection setup. A concurrency setting of 10,000 describes how clients issue requests; SQLite did not execute 10,000 queries at once. Its read pool allowed up to eight connections.

All reads returned HTTP 200, with no HTTP 429 responses or write errors. In the 10,000-request concurrency test, write p95 was 858 ms and read p95 was about 2.88 s. All four test databases had 1,000 unique actions, a resource value of 100,000→99,000, version 1,000, and 1,000 rewards. SQLite integrity_check returned ok for each database.

Active connections, rooms, and reconnection

A test with 10,000 connections sent ten events in each of twelve rounds, waiting five seconds between rounds. All 1,200,000 deliveries completed in about 67.27 seconds, with no missing or duplicate events. After 100 connections were abruptly closed and reconnected, all 10,000 follow-up events arrived.

A separate test split the connections across 100 rooms of 100 connections each. All 100,000 initial events arrived, with no cross-room delivery. Delivery after a 20-second idle period and after reconnecting 100 connections also passed. Across all 15 test cases, peak observed server RSS was about 1.50 GiB. No connections remained after the tests.

Latency and storage-path effects

During the active-connection test, periodic token revalidation across the full subscription namespace coincided with per-round delivery p95 values of about 1.91–2.31 seconds. The 312 ms figure from short delivery runs is therefore not a sustained latency guarantee.

An earlier test used the Windows shared filesystem in WSL (9p). Only 414 of 1,000 concurrent writes completed; the rest exceeded the five-second write wait/transaction budget. The successful results above used a WSL ext4 virtual disk on the same NVMe SSD. Results can vary with the storage access method.

With the default read limit of 500 requests/second per IP and a burst of 1,200, 37 reads returned HTTP 429. The final tests raised the HTTP limits instead of slowing the generators.

Choosing a configuration for your workload

WorkloadConfiguration to assess
Single server, internal tools, writes that can be queuedSQLite3, tested with your actual read/write ratio
Sustained writes across many rooms or resourcesConsider PostgreSQL or MySQL/MariaDB
Multiple servers and replicationAssess an external DB and event delivery between servers
Real-time delivery latencyCheck room size, message size, fan-out, and authentication revalidation cost

A queue orders concurrent writes; throughput remains bounded. The connection count here represents authenticated sockets from one account. The tests do not establish capacity for the complete workflows of 10,000 distinct users or a sustained long-running workload. Measure with your production TLS, proxies, WAN, and workload mix.

Use Operations to review requests, errors, response times, and DB status. For a complete user flow, try the sample in Build a real-time Gomoku game.