You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							480 lines
						
					
					
						
							13 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							480 lines
						
					
					
						
							13 KiB
						
					
					
				
								#!/bin/bash
							 | 
						|
								
							 | 
						|
								# Kafka Client Load Test Runner Script
							 | 
						|
								# This script helps run various load test scenarios against SeaweedFS Kafka Gateway
							 | 
						|
								
							 | 
						|
								set -euo pipefail
							 | 
						|
								
							 | 
						|
								# Default configuration
							 | 
						|
								SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
							 | 
						|
								PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
							 | 
						|
								DOCKER_COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
							 | 
						|
								CONFIG_FILE="$PROJECT_DIR/config/loadtest.yaml"
							 | 
						|
								
							 | 
						|
								# Default test parameters
							 | 
						|
								TEST_MODE="comprehensive"
							 | 
						|
								TEST_DURATION="300s"
							 | 
						|
								PRODUCER_COUNT=10
							 | 
						|
								CONSUMER_COUNT=5
							 | 
						|
								MESSAGE_RATE=1000
							 | 
						|
								MESSAGE_SIZE=1024
							 | 
						|
								TOPIC_COUNT=5
							 | 
						|
								PARTITIONS_PER_TOPIC=3
							 | 
						|
								
							 | 
						|
								# Colors for output
							 | 
						|
								RED='\033[0;31m'
							 | 
						|
								GREEN='\033[0;32m'
							 | 
						|
								YELLOW='\033[0;33m'
							 | 
						|
								BLUE='\033[0;34m'
							 | 
						|
								NC='\033[0m' # No Color
							 | 
						|
								
							 | 
						|
								# Function to print colored output
							 | 
						|
								log_info() {
							 | 
						|
								    echo -e "${BLUE}[INFO]${NC} $1"
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								log_success() {
							 | 
						|
								    echo -e "${GREEN}[SUCCESS]${NC} $1"
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								log_warning() {
							 | 
						|
								    echo -e "${YELLOW}[WARNING]${NC} $1"
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								log_error() {
							 | 
						|
								    echo -e "${RED}[ERROR]${NC} $1"
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Function to show usage
							 | 
						|
								show_usage() {
							 | 
						|
								    cat << EOF
							 | 
						|
								Kafka Client Load Test Runner
							 | 
						|
								
							 | 
						|
								Usage: $0 [OPTIONS] [COMMAND]
							 | 
						|
								
							 | 
						|
								Commands:
							 | 
						|
								  start               Start the load test infrastructure and run tests
							 | 
						|
								  stop                Stop all services
							 | 
						|
								  restart             Restart all services
							 | 
						|
								  status              Show service status
							 | 
						|
								  logs                Show logs from all services
							 | 
						|
								  clean               Clean up all resources (volumes, networks, etc.)
							 | 
						|
								  monitor             Start monitoring stack (Prometheus + Grafana)
							 | 
						|
								  scenarios           Run predefined test scenarios
							 | 
						|
								
							 | 
						|
								Options:
							 | 
						|
								  -m, --mode MODE           Test mode: producer, consumer, comprehensive (default: comprehensive)
							 | 
						|
								  -d, --duration DURATION   Test duration (default: 300s)
							 | 
						|
								  -p, --producers COUNT     Number of producers (default: 10)
							 | 
						|
								  -c, --consumers COUNT     Number of consumers (default: 5)
							 | 
						|
								  -r, --rate RATE          Messages per second per producer (default: 1000)
							 | 
						|
								  -s, --size SIZE          Message size in bytes (default: 1024)
							 | 
						|
								  -t, --topics COUNT       Number of topics (default: 5)
							 | 
						|
								  --partitions COUNT       Partitions per topic (default: 3)
							 | 
						|
								  --config FILE           Configuration file (default: config/loadtest.yaml)
							 | 
						|
								  --monitoring            Enable monitoring stack
							 | 
						|
								  --wait-ready            Wait for services to be ready before starting tests
							 | 
						|
								  -v, --verbose           Verbose output
							 | 
						|
								  -h, --help              Show this help message
							 | 
						|
								
							 | 
						|
								Examples:
							 | 
						|
								  # Run comprehensive test for 5 minutes
							 | 
						|
								  $0 start -m comprehensive -d 5m
							 | 
						|
								
							 | 
						|
								  # Run producer-only test with high throughput
							 | 
						|
								  $0 start -m producer -p 20 -r 2000 -d 10m
							 | 
						|
								
							 | 
						|
								  # Run consumer-only test
							 | 
						|
								  $0 start -m consumer -c 10
							 | 
						|
								
							 | 
						|
								  # Run with monitoring
							 | 
						|
								  $0 start --monitoring -d 15m
							 | 
						|
								
							 | 
						|
								  # Clean up everything
							 | 
						|
								  $0 clean
							 | 
						|
								
							 | 
						|
								Predefined Scenarios:
							 | 
						|
								  quick              Quick smoke test (1 min, low load)
							 | 
						|
								  standard           Standard load test (5 min, medium load) 
							 | 
						|
								  stress             Stress test (10 min, high load)
							 | 
						|
								  endurance          Endurance test (30 min, sustained load)
							 | 
						|
								  burst              Burst test (variable load)
							 | 
						|
								
							 | 
						|
								EOF
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Parse command line arguments
							 | 
						|
								parse_args() {
							 | 
						|
								    while [[ $# -gt 0 ]]; do
							 | 
						|
								        case $1 in
							 | 
						|
								            -m|--mode)
							 | 
						|
								                TEST_MODE="$2"
							 | 
						|
								                shift 2
							 | 
						|
								                ;;
							 | 
						|
								            -d|--duration)
							 | 
						|
								                TEST_DURATION="$2"
							 | 
						|
								                shift 2
							 | 
						|
								                ;;
							 | 
						|
								            -p|--producers)
							 | 
						|
								                PRODUCER_COUNT="$2"
							 | 
						|
								                shift 2
							 | 
						|
								                ;;
							 | 
						|
								            -c|--consumers)
							 | 
						|
								                CONSUMER_COUNT="$2"
							 | 
						|
								                shift 2
							 | 
						|
								                ;;
							 | 
						|
								            -r|--rate)
							 | 
						|
								                MESSAGE_RATE="$2"
							 | 
						|
								                shift 2
							 | 
						|
								                ;;
							 | 
						|
								            -s|--size)
							 | 
						|
								                MESSAGE_SIZE="$2"
							 | 
						|
								                shift 2
							 | 
						|
								                ;;
							 | 
						|
								            -t|--topics)
							 | 
						|
								                TOPIC_COUNT="$2"
							 | 
						|
								                shift 2
							 | 
						|
								                ;;
							 | 
						|
								            --partitions)
							 | 
						|
								                PARTITIONS_PER_TOPIC="$2"
							 | 
						|
								                shift 2
							 | 
						|
								                ;;
							 | 
						|
								            --config)
							 | 
						|
								                CONFIG_FILE="$2"
							 | 
						|
								                shift 2
							 | 
						|
								                ;;
							 | 
						|
								            --monitoring)
							 | 
						|
								                ENABLE_MONITORING=1
							 | 
						|
								                shift
							 | 
						|
								                ;;
							 | 
						|
								            --wait-ready)
							 | 
						|
								                WAIT_READY=1
							 | 
						|
								                shift
							 | 
						|
								                ;;
							 | 
						|
								            -v|--verbose)
							 | 
						|
								                VERBOSE=1
							 | 
						|
								                shift
							 | 
						|
								                ;;
							 | 
						|
								            -h|--help)
							 | 
						|
								                show_usage
							 | 
						|
								                exit 0
							 | 
						|
								                ;;
							 | 
						|
								            -*)
							 | 
						|
								                log_error "Unknown option: $1"
							 | 
						|
								                show_usage
							 | 
						|
								                exit 1
							 | 
						|
								                ;;
							 | 
						|
								            *)
							 | 
						|
								                if [[ -z "${COMMAND:-}" ]]; then
							 | 
						|
								                    COMMAND="$1"
							 | 
						|
								                else
							 | 
						|
								                    log_error "Multiple commands specified"
							 | 
						|
								                    show_usage
							 | 
						|
								                    exit 1
							 | 
						|
								                fi
							 | 
						|
								                shift
							 | 
						|
								                ;;
							 | 
						|
								        esac
							 | 
						|
								    done
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Check if Docker and Docker Compose are available
							 | 
						|
								check_dependencies() {
							 | 
						|
								    if ! command -v docker &> /dev/null; then
							 | 
						|
								        log_error "Docker is not installed or not in PATH"
							 | 
						|
								        exit 1
							 | 
						|
								    fi
							 | 
						|
								    
							 | 
						|
								    if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
							 | 
						|
								        log_error "Docker Compose is not installed or not in PATH"
							 | 
						|
								        exit 1
							 | 
						|
								    fi
							 | 
						|
								    
							 | 
						|
								    # Use docker compose if available, otherwise docker-compose
							 | 
						|
								    if docker compose version &> /dev/null; then
							 | 
						|
								        DOCKER_COMPOSE="docker compose"
							 | 
						|
								    else
							 | 
						|
								        DOCKER_COMPOSE="docker-compose"
							 | 
						|
								    fi
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Wait for services to be ready
							 | 
						|
								wait_for_services() {
							 | 
						|
								    log_info "Waiting for services to be ready..."
							 | 
						|
								    
							 | 
						|
								    local timeout=300  # 5 minutes timeout
							 | 
						|
								    local elapsed=0
							 | 
						|
								    local check_interval=5
							 | 
						|
								    
							 | 
						|
								    while [[ $elapsed -lt $timeout ]]; do
							 | 
						|
								        if $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" ps --format table | grep -q "healthy"; then
							 | 
						|
								            if check_service_health; then
							 | 
						|
								                log_success "All services are ready!"
							 | 
						|
								                return 0
							 | 
						|
								            fi
							 | 
						|
								        fi
							 | 
						|
								        
							 | 
						|
								        sleep $check_interval
							 | 
						|
								        elapsed=$((elapsed + check_interval))
							 | 
						|
								        log_info "Waiting... ($elapsed/${timeout}s)"
							 | 
						|
								    done
							 | 
						|
								    
							 | 
						|
								    log_error "Services did not become ready within $timeout seconds"
							 | 
						|
								    return 1
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Check health of critical services
							 | 
						|
								check_service_health() {
							 | 
						|
								    # Check Kafka Gateway
							 | 
						|
								    if ! curl -s http://localhost:9093 >/dev/null 2>&1; then
							 | 
						|
								        return 1
							 | 
						|
								    fi
							 | 
						|
								    
							 | 
						|
								    # Check Schema Registry
							 | 
						|
								    if ! curl -s http://localhost:8081/subjects >/dev/null 2>&1; then
							 | 
						|
								        return 1
							 | 
						|
								    fi
							 | 
						|
								    
							 | 
						|
								    return 0
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Start the load test infrastructure
							 | 
						|
								start_services() {
							 | 
						|
								    log_info "Starting SeaweedFS Kafka load test infrastructure..."
							 | 
						|
								    
							 | 
						|
								    # Set environment variables
							 | 
						|
								    export TEST_MODE="$TEST_MODE"
							 | 
						|
								    export TEST_DURATION="$TEST_DURATION"
							 | 
						|
								    export PRODUCER_COUNT="$PRODUCER_COUNT"
							 | 
						|
								    export CONSUMER_COUNT="$CONSUMER_COUNT"
							 | 
						|
								    export MESSAGE_RATE="$MESSAGE_RATE"
							 | 
						|
								    export MESSAGE_SIZE="$MESSAGE_SIZE"
							 | 
						|
								    export TOPIC_COUNT="$TOPIC_COUNT"
							 | 
						|
								    export PARTITIONS_PER_TOPIC="$PARTITIONS_PER_TOPIC"
							 | 
						|
								    
							 | 
						|
								    # Start core services
							 | 
						|
								    $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" up -d \
							 | 
						|
								        seaweedfs-master \
							 | 
						|
								        seaweedfs-volume \
							 | 
						|
								        seaweedfs-filer \
							 | 
						|
								        seaweedfs-mq-broker \
							 | 
						|
								        kafka-gateway \
							 | 
						|
								        schema-registry
							 | 
						|
								    
							 | 
						|
								    # Start monitoring if enabled
							 | 
						|
								    if [[ "${ENABLE_MONITORING:-0}" == "1" ]]; then
							 | 
						|
								        log_info "Starting monitoring stack..."
							 | 
						|
								        $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" --profile monitoring up -d
							 | 
						|
								    fi
							 | 
						|
								    
							 | 
						|
								    # Wait for services to be ready if requested
							 | 
						|
								    if [[ "${WAIT_READY:-0}" == "1" ]]; then
							 | 
						|
								        wait_for_services
							 | 
						|
								    fi
							 | 
						|
								    
							 | 
						|
								    log_success "Infrastructure started successfully"
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Run the load test
							 | 
						|
								run_loadtest() {
							 | 
						|
								    log_info "Starting Kafka client load test..."
							 | 
						|
								    log_info "Mode: $TEST_MODE, Duration: $TEST_DURATION"
							 | 
						|
								    log_info "Producers: $PRODUCER_COUNT, Consumers: $CONSUMER_COUNT"
							 | 
						|
								    log_info "Message Rate: $MESSAGE_RATE msgs/sec, Size: $MESSAGE_SIZE bytes"
							 | 
						|
								    
							 | 
						|
								    # Run the load test
							 | 
						|
								    $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" --profile loadtest up --abort-on-container-exit kafka-client-loadtest
							 | 
						|
								    
							 | 
						|
								    # Show test results
							 | 
						|
								    show_results
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Show test results
							 | 
						|
								show_results() {
							 | 
						|
								    log_info "Load test completed! Gathering results..."
							 | 
						|
								    
							 | 
						|
								    # Get final metrics from the load test container
							 | 
						|
								    if $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" ps kafka-client-loadtest-runner &>/dev/null; then
							 | 
						|
								        log_info "Final test statistics:"
							 | 
						|
								        $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" exec -T kafka-client-loadtest-runner curl -s http://localhost:8080/stats || true
							 | 
						|
								    fi
							 | 
						|
								    
							 | 
						|
								    # Show Prometheus metrics if monitoring is enabled
							 | 
						|
								    if [[ "${ENABLE_MONITORING:-0}" == "1" ]]; then
							 | 
						|
								        log_info "Monitoring dashboards available at:"
							 | 
						|
								        log_info "  Prometheus: http://localhost:9090"
							 | 
						|
								        log_info "  Grafana:    http://localhost:3000 (admin/admin)"
							 | 
						|
								    fi
							 | 
						|
								    
							 | 
						|
								    # Show where results are stored
							 | 
						|
								    if [[ -d "$PROJECT_DIR/test-results" ]]; then
							 | 
						|
								        log_info "Test results saved to: $PROJECT_DIR/test-results/"
							 | 
						|
								    fi
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Stop services
							 | 
						|
								stop_services() {
							 | 
						|
								    log_info "Stopping all services..."
							 | 
						|
								    $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" --profile loadtest --profile monitoring down
							 | 
						|
								    log_success "Services stopped"
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Show service status
							 | 
						|
								show_status() {
							 | 
						|
								    log_info "Service status:"
							 | 
						|
								    $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" ps
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Show logs
							 | 
						|
								show_logs() {
							 | 
						|
								    $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" logs -f "${1:-}"
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Clean up all resources
							 | 
						|
								clean_all() {
							 | 
						|
								    log_warning "This will remove all volumes, networks, and containers. Are you sure? (y/N)"
							 | 
						|
								    read -r response
							 | 
						|
								    if [[ "$response" =~ ^[Yy]$ ]]; then
							 | 
						|
								        log_info "Cleaning up all resources..."
							 | 
						|
								        $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" --profile loadtest --profile monitoring down -v --remove-orphans
							 | 
						|
								        
							 | 
						|
								        # Remove any remaining volumes
							 | 
						|
								        docker volume ls -q | grep -E "(kafka-client-loadtest|seaweedfs)" | xargs -r docker volume rm
							 | 
						|
								        
							 | 
						|
								        # Remove networks
							 | 
						|
								        docker network ls -q | grep -E "kafka-client-loadtest" | xargs -r docker network rm
							 | 
						|
								        
							 | 
						|
								        log_success "Cleanup completed"
							 | 
						|
								    else
							 | 
						|
								        log_info "Cleanup cancelled"
							 | 
						|
								    fi
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Run predefined scenarios
							 | 
						|
								run_scenario() {
							 | 
						|
								    local scenario="$1"
							 | 
						|
								    
							 | 
						|
								    case "$scenario" in
							 | 
						|
								        quick)
							 | 
						|
								            TEST_MODE="comprehensive"
							 | 
						|
								            TEST_DURATION="1m"
							 | 
						|
								            PRODUCER_COUNT=2
							 | 
						|
								            CONSUMER_COUNT=2
							 | 
						|
								            MESSAGE_RATE=100
							 | 
						|
								            MESSAGE_SIZE=512
							 | 
						|
								            TOPIC_COUNT=2
							 | 
						|
								            ;;
							 | 
						|
								        standard)
							 | 
						|
								            TEST_MODE="comprehensive"
							 | 
						|
								            TEST_DURATION="5m"
							 | 
						|
								            PRODUCER_COUNT=5
							 | 
						|
								            CONSUMER_COUNT=3
							 | 
						|
								            MESSAGE_RATE=500
							 | 
						|
								            MESSAGE_SIZE=1024
							 | 
						|
								            TOPIC_COUNT=3
							 | 
						|
								            ;;
							 | 
						|
								        stress)
							 | 
						|
								            TEST_MODE="comprehensive"
							 | 
						|
								            TEST_DURATION="10m"
							 | 
						|
								            PRODUCER_COUNT=20
							 | 
						|
								            CONSUMER_COUNT=10
							 | 
						|
								            MESSAGE_RATE=2000
							 | 
						|
								            MESSAGE_SIZE=2048
							 | 
						|
								            TOPIC_COUNT=10
							 | 
						|
								            ;;
							 | 
						|
								        endurance)
							 | 
						|
								            TEST_MODE="comprehensive"
							 | 
						|
								            TEST_DURATION="30m"
							 | 
						|
								            PRODUCER_COUNT=10
							 | 
						|
								            CONSUMER_COUNT=5
							 | 
						|
								            MESSAGE_RATE=1000
							 | 
						|
								            MESSAGE_SIZE=1024
							 | 
						|
								            TOPIC_COUNT=5
							 | 
						|
								            ;;
							 | 
						|
								        burst)
							 | 
						|
								            TEST_MODE="comprehensive"
							 | 
						|
								            TEST_DURATION="10m"
							 | 
						|
								            PRODUCER_COUNT=10
							 | 
						|
								            CONSUMER_COUNT=5
							 | 
						|
								            MESSAGE_RATE=1000
							 | 
						|
								            MESSAGE_SIZE=1024
							 | 
						|
								            TOPIC_COUNT=5
							 | 
						|
								            # Note: Burst behavior would be configured in the load test config
							 | 
						|
								            ;;
							 | 
						|
								        *)
							 | 
						|
								            log_error "Unknown scenario: $scenario"
							 | 
						|
								            log_info "Available scenarios: quick, standard, stress, endurance, burst"
							 | 
						|
								            exit 1
							 | 
						|
								            ;;
							 | 
						|
								    esac
							 | 
						|
								    
							 | 
						|
								    log_info "Running $scenario scenario..."
							 | 
						|
								    start_services
							 | 
						|
								    if [[ "${WAIT_READY:-0}" == "1" ]]; then
							 | 
						|
								        wait_for_services
							 | 
						|
								    fi
							 | 
						|
								    run_loadtest
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Main execution
							 | 
						|
								main() {
							 | 
						|
								    if [[ $# -eq 0 ]]; then
							 | 
						|
								        show_usage
							 | 
						|
								        exit 0
							 | 
						|
								    fi
							 | 
						|
								    
							 | 
						|
								    parse_args "$@"
							 | 
						|
								    check_dependencies
							 | 
						|
								    
							 | 
						|
								    case "${COMMAND:-}" in
							 | 
						|
								        start)
							 | 
						|
								            start_services
							 | 
						|
								            run_loadtest
							 | 
						|
								            ;;
							 | 
						|
								        stop)
							 | 
						|
								            stop_services
							 | 
						|
								            ;;
							 | 
						|
								        restart)
							 | 
						|
								            stop_services
							 | 
						|
								            start_services
							 | 
						|
								            ;;
							 | 
						|
								        status)
							 | 
						|
								            show_status
							 | 
						|
								            ;;
							 | 
						|
								        logs)
							 | 
						|
								            show_logs
							 | 
						|
								            ;;
							 | 
						|
								        clean)
							 | 
						|
								            clean_all
							 | 
						|
								            ;;
							 | 
						|
								        monitor)
							 | 
						|
								            ENABLE_MONITORING=1
							 | 
						|
								            $DOCKER_COMPOSE -f "$DOCKER_COMPOSE_FILE" --profile monitoring up -d
							 | 
						|
								            log_success "Monitoring stack started"
							 | 
						|
								            log_info "Prometheus: http://localhost:9090"
							 | 
						|
								            log_info "Grafana:    http://localhost:3000 (admin/admin)"
							 | 
						|
								            ;;
							 | 
						|
								        scenarios)
							 | 
						|
								            if [[ -n "${2:-}" ]]; then
							 | 
						|
								                run_scenario "$2"
							 | 
						|
								            else
							 | 
						|
								                log_error "Please specify a scenario"
							 | 
						|
								                log_info "Available scenarios: quick, standard, stress, endurance, burst"
							 | 
						|
								                exit 1
							 | 
						|
								            fi
							 | 
						|
								            ;;
							 | 
						|
								        *)
							 | 
						|
								            log_error "Unknown command: ${COMMAND:-}"
							 | 
						|
								            show_usage
							 | 
						|
								            exit 1
							 | 
						|
								            ;;
							 | 
						|
								    esac
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								# Set default values
							 | 
						|
								ENABLE_MONITORING=0
							 | 
						|
								WAIT_READY=0
							 | 
						|
								VERBOSE=0
							 | 
						|
								
							 | 
						|
								# Run main function
							 | 
						|
								main "$@"
							 |