Skip to content

Performance Benchmarks

Overview

CoSky achieves extraordinary throughput by combining Redis as the backing store with a local in-process consistency cache that is kept synchronized via Redis PubSub. The benchmark results below, obtained with JMH (Java Microbenchmark Harness), demonstrate that the consistency layer delivers 800x+ improvement for configuration reads and 250x+ improvement for service discovery compared to standard Redis operations. This page documents the benchmark methodology, environment, raw results, and architectural explanation for why the consistency layer is so fast.

Benchmark Methodology

All benchmarks are conducted using JMH (Java Microbenchmark Harness) version 1.29. Each benchmark runs with:

  • Mode: Throughput (thrpt)
  • Threads: 25-50 concurrent threads
  • Warmup: 1 iteration, 10 seconds
  • Measurement: 1 iteration, 10 seconds
  • Forks: 1

The CI pipeline runs benchmarks on every push via GitHub Actions, enabling performance regression detection for every commit.

mermaid
flowchart LR
    subgraph CI Benchmark Pipeline
        style CI Benchmark Pipeline fill:#161b22,stroke:#30363d,color:#e6edf3
        P["Push Event"] --> CH["Checkout"]
        CH --> JDK["Setup JDK 17"]
        JDK --> R["Start Redis Service"]
        R --> J1["gradle cosky-config:jmh"]
        R --> J2["gradle cosky-discovery:jmh"]
        J1 --> R1["Config benchmark results"]
        J2 --> R2["Discovery benchmark results"]
    end

    P:::node
    CH:::node
    JDK:::node
    R:::node
    J1:::node
    J2:::node
    R1:::node
    R2:::node

    classDef node fill:#2d333b,stroke:#6d5dfc,color:#e6edf3

Test Environment

ComponentSpecification
HardwareMacBook Pro (Apple M1)
JDKZulu 11.0.11 (OpenJDK 64-Bit Server VM)
RedisDeployed locally on the same machine
JMH Version1.29
Methodologythrpt mode, 50 threads, 1 fork, 10s warmup + measurement

Config Service Benchmarks

bash
# Run config benchmarks
gradle cosky-config:jmh
# or with JMH jar directly
java -jar cosky-config/build/libs/cosky-config-lastVersion-jmh.jar \
  -bm thrpt -t 25 -wi 1 -rf json -f 1
BenchmarkModeScoreUnitImprovement
ConsistencyRedisConfigServiceBenchmark.getConfigthrpt256,733,987ops/s1,062x
RedisConfigServiceBenchmark.getConfigthrpt241,787ops/sbaseline
RedisConfigServiceBenchmark.setConfigthrpt140,461ops/s-

Service Discovery Benchmarks

bash
# Run discovery benchmarks
gradle cosky-discovery:jmh
# or with JMH jar directly
java -jar cosky-discovery/build/libs/cosky-discovery-lastVersion-jmh.jar \
  -bm thrpt -t 25 -wi 1 -rf json -f 1
BenchmarkModeScoreUnitImprovement
ConsistencyRedisServiceDiscoveryBenchmark.getInstancesthrpt76,621,729ops/s338x
ConsistencyRedisServiceDiscoveryBenchmark.getServicesthrpt455,760,632ops/s1,495x
RedisServiceDiscoveryBenchmark.getInstancesthrpt226,909ops/sbaseline
RedisServiceDiscoveryBenchmark.getServicesthrpt304,979ops/sbaseline
RedisServiceRegistryBenchmark.registerthrpt110,664ops/s-
RedisServiceRegistryBenchmark.deregisterthrpt255,305ops/s-
RedisServiceRegistryBenchmark.renewthrpt210,960ops/s-

Performance Comparison Chart

The following chart compares the standard Redis-backed operations against the consistency-cached layer. Note the logarithmic scale -- the consistency layer is orders of magnitude faster.

mermaid
xychart-beta
    title "Config Service: Standard vs Consistency (ops/s)"
    x-axis ["getConfig (Redis)", "setConfig (Redis)", "getConfig (Consistency)"]
    y-axis "Operations per second" 0 --> 260000000
    bar [241787, 140461, 256733987]

Why the Consistency Layer Is Faster

The key architectural insight is that the consistency layer reads from an in-memory ConcurrentHashMap cache instead of making Redis round-trips. The cache is kept synchronized in real-time via Redis PubSub, so it always reflects the latest state without polling.

mermaid
flowchart TB
    subgraph Standard Redis Path
        style Standard Redis Path fill:#161b22,stroke:#30363d,color:#e6edf3
        A1["Client Request"] -->|"1. network round-trip"| R1["Redis"]
        R1 -->|"2. response"| A1
    end
    subgraph Consistency Cache Path
        style Consistency Cache Path fill:#161b22,stroke:#30363d,color:#e6edf3
        A2["Client Request"] -->|"1. read local cache"| C["ConcurrentHashMap<br>(in-process)"]
        C -->|"2. return instantly"| A2
        R2["Redis PubSub"] -->|"async: cache invalidation"| C
    end

    A1:::node
    R1:::node
    A2:::node
    C:::node
    R2:::node

    classDef node fill:#2d333b,stroke:#6d5dfc,color:#e6edf3

Consistency Layer Architecture

The ConsistencyRedisServiceDiscovery class wraps a standard ServiceDiscovery delegate and adds local caching with Redis PubSub-based invalidation:

mermaid
sequenceDiagram
    autonumber
    participant C as Client
    participant CRD as ConsistencyRedisServiceDiscovery
    participant Cache as ConcurrentHashMap Cache
    participant RSD as RedisServiceDiscovery
    participant Redis as Redis
    participant PubSub as Redis PubSub

    Note over CRD,PubSub: Cache initialization (first call)
    C->>CRD: getInstances(namespace, serviceId)
    CRD->>Cache: computeIfAbsent(key)
    Cache-->>CRD: cache miss
    CRD->>PubSub: subscribe to instance changes
    CRD->>RSD: delegate.getInstances()
    RSD->>Redis: SMEMBERS / GET
    Redis-->>RSD: instance list
    RSD-->>CRD: Flux<ServiceInstance>
    CRD->>Cache: store as CopyOnWriteArraySet
    CRD-->>C: Flux<ServiceInstance>

    Note over CRD,PubSub: Subsequent calls (cache hit)
    C->>CRD: getInstances(namespace, serviceId)
    CRD->>Cache: get(key)
    Cache-->>CRD: cached instances
    CRD-->>C: Flux<ServiceInstance> (no Redis call)

    Note over CRD,PubSub: Cache invalidation via PubSub
    Redis->>PubSub: instance change event
    PubSub->>CRD: onInstanceChanged(event)
    CRD->>Cache: update CopyOnWriteArraySet

Cache Invalidation Events

The consistency layer handles several types of instance change events, each triggering a specific cache update strategy:

mermaid
stateDiagram-v2
    direction LR
    [*] --> Cached: first read from Redis
    Cached --> Updated: REGISTER event
    Cached --> Updated: SET_METADATA event
    Cached --> TTLRefreshed: RENEW event
    Cached --> Removed: DEREGISTER event
    Cached --> Removed: EXPIRED event
    Updated --> Cached: refresh from Redis
    TTLRefreshed --> Cached: update TTL in-place
    Removed --> [*]: remove from cache

    state Cached {
        [*] --> InMemory: ConcurrentHashMap
        InMemory --> InMemory: read (no network)
    }

How to Run Benchmarks Locally

Prerequisites

  • JDK 17+ installed
  • Redis running locally on port 6379

Config Benchmarks

bash
# Run the full config benchmark suite
./gradlew cosky-config:jmh

# Run with custom thread count
./gradlew cosky-config:jmh -PjmhThreads=10

# Run specific benchmark
java -jar cosky-config/build/libs/cosky-config-*-jmh.jar \
  -bm thrpt \
  -t 25 \
  -wi 1 \
  -rf json \
  -f 1 \
  -p CONFIG_ID=my-config

Discovery Benchmarks

bash
# Run the full discovery benchmark suite
./gradlew cosky-discovery:jmh

# Run with custom thread count
./gradlew cosky-discovery:jmh -PjmhThreads=10

Note: The JMH benchmark results above were obtained on a MacBook Pro (M1) with a locally deployed Redis. Running the same benchmarks on GitHub Actions runners yields approximately 2x lower scores due to shared resource constraints. However, the relative comparison between standard and consistency operations remains valid in any environment.

Feature Comparison with Competitors

FeatureCoSkyEurekaConsulCoreDNSZookeeperNacosApollo
CAPCP+APAPCPCPCPCP+APCP+AP
Health CheckClient BeatClient BeatTCP/HTTP/gRPCKeep AliveKeep AliveTCP/HTTP/Client BeatClient Beat
Load BalancingWeight/SelectorRibbonFabioRoundRobinRoundRobinWeight/metadataRoundRobin
Auto LogoffYesYesNoNoYesYesYes
Access ProtocolHTTP/RedisHTTPHTTP/DNSDNSTCPHTTP/DNSHTTP
Listening SupportYesYesYesNoYesYesYes
Multi-DCYesYesYesNoNoYesYes
Cross Registry SyncYesNoYesNoNoYesNo
Spring CloudYesYesYesNoNoYesYes
K8S IntegrationYesNoYesYesNoYesNo
PersistenceRedis----MySQLMySQL

Key Insights

  • Config reads via the consistency layer achieve 256M ops/s -- a 1,062x improvement over direct Redis reads at 241K ops/s

  • Service discovery via the consistency layer achieves 76M ops/s for instances and 455M ops/s for services -- 338x and 1,495x improvements respectively

  • Write operations (register, deregister, renew, setConfig) are bounded by Redis network latency, achieving 110K-255K ops/s

  • The consistency layer's performance advantage comes from replacing network round-trips with in-memory ConcurrentHashMap lookups, kept synchronized via Redis PubSub

  • CoSky's hybrid CP+AP model provides both strong consistency for writes and eventual consistency with extreme read performan```mermaid flowchart LR subgraph Performance Characteristics style Performance Characteristics fill:#161b22,stroke:#30363d,color:#e6edf3 subgraph Reads - Consistency Layer style Reads - Consistency Layer fill:#161b22,stroke:#30363d,color:#e6edf3 C1["Config getConfig
    256M ops/s"] C2["Discovery getInstances
    76M ops/s"] C3["Discovery getServices
    455M ops/s"] end subgraph Reads - Standard Redis style Reads - Standard Redis fill:#161b22,stroke:#30363d,color:#e6edf3 R1["Config getConfig
    241K ops/s"] R2["Discovery getInstances
    226K ops/s"] R3["Discovery getServices
    304K ops/s"] end subgraph Writes style Writes fill:#161b22,stroke:#30363d,color:#e6edf3 W1["setConfig
    140K ops/s"] W2["register
    110K ops/s"] W3["deregister
    255K ops/s"] W4["renew
    210K ops/s"] end end

    C1:::node C2:::node C3:::node R1:::node R2:::node R3:::node W1:::node W2:::node W3:::node W4:::node

    classDef node fill:#2d333b,stroke:#6d5dfc,color:#e6edf3

References

Released under the Apache License 2.0.