Best Practices
This guide covers production deployment recommendations for receiving ShredStream.com data reliably at scale. Following these practices will minimize packet loss, reduce latency, and ensure your shred processing pipeline stays healthy.
UDP Buffer Sizing
The single most common source of shred loss is an undersized kernel receive buffer. When shreds arrive faster than your application reads them, the kernel drops packets silently. Set your receive buffer to at least 25 MB:
# Set at runtimesudo sysctl -w net.core.rmem_max=26214400sudo sysctl -w net.core.rmem_default=26214400# Persist across reboots - add to /etc/sysctl.confnet.core.rmem_max=26214400net.core.rmem_default=26214400# Verifysysctl net.core.rmem_max
Note on Linux buffer doubling
Linux internally doubles the value you pass to SO_RCVBUF (half is reserved for kernel bookkeeping). If you request 25 MB, getsockopt may report ~50 MB. This is expected.
Monitoring Your Stream
Track key metrics to detect degradation early. The most important things to monitor are:
- Shred rate — Expected: 500-5,000 shreds/sec depending on network load
- Kernel drops — Nonzero drops mean your buffer or processing is too slow
- Slot gap — Compare the latest slot in your stream vs. a Solana RPC to measure freshness
- Process CPU/memory — Ensure your listener is not saturating resources
Monitor kernel-level UDP drops on Linux by reading /proc/net/udp or using ss:
# Show UDP socket statistics including dropsss -u -a -n | head -20# Monitor drops over time for a specific portwatch -n 1 'cat /proc/net/udp | grep 1F41' # 1F41 = hex for port 8001# netstat summary - look for "packet receive errors"netstat -su
Here is an example monitoring loop that logs throughput and checks for slot gaps:
import socketimport structimport timesock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 26_214_400)sock.bind(("0.0.0.0", 8001))count = 0last_slot = 0last_report = time.monotonic()while True:data, _ = sock.recvfrom(1280)count += 1# Parse slot from shred header (bytes 65-73, little-endian u64)if len(data) >= 73:slot = struct.unpack_from("<Q", data, 65)[0]if slot > last_slot:last_slot = slotnow = time.monotonic()if now - last_report >= 10.0:rate = count / (now - last_report)print(f"[monitor] {rate:.0f} shreds/sec | latest slot: {last_slot}")count = 0last_report = now
Redundancy and Failover
For mission-critical deployments (e.g., MEV bots, liquidation engines), run redundant streams:
- Multi-region streams — Activate streams in two or more regions and deduplicate by shred signature. The first copy to arrive wins.
- Long-term commitments — Use the duration multiplier to lock in longer subscriptions (up to 24 months) at discounted rates. Combine with multi-region for maximum reliability and savings.
- Hot standby servers — Maintain a second server with the same listener. If the primary goes down, update the IP via the API.
- IP failover script — Automate IP switching when your monitoring detects packet loss above a threshold.
import requestsimport timeAPI_KEY = "ss_live_abc123..."BASE_URL = "https://api.shredstream.com/v1"HEADERS = {"Authorization": f"Bearer {API_KEY}"}PRIMARY_IP = "203.0.113.42"FAILOVER_IP = "198.51.100.10"PORT = 8001STREAM_ID = Nonedef activate(ip: str) -> str:resp = requests.post(f"{BASE_URL}/activate",headers=HEADERS,json={"ip": ip, "port": PORT, "region": "us-east"},)resp.raise_for_status()return resp.json()["stream_id"]def deactivate(stream_id: str):requests.post(f"{BASE_URL}/deactivate",headers=HEADERS,json={"stream_id": stream_id},)def check_health(stream_id: str) -> float:resp = requests.get(f"{BASE_URL}/status",headers=HEADERS,params={"stream_id": stream_id},)metrics = resp.json()["streams"][0]["metrics"]return metrics["packet_loss_pct"]# Main failover loopSTREAM_ID = activate(PRIMARY_IP)current_ip = PRIMARY_IPwhile True:time.sleep(30)loss = check_health(STREAM_ID)if loss > 1.0: # More than 1% packet lossfailover_ip = FAILOVER_IP if current_ip == PRIMARY_IP else PRIMARY_IPprint(f"High loss ({loss}%), switching to {failover_ip}")deactivate(STREAM_ID)STREAM_ID = activate(failover_ip)current_ip = failover_ip
Error Handling
Your UDP listener should be resilient to malformed or truncated packets. Because UDP is connectionless, you will occasionally receive packets that are not valid shreds (e.g., port scanners, stale routes). Always validate before processing:
import socketimport structSHRED_MIN_SIZE = 88 # Minimum valid shred (header only)SHRED_MAX_SIZE = 1280 # Maximum shred packet sizesock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 26_214_400)sock.bind(("0.0.0.0", 8001))while True:data, addr = sock.recvfrom(2048) # Read extra to detect oversized# Validate packet sizeif len(data) < SHRED_MIN_SIZE or len(data) > SHRED_MAX_SIZE:continue # Skip invalid packets# Validate shred variant byte (offset 64)variant = data[64]# Data shreds: variant & 0xF0 == 0xa0# Coding shreds: variant & 0xF0 == 0x50if variant & 0xF0 not in (0xa0, 0x50):continue # Not a valid shred type# Parse slot (offset 65, 8 bytes LE)slot = struct.unpack_from("<Q", data, 65)[0]# Process the validated shredprocess_shred(slot, data)
Reconnection Strategies
Unlike TCP, UDP does not have a "connection" to lose. However, your stream can stop delivering if your subscription expires, your IP changes, or infrastructure maintenance occurs. Implement these strategies:
1. Idle Timeout Detection
If no packets arrive for 30 seconds during normal Solana operation, something is wrong. Use a timeout on your receive call to detect this:
import socketsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 26_214_400)sock.settimeout(30.0) # 30-second timeoutsock.bind(("0.0.0.0", 8001))while True:try:data, addr = sock.recvfrom(1280)process_shred(data)except socket.timeout:print("WARNING: No shreds received for 30s, checking stream status...")# Call GET /status to verify stream is active# Re-activate if needed
2. Periodic Health Checks
Run a background thread that polls the GET /status endpoint every 60 seconds. If the stream status changes from active to expired, trigger your renewal or alerting workflow.
3. Exponential Backoff for Re-activation
When re-activating a stream after an error, use exponential backoff to avoid hammering the API:
import timeimport requestsdef activate_with_backoff(ip, port, region, api_key, max_retries=5):delay = 1.0for attempt in range(max_retries):try:resp = requests.post("https://api.shredstream.com/v1/activate",headers={"Authorization": f"Bearer {api_key}"},json={"ip": ip, "port": port, "region": region},timeout=10,)resp.raise_for_status()return resp.json()except requests.RequestException as e:print(f"Attempt {attempt + 1} failed: {e}")if attempt < max_retries - 1:time.sleep(delay)delay = min(delay * 2, 60) # Cap at 60 secondsraise RuntimeError("Failed to activate stream after max retries")
Performance Tips
- Pin your receiver to a CPU core. On Linux, use
tasksetorisolcpusto prevent the scheduler from migrating your process. - Use a dedicated NIC queue. With RSS (Receive Side Scaling), direct all traffic on your shred port to a single queue for cache locality.
- Avoid allocations in the hot path. Pre-allocate buffers and reuse them. In Rust, this means using a fixed
[u8; 1280]buffer, not aVec. - Separate receive and processing. Use a ring buffer or channel between the receive thread and processing threads to decouple packet ingestion from business logic.
- Consider recvmmsg (Linux). Read multiple packets in a single system call to reduce syscall overhead under high throughput.
use std::net::UdpSocket;use std::sync::mpsc;use std::thread;fn main() -> std::io::Result<()> {let socket = UdpSocket::bind("0.0.0.0:8001")?;socket.set_recv_buffer_size(26_214_400)?;// Channel to decouple receive from processinglet (tx, rx) = mpsc::sync_channel::<Vec<u8>>(10_000);// Receiver thread - hot path, minimal allocationslet recv_handle = thread::spawn(move || {let mut buf = [0u8; 1280];loop {if let Ok((len, _)) = socket.recv_from(&mut buf) {let _ = tx.send(buf[..len].to_vec());}}});// Processing thread - can do heavier work herelet proc_handle = thread::spawn(move || {let mut count: u64 = 0;while let Ok(shred) = rx.recv() {count += 1;// Parse and process shred dataif count % 10_000 == 0 {println!("Processed {} shreds", count);}}});recv_handle.join().unwrap();proc_handle.join().unwrap();Ok(())}