Multi-CDN Setup
Lunar Stream provides multiple CDN endpoints for redundancy and optimal performance.
Multi-CDN Architecture
CDN Failover Flow
Available CDN Endpoints
Each livestream has multiple HLS URLs from different CDN providers:
| CDN | URL Pattern | Region |
|---|---|---|
| Origin | https://stream.lunarstream.kozow.com/live/{streamKey}/hls.m3u8 | Primary |
| BunnyCDN | https://zlmediakit-cdn.b-cdn.net/live/{streamKey}/hls.m3u8 | Global |
| Gcore | https://gcore-zlmediakit.lunarstream.kozow.com/live/{streamKey}/hls.m3u8 | Global |
Getting CDN URLs
When you retrieve a livestream, the response includes all available CDN URLs:
bash
curl -X GET "https://api.lunarstream.kozow.com/api/v1/livestream/LIVESTREAM_ID?projectId=PROJECT_ID" \
-H "ls-api-key: YOUR_API_KEY"Response:
json
{
"data": {
"id": "d926da37-56ae-4212-83bc-f20d9de64d6b",
"streamKey": "ee04affe2a669854052102fe762bd715",
"hlsPaths": [
"https://stream.lunarstream.kozow.com/live/ee04affe2a669854052102fe762bd715/hls.m3u8",
"https://zlmediakit-cdn.b-cdn.net/live/ee04affe2a669854052102fe762bd715/hls.m3u8",
"https://gcore-zlmediakit.lunarstream.kozow.com/live/ee04affe2a669854052102fe762bd715/hls.m3u8"
]
}
}Implementing CDN Failover
JavaScript Implementation
javascript
class MultiCDNPlayer {
constructor(hlsPaths) {
this.cdnUrls = hlsPaths;
this.currentIndex = 0;
this.maxRetries = 3;
}
getCurrentUrl() {
return this.cdnUrls[this.currentIndex];
}
switchToNextCDN() {
if (this.currentIndex < this.cdnUrls.length - 1) {
this.currentIndex++;
console.log(`Switching to CDN: ${this.getCurrentUrl()}`);
return true;
}
return false;
}
reset() {
this.currentIndex = 0;
}
}
// Usage with Video.js
const cdnPlayer = new MultiCDNPlayer(hlsPaths);
const player = videojs('video-player');
player.src({ src: cdnPlayer.getCurrentUrl(), type: 'application/x-mpegURL' });
player.on('error', () => {
if (cdnPlayer.switchToNextCDN()) {
player.src({ src: cdnPlayer.getCurrentUrl(), type: 'application/x-mpegURL' });
player.play();
} else {
console.error('All CDNs failed');
}
});React Hook Implementation
javascript
import { useState, useCallback } from 'react';
function useMultiCDN(hlsPaths) {
const [currentIndex, setCurrentIndex] = useState(0);
const currentUrl = hlsPaths[currentIndex];
const hasMoreCDNs = currentIndex < hlsPaths.length - 1;
const switchToNextCDN = useCallback(() => {
if (hasMoreCDNs) {
setCurrentIndex(prev => prev + 1);
return true;
}
return false;
}, [hasMoreCDNs]);
const reset = useCallback(() => {
setCurrentIndex(0);
}, []);
return { currentUrl, switchToNextCDN, reset, hasMoreCDNs };
}
// Usage
const StreamPlayer = ({ hlsPaths }) => {
const { currentUrl, switchToNextCDN } = useMultiCDN(hlsPaths);
const handleError = () => {
if (!switchToNextCDN()) {
console.error('All CDNs failed');
}
};
return (
<video src={currentUrl} onError={handleError} controls />
);
};Best Practices
1. CDN Selection Strategy
javascript
// Prioritize CDNs based on user location or performance
function selectOptimalCDN(hlsPaths, userRegion) {
const cdnPriority = {
'asia': ['gcore', 'bunny', 'origin'],
'europe': ['bunny', 'gcore', 'origin'],
'default': ['origin', 'bunny', 'gcore']
};
const priority = cdnPriority[userRegion] || cdnPriority['default'];
return hlsPaths.sort((a, b) => {
const aIndex = priority.findIndex(cdn => a.includes(cdn));
const bIndex = priority.findIndex(cdn => b.includes(cdn));
return aIndex - bIndex;
});
}2. Health Checking
javascript
async function checkCDNHealth(url) {
try {
const response = await fetch(url, { method: 'HEAD' });
return response.ok;
} catch {
return false;
}
}
async function findHealthyCDN(hlsPaths) {
for (const url of hlsPaths) {
if (await checkCDNHealth(url)) {
return url;
}
}
return null;
}3. Performance Monitoring
Track CDN performance to optimize future selections:
javascript
function trackCDNPerformance(cdnUrl, loadTime, errors) {
// Send to your analytics
analytics.track('cdn_performance', {
cdn: new URL(cdnUrl).hostname,
loadTime,
errors
});
}