Runtime Modes
Pulsar Functions can run in three different modes:Thread Mode
Functions run as threads within the Function Worker process. Characteristics:- Lowest overhead and fastest startup
- Shared JVM with Function Worker
- No isolation between functions
- Best for lightweight, trusted functions
- Development and testing
- Simple transformations
- Low-latency requirements
Process Mode
Functions run as separate processes on the same host. Characteristics:- Process-level isolation
- Better resource control
- Independent failure domains
- Moderate overhead
- Production deployments
- Functions requiring isolation
- Multi-language support
Kubernetes Mode
Functions run as Kubernetes pods. Characteristics:- Full container isolation
- Kubernetes resource management
- Auto-scaling support
- Cloud-native deployment
- Large-scale production deployments
- Multi-tenant environments
- Functions requiring specific container images
- Integration with Kubernetes ecosystem
Resource Configuration
CPU Allocation
Specify CPU resources in cores:- Translates to Kubernetes CPU requests
- Can specify limits separately in function worker config
Memory Allocation
Specify RAM in bytes:- Include overhead for runtime and libraries
- Monitor actual usage and adjust
- Set appropriate JVM heap size for Java functions
Disk Allocation
Specify disk space in bytes:- Function package and dependencies
- Local state storage (if enabled)
- Temporary files
Complete Resource Configuration
function-config.yaml
Parallelism and Scaling
Instance Parallelism
Run multiple instances for horizontal scaling:- Each instance processes a subset of input partitions
- Load balanced automatically by Pulsar
- Instances can run on different workers
- Start with parallelism = number of input topic partitions
- Increase if instances are CPU-bound
- Monitor per-instance throughput
Dynamic Scaling
Update parallelism without redeployment:Subscription Configuration
Subscription Type
Control how messages are distributed across function instances:- SHARED (default): Messages distributed round-robin across instances
- FAILOVER: Only one instance receives messages; others are standby
- KEY_SHARED: Messages with same key go to same instance
Subscription Position
Set where to start consuming:Processing Guarantees
At-Most-Once
Fastest processing, no retries:- Message acknowledged immediately before processing
- No redelivery on failure
- Lowest latency
At-Least-Once
Default mode with automatic retries:- Message acknowledged after successful processing
- Automatic retries on failure
- Requires idempotent function logic
Effectively-Once
Exactly-once semantics using state:- Message processing and state updates are atomic
- Highest consistency guarantees
- Higher latency due to coordination
- Function must use Pulsar state storage
- State updates committed with message acknowledgment
Timeout Configuration
Message Timeout
Set maximum processing time per message:- Message is considered failed
- Retried based on retry configuration
Retry Configuration
Configure retry behavior:function-config.yaml
State Storage Configuration
Enable State Storage
Configure state backend:stateful-config.yaml
State Storage Options
BookKeeper (default):- Integrated with Pulsar cluster
- High performance, low latency
- Automatic replication
- Connect to external databases
- Use for shared state across functions
- Custom implementation via StateStore interface
Custom Runtime Options
JVM Options (Java)
Configure JVM for Java functions:java-function-config.yaml
Environment Variables
Set environment variables for function runtime:Kubernetes-Specific Configuration
Custom Container Image
Use custom Docker image:Service Account
Specify Kubernetes service account:k8s-function-config.yaml
Monitoring and Debugging
Enable Debug Logging
Profiling Functions
For Java functions, enable profiling:profiling-config.yaml
Best Practices
Choose the Right Runtime
Use Thread mode for development, Process mode for production, and Kubernetes mode for large-scale or multi-tenant deployments.
Right-Size Resources
Monitor actual resource usage and adjust CPU/RAM allocations. Over-provisioning wastes resources; under-provisioning causes failures.
Match Parallelism to Load
Start with parallelism equal to the number of input partitions. Increase based on per-instance CPU utilization.
Configure Appropriate Guarantees
Use EFFECTIVELY_ONCE only when necessary. ATLEAST_ONCE with idempotent logic is often sufficient and more performant.
Set Reasonable Timeouts
Set timeouts based on expected processing time plus buffer. Monitor timeout-related failures.
Performance Tuning
Optimize Throughput
Troubleshooting
OOM Errors
Symptoms: Function instances crash frequently Solutions:- Increase
--ramallocation - Optimize function memory usage
- Check for memory leaks
High Latency
Symptoms: Messages processed slowly Solutions:- Increase
--parallelism - Use THREAD or PROCESS runtime instead of KUBERNETES
- Optimize function code
- Use async operations
Function Won’t Scale
Symptoms: Adding instances doesn’t increase throughput Solutions:- Increase input topic partitions
- Check for bottlenecks in function code
- Verify resource availability on workers
Next Steps
Function Development
Learn advanced development patterns
Deployment Guide
Explore deployment options