snapshot of https://github.com/nats-io/nats-server.git (main, 2026-09-15; blobs > 131072B omitted)
Some checks failed
NATS Server Tests / Lint (push) Failing after 3s
NATS Server Tests / Build (Latest Go) (push) Has been skipped
NATS Server Tests / Build (Minimum Go) (push) Has been skipped
NATS Server Tests / Build (Minimum Go, windows-2022) (push) Has been skipped
NATS Server Tests / Build (Minimum Go, windows-2025) (push) Has been skipped
NATS Server Tests / Test Stores (push) Has been skipped
NATS Server Tests / Test JetStream (push) Has been skipped
NATS Server Tests / Test Raft (push) Has been skipped
NATS Server Tests / Test JetStream Consumers (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 1 (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 2 (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 3 (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 4 (push) Has been skipped
NATS Server Tests / Test JetStream Supercluster (push) Has been skipped
NATS Server Tests / Test No-Race 1 (push) Has been skipped
NATS Server Tests / Test No-Race 2 (push) Has been skipped
NATS Server Tests / Test MQTT (push) Has been skipped
NATS Server Tests / Test Message Tracing (push) Has been skipped
NATS Server Tests / Test JWT (push) Has been skipped
NATS Server Tests / Test Remaining Server Tests (push) Has been skipped
NATS Server Tests / Test Other Packages (push) Has been skipped
Vulnerability Scan / govulncheck (push) Failing after 12m2s
Some checks failed
NATS Server Tests / Lint (push) Failing after 3s
NATS Server Tests / Build (Latest Go) (push) Has been skipped
NATS Server Tests / Build (Minimum Go) (push) Has been skipped
NATS Server Tests / Build (Minimum Go, windows-2022) (push) Has been skipped
NATS Server Tests / Build (Minimum Go, windows-2025) (push) Has been skipped
NATS Server Tests / Test Stores (push) Has been skipped
NATS Server Tests / Test JetStream (push) Has been skipped
NATS Server Tests / Test Raft (push) Has been skipped
NATS Server Tests / Test JetStream Consumers (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 1 (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 2 (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 3 (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 4 (push) Has been skipped
NATS Server Tests / Test JetStream Supercluster (push) Has been skipped
NATS Server Tests / Test No-Race 1 (push) Has been skipped
NATS Server Tests / Test No-Race 2 (push) Has been skipped
NATS Server Tests / Test MQTT (push) Has been skipped
NATS Server Tests / Test Message Tracing (push) Has been skipped
NATS Server Tests / Test JWT (push) Has been skipped
NATS Server Tests / Test Remaining Server Tests (push) Has been skipped
NATS Server Tests / Test Other Packages (push) Has been skipped
Vulnerability Scan / govulncheck (push) Failing after 12m2s
This commit is contained in:
350
server/jetstream_meta_benchmark_test.go
Normal file
350
server/jetstream_meta_benchmark_test.go
Normal file
@@ -0,0 +1,350 @@
|
||||
// Copyright 2024-2025 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !skip_js_tests && !skip_js_cluster_tests && !skip_js_cluster_tests_2
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
func BenchmarkJetStreamCreate(b *testing.B) {
|
||||
|
||||
const (
|
||||
verbose = false
|
||||
resourcePrefix = "S"
|
||||
concurrency = 12
|
||||
)
|
||||
|
||||
// Types of resource that this benchmark creates
|
||||
type ResourceType string
|
||||
const (
|
||||
Stream ResourceType = "Stream"
|
||||
KVBucket ResourceType = "KVBucket"
|
||||
ObjectStore ResourceType = "ObjStore"
|
||||
)
|
||||
|
||||
resourceTypeCases := []ResourceType{
|
||||
Stream,
|
||||
KVBucket,
|
||||
ObjectStore,
|
||||
}
|
||||
|
||||
benchmarksCases := []struct {
|
||||
clusterSize int
|
||||
replicas int
|
||||
storage nats.StorageType
|
||||
}{
|
||||
{1, 1, nats.MemoryStorage},
|
||||
{3, 3, nats.MemoryStorage},
|
||||
{3, 3, nats.FileStorage},
|
||||
}
|
||||
|
||||
for _, bc := range benchmarksCases {
|
||||
bName := fmt.Sprintf(
|
||||
"N=%d,R=%d,storage=%s,C=%d",
|
||||
bc.clusterSize,
|
||||
bc.replicas,
|
||||
bc.storage.String(),
|
||||
concurrency,
|
||||
)
|
||||
|
||||
b.Run(
|
||||
bName,
|
||||
func(b *testing.B) {
|
||||
for _, rt := range resourceTypeCases {
|
||||
//for _, bc := range benchmarksCases {
|
||||
rName := fmt.Sprintf("resource=%s", rt)
|
||||
b.Run(
|
||||
rName,
|
||||
func(b *testing.B) {
|
||||
|
||||
if verbose {
|
||||
b.Logf(
|
||||
"Creating %d %s resources in cluster with %d nodes, R=%d, %s storage",
|
||||
b.N,
|
||||
string(rt),
|
||||
bc.clusterSize,
|
||||
bc.replicas,
|
||||
bc.storage,
|
||||
)
|
||||
}
|
||||
|
||||
// Setup server or cluster
|
||||
_, leaderServer, shutdown, nc, _ := startJSClusterAndConnect(b, bc.clusterSize)
|
||||
defer shutdown()
|
||||
defer nc.Close()
|
||||
|
||||
// All clients connect to cluster (meta) leader for lower variability
|
||||
connectURL := leaderServer.ClientURL()
|
||||
|
||||
// Wait for all clients and main routine to be ready
|
||||
wgReady := sync.WaitGroup{}
|
||||
wgReady.Add(concurrency + 1)
|
||||
// Wait for all routines to complete
|
||||
wgComplete := sync.WaitGroup{}
|
||||
wgComplete.Add(concurrency)
|
||||
|
||||
// Number of operations (divided amongst clients)
|
||||
opsLeft := atomic.Int64{}
|
||||
opsLeft.Store(int64(b.N))
|
||||
totalErrors := atomic.Int64{}
|
||||
|
||||
// Pre-create connections and JS contexts
|
||||
for i := 1; i <= concurrency; i++ {
|
||||
nc, js := jsClientConnectURL(b, connectURL)
|
||||
defer nc.Close()
|
||||
go func(clientId int, nc *nats.Conn, js nats.JetStreamContext) {
|
||||
defer wgComplete.Done()
|
||||
|
||||
// Config struct (reused and modified in place for each call)
|
||||
streamConfig := nats.StreamConfig{
|
||||
Name: "?",
|
||||
Storage: bc.storage,
|
||||
Replicas: bc.replicas,
|
||||
}
|
||||
kvConfig := nats.KeyValueConfig{
|
||||
Bucket: "?",
|
||||
Storage: bc.storage,
|
||||
Replicas: bc.replicas,
|
||||
}
|
||||
objConfig := nats.ObjectStoreConfig{
|
||||
Bucket: "?",
|
||||
Storage: bc.storage,
|
||||
Replicas: bc.replicas,
|
||||
}
|
||||
|
||||
// Block until everyone is ready
|
||||
wgReady.Done()
|
||||
wgReady.Wait()
|
||||
|
||||
errCount := int64(0)
|
||||
defer func() {
|
||||
// Roll up error count on completion
|
||||
totalErrors.Add(errCount)
|
||||
}()
|
||||
|
||||
// Track per-client opCount (just for logging/debugging)
|
||||
opCount := 0
|
||||
for opsLeft.Add(-1) >= 0 {
|
||||
var err error
|
||||
// Create unique resource name
|
||||
resourceName := fmt.Sprintf("%s_%d_%d", resourcePrefix, clientId, opCount)
|
||||
switch rt {
|
||||
case Stream:
|
||||
streamConfig.Name = resourceName
|
||||
_, err = js.AddStream(&streamConfig)
|
||||
case KVBucket:
|
||||
kvConfig.Bucket = resourceName
|
||||
_, err = js.CreateKeyValue(&kvConfig)
|
||||
case ObjectStore:
|
||||
objConfig.Bucket = resourceName
|
||||
_, err = js.CreateObjectStore(&objConfig)
|
||||
}
|
||||
opCount += 1
|
||||
if err != nil {
|
||||
b.Logf("Error creating %s (%s): %s", rt, resourceName, err)
|
||||
errCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
if verbose {
|
||||
b.Logf("Client %d completed %d operations", clientId, opCount)
|
||||
}
|
||||
|
||||
}(i, nc, js)
|
||||
}
|
||||
|
||||
// Wait for all clients to be ready
|
||||
wgReady.Done()
|
||||
wgReady.Wait()
|
||||
|
||||
// Start benchmark clock
|
||||
b.ResetTimer()
|
||||
|
||||
wgComplete.Wait()
|
||||
b.StopTimer()
|
||||
|
||||
b.ReportMetric(float64(100*(totalErrors.Load()))/float64(b.N), "%error")
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkJetStreamCreateConsumers(b *testing.B) {
|
||||
|
||||
const (
|
||||
verbose = false
|
||||
streamName = "S"
|
||||
consumerPrefix = "C"
|
||||
concurrency = 12
|
||||
)
|
||||
|
||||
benchmarksCases := []struct {
|
||||
clusterSize int
|
||||
consumerReplicas int
|
||||
consumerStorage nats.StorageType
|
||||
}{
|
||||
{1, 1, nats.MemoryStorage},
|
||||
{3, 3, nats.MemoryStorage},
|
||||
{3, 3, nats.FileStorage},
|
||||
}
|
||||
|
||||
type ConsumerType string
|
||||
const (
|
||||
Ephemeral ConsumerType = "Ephemeral"
|
||||
Durable ConsumerType = "Durable"
|
||||
)
|
||||
|
||||
consumerTypeCases := []ConsumerType{
|
||||
Ephemeral,
|
||||
Durable,
|
||||
}
|
||||
|
||||
for _, bc := range benchmarksCases {
|
||||
|
||||
bName := fmt.Sprintf(
|
||||
"N=%d,R=%d,storage=%s,C=%d",
|
||||
bc.clusterSize,
|
||||
bc.consumerReplicas,
|
||||
bc.consumerStorage.String(),
|
||||
concurrency,
|
||||
)
|
||||
|
||||
b.Run(
|
||||
bName,
|
||||
func(b *testing.B) {
|
||||
|
||||
for _, ct := range consumerTypeCases {
|
||||
|
||||
cName := fmt.Sprintf("Consumer=%s", ct)
|
||||
|
||||
b.Run(
|
||||
cName,
|
||||
func(b *testing.B) {
|
||||
if verbose {
|
||||
b.Logf(
|
||||
"Creating %d consumers in cluster with %d nodes, R=%d, %s storage",
|
||||
b.N,
|
||||
bc.clusterSize,
|
||||
bc.consumerReplicas,
|
||||
bc.consumerStorage,
|
||||
)
|
||||
}
|
||||
|
||||
// Setup server or cluster
|
||||
_, leaderServer, shutdown, nc, js := startJSClusterAndConnect(b, bc.clusterSize)
|
||||
defer shutdown()
|
||||
defer nc.Close()
|
||||
|
||||
// All clients connect to cluster (meta) leader for lower variability
|
||||
connectURL := leaderServer.ClientURL()
|
||||
|
||||
// Create stream
|
||||
streamConfig := nats.StreamConfig{
|
||||
Name: streamName,
|
||||
Storage: nats.FileStorage,
|
||||
Replicas: bc.clusterSize,
|
||||
}
|
||||
|
||||
_, err := js.AddStream(&streamConfig)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to create stream: %s", err)
|
||||
}
|
||||
|
||||
// Wait for all clients and main routine to be ready
|
||||
wgReady := sync.WaitGroup{}
|
||||
wgReady.Add(concurrency + 1)
|
||||
// Wait for all routines to complete
|
||||
wgComplete := sync.WaitGroup{}
|
||||
wgComplete.Add(concurrency)
|
||||
|
||||
// Number of operations (divided amongst clients)
|
||||
opsLeft := atomic.Int64{}
|
||||
opsLeft.Store(int64(b.N))
|
||||
// Total number of errors
|
||||
totalErrors := atomic.Int64{}
|
||||
|
||||
// Pre-create connections and JS contexts
|
||||
for i := 1; i <= concurrency; i++ {
|
||||
nc, js := jsClientConnectURL(b, connectURL)
|
||||
defer nc.Close()
|
||||
|
||||
go func(clientId int, nc *nats.Conn, js nats.JetStreamContext) {
|
||||
defer wgComplete.Done()
|
||||
|
||||
// Config struct (reused and modified in place for each call)
|
||||
cfg := nats.ConsumerConfig{
|
||||
Durable: "",
|
||||
Name: "",
|
||||
Replicas: bc.consumerReplicas,
|
||||
MemoryStorage: bc.consumerStorage == nats.MemoryStorage,
|
||||
}
|
||||
|
||||
// Block until everyone is ready
|
||||
wgReady.Done()
|
||||
wgReady.Wait()
|
||||
|
||||
errCount := int64(0)
|
||||
opCount := 0
|
||||
for opsLeft.Add(-1) >= 0 {
|
||||
var err error
|
||||
// Set unique consumer name
|
||||
cfg.Name = fmt.Sprintf("%s_%d_%d", consumerPrefix, clientId, opCount)
|
||||
if ct == Durable {
|
||||
cfg.Durable = cfg.Name
|
||||
}
|
||||
_, err = js.AddConsumer(streamName, &cfg)
|
||||
if err != nil {
|
||||
b.Logf("Failed to add consumer: %s", err)
|
||||
errCount += 1
|
||||
}
|
||||
opCount += 1
|
||||
}
|
||||
|
||||
if verbose {
|
||||
b.Logf("Client %d completed %d operations", clientId, opCount)
|
||||
}
|
||||
|
||||
totalErrors.Add(errCount)
|
||||
|
||||
}(i, nc, js)
|
||||
}
|
||||
|
||||
// Wait for all clients to be ready
|
||||
wgReady.Done()
|
||||
wgReady.Wait()
|
||||
|
||||
// Start benchmark clock
|
||||
b.ResetTimer()
|
||||
|
||||
wgComplete.Wait()
|
||||
b.StopTimer()
|
||||
|
||||
b.ReportMetric(float64(100*(totalErrors.Load()))/float64(b.N), "%error")
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user