├── results ├── requirements.txt ├── Dockerfile ├── benchmark-plot.py └── vts-plot.py ├── .luacheckrc ├── fonts └── OpenSans-Bold.ttf ├── images └── architecture.png ├── healthchecker ├── go.mod ├── Dockerfile ├── go.sum └── healthchecker.go ├── origin ├── samples │ ├── hls │ │ ├── signal-1 │ │ │ ├── 0.ts │ │ │ ├── 1.ts │ │ │ ├── 2.ts │ │ │ ├── 3.ts │ │ │ └── index.m3u8 │ │ ├── signal-10 │ │ │ ├── 0.ts │ │ │ ├── 1.ts │ │ │ ├── 2.ts │ │ │ ├── 3.ts │ │ │ └── index.m3u8 │ │ ├── signal-2 │ │ │ ├── 0.ts │ │ │ ├── 1.ts │ │ │ ├── 2.ts │ │ │ ├── 3.ts │ │ │ └── index.m3u8 │ │ ├── signal-3 │ │ │ ├── 0.ts │ │ │ ├── 1.ts │ │ │ ├── 2.ts │ │ │ ├── 3.ts │ │ │ └── index.m3u8 │ │ ├── signal-4 │ │ │ ├── 0.ts │ │ │ ├── 1.ts │ │ │ ├── 2.ts │ │ │ ├── 3.ts │ │ │ └── index.m3u8 │ │ ├── signal-5 │ │ │ ├── 0.ts │ │ │ ├── 1.ts │ │ │ ├── 2.ts │ │ │ ├── 3.ts │ │ │ └── index.m3u8 │ │ ├── signal-6 │ │ │ ├── 0.ts │ │ │ ├── 1.ts │ │ │ ├── 2.ts │ │ │ ├── 3.ts │ │ │ └── index.m3u8 │ │ ├── signal-7 │ │ │ ├── 0.ts │ │ │ ├── 1.ts │ │ │ ├── 2.ts │ │ │ ├── 3.ts │ │ │ └── index.m3u8 │ │ ├── signal-8 │ │ │ ├── 0.ts │ │ │ ├── 1.ts │ │ │ ├── 2.ts │ │ │ ├── 3.ts │ │ │ └── index.m3u8 │ │ └── signal-9 │ │ │ ├── 0.ts │ │ │ ├── 1.ts │ │ │ ├── 2.ts │ │ │ ├── 3.ts │ │ │ └── index.m3u8 │ └── dash │ │ ├── signal-1 │ │ ├── 256.init.mp4 │ │ ├── 256.1026000.mp4 │ │ ├── 256.126000.mp4 │ │ ├── 256.1476000.mp4 │ │ ├── 256.576000.mp4 │ │ └── index.mpd │ │ ├── signal-2 │ │ ├── 256.init.mp4 │ │ ├── 256.1026000.mp4 │ │ ├── 256.126000.mp4 │ │ ├── 256.1476000.mp4 │ │ ├── 256.576000.mp4 │ │ └── index.mpd │ │ ├── signal-3 │ │ ├── 256.init.mp4 │ │ ├── 256.1026000.mp4 │ │ ├── 256.126000.mp4 │ │ ├── 256.1476000.mp4 │ │ ├── 256.576000.mp4 │ │ └── index.mpd │ │ ├── signal-4 │ │ ├── 256.init.mp4 │ │ ├── 256.1026000.mp4 │ │ ├── 256.126000.mp4 │ │ ├── 256.1476000.mp4 │ │ ├── 256.576000.mp4 │ │ └── index.mpd │ │ ├── signal-5 │ │ ├── 256.init.mp4 │ │ ├── 256.1026000.mp4 │ │ ├── 256.126000.mp4 │ │ ├── 256.1476000.mp4 │ │ ├── 256.576000.mp4 │ │ └── index.mpd │ │ ├── signal-6 │ │ ├── 256.init.mp4 │ │ ├── 256.1026000.mp4 │ │ ├── 256.126000.mp4 │ │ ├── 256.1476000.mp4 │ │ ├── 256.576000.mp4 │ │ └── index.mpd │ │ ├── signal-7 │ │ ├── 256.init.mp4 │ │ ├── 256.1026000.mp4 │ │ ├── 256.126000.mp4 │ │ ├── 256.1476000.mp4 │ │ ├── 256.576000.mp4 │ │ └── index.mpd │ │ ├── signal-8 │ │ ├── 256.init.mp4 │ │ ├── 256.1026000.mp4 │ │ ├── 256.126000.mp4 │ │ ├── 256.1476000.mp4 │ │ ├── 256.576000.mp4 │ │ └── index.mpd │ │ ├── signal-9 │ │ ├── 256.init.mp4 │ │ ├── 256.1026000.mp4 │ │ ├── 256.126000.mp4 │ │ ├── 256.1476000.mp4 │ │ ├── 256.576000.mp4 │ │ └── index.mpd │ │ └── signal-10 │ │ ├── 256.126000.mp4 │ │ ├── 256.576000.mp4 │ │ ├── 256.init.mp4 │ │ ├── 256.1026000.mp4 │ │ ├── 256.1476000.mp4 │ │ └── index.mpd ├── nginx-origin.conf └── Dockerfile ├── .gitignore ├── benchmark └── Dockerfile ├── benchmark.sh ├── benchmark_all.sh ├── lb ├── Dockerfile ├── nginx-lb.conf └── load_balancer.lua ├── README.md ├── docker-compose.yml ├── nginx-cache.conf └── Makefile /results/requirements.txt: -------------------------------------------------------------------------------- 1 | plotnine 2 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | std="ngx_lua+busted" 2 | max_line_length=120 3 | -------------------------------------------------------------------------------- /fonts/OpenSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/fonts/OpenSans-Bold.ttf -------------------------------------------------------------------------------- /images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/images/architecture.png -------------------------------------------------------------------------------- /healthchecker/go.mod: -------------------------------------------------------------------------------- 1 | module healthchecker 2 | 3 | go 1.12 4 | 5 | require github.com/go-redis/redis v6.15.2+incompatible 6 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-1/0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-1/0.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-1/1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-1/1.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-1/2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-1/2.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-1/3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-1/3.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-10/0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-10/0.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-10/1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-10/1.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-10/2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-10/2.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-10/3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-10/3.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-2/0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-2/0.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-2/1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-2/1.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-2/2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-2/2.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-2/3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-2/3.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-3/0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-3/0.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-3/1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-3/1.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-3/2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-3/2.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-3/3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-3/3.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-4/0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-4/0.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-4/1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-4/1.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-4/2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-4/2.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-4/3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-4/3.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-5/0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-5/0.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-5/1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-5/1.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-5/2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-5/2.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-5/3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-5/3.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-6/0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-6/0.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-6/1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-6/1.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-6/2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-6/2.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-6/3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-6/3.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-7/0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-7/0.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-7/1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-7/1.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-7/2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-7/2.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-7/3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-7/3.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-8/0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-8/0.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-8/1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-8/1.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-8/2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-8/2.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-8/3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-8/3.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-9/0.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-9/0.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-9/1.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-9/1.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-9/2.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-9/2.ts -------------------------------------------------------------------------------- /origin/samples/hls/signal-9/3.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/hls/signal-9/3.ts -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | benchmark-*-table.txt 3 | /results/*.png 4 | /results/*.txt 5 | /results/benchmark 6 | /healthchecker/healthchecker 7 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-1/256.init.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-1/256.init.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-2/256.init.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-2/256.init.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-3/256.init.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-3/256.init.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-4/256.init.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-4/256.init.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-5/256.init.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-5/256.init.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-6/256.init.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-6/256.init.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-7/256.init.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-7/256.init.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-8/256.init.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-8/256.init.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-9/256.init.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-9/256.init.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-1/256.1026000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-1/256.1026000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-1/256.126000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-1/256.126000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-1/256.1476000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-1/256.1476000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-1/256.576000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-1/256.576000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-10/256.126000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-10/256.126000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-10/256.576000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-10/256.576000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-10/256.init.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-10/256.init.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-2/256.1026000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-2/256.1026000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-2/256.126000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-2/256.126000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-2/256.1476000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-2/256.1476000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-2/256.576000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-2/256.576000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-3/256.1026000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-3/256.1026000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-3/256.126000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-3/256.126000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-3/256.1476000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-3/256.1476000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-3/256.576000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-3/256.576000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-4/256.1026000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-4/256.1026000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-4/256.126000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-4/256.126000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-4/256.1476000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-4/256.1476000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-4/256.576000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-4/256.576000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-5/256.1026000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-5/256.1026000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-5/256.126000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-5/256.126000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-5/256.1476000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-5/256.1476000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-5/256.576000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-5/256.576000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-6/256.1026000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-6/256.1026000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-6/256.126000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-6/256.126000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-6/256.1476000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-6/256.1476000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-6/256.576000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-6/256.576000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-7/256.1026000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-7/256.1026000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-7/256.126000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-7/256.126000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-7/256.1476000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-7/256.1476000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-7/256.576000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-7/256.576000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-8/256.1026000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-8/256.1026000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-8/256.126000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-8/256.126000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-8/256.1476000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-8/256.1476000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-8/256.576000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-8/256.576000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-9/256.1026000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-9/256.1026000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-9/256.126000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-9/256.126000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-9/256.1476000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-9/256.1476000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-9/256.576000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-9/256.576000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-10/256.1026000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-10/256.1026000.mp4 -------------------------------------------------------------------------------- /origin/samples/dash/signal-10/256.1476000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/anacarolinacastro/simple-video-cdn/HEAD/origin/samples/dash/signal-10/256.1476000.mp4 -------------------------------------------------------------------------------- /healthchecker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest 2 | RUN mkdir /app 3 | COPY healthchecker.go /app 4 | WORKDIR /app 5 | RUN go build -o healthchecker . 6 | RUN ["chmod", "+x", "/app/healthchecker"] 7 | CMD ["/app/healthchecker"] -------------------------------------------------------------------------------- /healthchecker/go.sum: -------------------------------------------------------------------------------- 1 | github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= 2 | github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= 3 | -------------------------------------------------------------------------------- /benchmark/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:latest 2 | 3 | RUN mkdir /app 4 | WORKDIR /app 5 | 6 | RUN go get github.com/tsliwowicz/go-wrk 7 | RUN go build -o go-wrk /go/src/github.com/tsliwowicz/go-wrk 8 | 9 | ENTRYPOINT [ "/app/go-wrk" ] 10 | 11 | -------------------------------------------------------------------------------- /results/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | WORKDIR /usr/src/app 4 | 5 | COPY requirements.txt ./ 6 | RUN pip install --no-cache-dir -r requirements.txt 7 | 8 | COPY . . 9 | 10 | CMD [ "python", "vts-plot.py" ] 11 | # ENTRYPOINT [ "bash" ] 12 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-1/index.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-TARGETDURATION:10 5 | 6 | #EXTINF:5.000, 7 | 0.ts 8 | #EXTINF:5.000, 9 | 1.ts 10 | #EXTINF:5.000, 11 | 2.ts 12 | #EXTINF:2.567, 13 | 3.ts 14 | 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-10/index.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-TARGETDURATION:10 5 | 6 | #EXTINF:5.000, 7 | 0.ts 8 | #EXTINF:5.000, 9 | 1.ts 10 | #EXTINF:5.000, 11 | 2.ts 12 | #EXTINF:2.567, 13 | 3.ts 14 | 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-2/index.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-TARGETDURATION:10 5 | 6 | #EXTINF:5.000, 7 | 0.ts 8 | #EXTINF:5.000, 9 | 1.ts 10 | #EXTINF:5.000, 11 | 2.ts 12 | #EXTINF:2.567, 13 | 3.ts 14 | 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-3/index.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-TARGETDURATION:10 5 | 6 | #EXTINF:5.000, 7 | 0.ts 8 | #EXTINF:5.000, 9 | 1.ts 10 | #EXTINF:5.000, 11 | 2.ts 12 | #EXTINF:2.567, 13 | 3.ts 14 | 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-4/index.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-TARGETDURATION:10 5 | 6 | #EXTINF:5.000, 7 | 0.ts 8 | #EXTINF:5.000, 9 | 1.ts 10 | #EXTINF:5.000, 11 | 2.ts 12 | #EXTINF:2.567, 13 | 3.ts 14 | 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-5/index.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-TARGETDURATION:10 5 | 6 | #EXTINF:5.000, 7 | 0.ts 8 | #EXTINF:5.000, 9 | 1.ts 10 | #EXTINF:5.000, 11 | 2.ts 12 | #EXTINF:2.567, 13 | 3.ts 14 | 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-6/index.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-TARGETDURATION:10 5 | 6 | #EXTINF:5.000, 7 | 0.ts 8 | #EXTINF:5.000, 9 | 1.ts 10 | #EXTINF:5.000, 11 | 2.ts 12 | #EXTINF:2.567, 13 | 3.ts 14 | 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-7/index.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-TARGETDURATION:10 5 | 6 | #EXTINF:5.000, 7 | 0.ts 8 | #EXTINF:5.000, 9 | 1.ts 10 | #EXTINF:5.000, 11 | 2.ts 12 | #EXTINF:2.567, 13 | 3.ts 14 | 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-8/index.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-TARGETDURATION:10 5 | 6 | #EXTINF:5.000, 7 | 0.ts 8 | #EXTINF:5.000, 9 | 1.ts 10 | #EXTINF:5.000, 11 | 2.ts 12 | #EXTINF:2.567, 13 | 3.ts 14 | 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /origin/samples/hls/signal-9/index.m3u8: -------------------------------------------------------------------------------- 1 | #EXTM3U 2 | #EXT-X-VERSION:3 3 | #EXT-X-MEDIA-SEQUENCE:0 4 | #EXT-X-TARGETDURATION:10 5 | 6 | #EXTINF:5.000, 7 | 0.ts 8 | #EXTINF:5.000, 9 | 1.ts 10 | #EXTINF:5.000, 11 | 2.ts 12 | #EXTINF:2.567, 13 | 3.ts 14 | 15 | #EXT-X-ENDLIST 16 | -------------------------------------------------------------------------------- /benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | for i in $(seq 1 $2) 3 | do 4 | count=100 5 | if [ $i -eq "10" ] 6 | then 7 | count=500 8 | fi 9 | 10 | docker run --net="host" --rm anafrombr/go-wrk -redir -T 5000 -c $count -d 5 http://0.0.0.0:80/live/hls/signal-$i/index.m3u8 > results/benchmark/signal-$1-$i.log & 11 | done 12 | -------------------------------------------------------------------------------- /benchmark_all.sh: -------------------------------------------------------------------------------- 1 | algoritms=("random" "round_robin" "least_conn" "consistent_hash" "consistent_hash_bound_load") 2 | # algoritms=("consistent_hash" "consistent_hash_bound_load") 3 | # algoritms=("consistent_hash_bound_load") 4 | # algoritms=("consistent_hash") 5 | for i in "${algoritms[@]}" 6 | do 7 | echo $i 8 | LB_ALGORITM=$i make run & 9 | sleep 40; 10 | LB_ALGORITM=$i SIGNALS=10 make benchmark; 11 | sleep 30; 12 | LB_ALGORITM=$i make plot; 13 | make down; 14 | sleep 20 15 | done 16 | -------------------------------------------------------------------------------- /origin/nginx-origin.conf: -------------------------------------------------------------------------------- 1 | daemon off; 2 | user www-data; 3 | 4 | error_log stderr notice; 5 | 6 | events { } 7 | 8 | http { 9 | server { 10 | listen 8080; 11 | 12 | location /ingest/ { 13 | client_max_body_size 0; 14 | 15 | ts; 16 | ts_hls path=/var/media/hls segment=5s noclean; 17 | ts_dash path=/var/media/dash segment=5s noclean; 18 | } 19 | 20 | location /live/ { 21 | types { 22 | application/x-mpegURL m3u8; 23 | application/dash+xml mpd; 24 | video/MP2T ts; 25 | video/mp4 mp4; 26 | } 27 | alias /var/media/; 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /lb/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openresty/openresty:alpine 2 | 3 | WORKDIR /tmp 4 | RUN apk update &&\ 5 | apk add make && \ 6 | apk add openssl && \ 7 | apk add lua-dev && \ 8 | apk add wget && \ 9 | apk add gcc && \ 10 | apk add unzip && \ 11 | apk add libc-dev && \ 12 | apk add busybox-extras 13 | 14 | RUN wget 45.33.61.132/releases/luarocks-3.1.3.tar.gz && \ 15 | tar zxpf luarocks-3.1.3.tar.gz && \ 16 | rm luarocks-3.1.3.tar.gz && \ 17 | cd luarocks-3.1.3 && \ 18 | ./configure && \ 19 | make bootstrap 20 | 21 | RUN luarocks install lua-resty-redis && \ 22 | luarocks install lua-resty-string && \ 23 | luarocks install luacheck 24 | 25 | COPY nginx-lb.conf /usr/local/openresty/nginx/conf/nginx.conf 26 | COPY load_balancer.lua /usr/local/openresty/nginx/conf/load_balancer.lua 27 | -------------------------------------------------------------------------------- /lb/nginx-lb.conf: -------------------------------------------------------------------------------- 1 | env LB_ALGORITM; 2 | env CACHE_PORTS_RANGE; 3 | env NODES; 4 | env REPLICAS_PER_CACHE; 5 | env CACHE_POOL_SIZE; 6 | 7 | events { 8 | worker_connections 1024; 9 | } 10 | 11 | error_log stderr; 12 | 13 | http { 14 | lua_package_path '/usr/local/share/lua/5.1/?.lua;/usr/local/openresty/nginx/conf/load_balancer.lua;${prefix}../../?.lua;;'; 15 | 16 | log_format lb '$remote_addr - - [$time_local] ' 17 | '"$request" $status $body_bytes_sent ' 18 | '"$http_referer" "$http_user_agent"'; 19 | 20 | lua_shared_dict ports_load 10m; 21 | 22 | server { 23 | listen 8080; 24 | error_log /dev/stdout debug; 25 | access_log /dev/stdout lb; 26 | 27 | add_header 'Access-Control-Allow-Origin' '*'; 28 | add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; 29 | add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; 30 | add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; 31 | 32 | location ~ ".*\/(?.*)\/.*\.m3u8|mpd|ts|mp4$" { 33 | rewrite_by_lua_block { 34 | local load_balancer = require "load_balancer" 35 | load_balancer.cache() 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-1/index.mpd: -------------------------------------------------------------------------------- 1 | 2 | 13 | 16 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-10/index.mpd: -------------------------------------------------------------------------------- 1 | 2 | 13 | 16 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-2/index.mpd: -------------------------------------------------------------------------------- 1 | 2 | 13 | 16 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-3/index.mpd: -------------------------------------------------------------------------------- 1 | 2 | 13 | 16 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-4/index.mpd: -------------------------------------------------------------------------------- 1 | 2 | 13 | 16 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-5/index.mpd: -------------------------------------------------------------------------------- 1 | 2 | 13 | 16 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-6/index.mpd: -------------------------------------------------------------------------------- 1 | 2 | 13 | 16 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-7/index.mpd: -------------------------------------------------------------------------------- 1 | 2 | 13 | 16 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-8/index.mpd: -------------------------------------------------------------------------------- 1 | 2 | 13 | 16 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /origin/samples/dash/signal-9/index.mpd: -------------------------------------------------------------------------------- 1 | 2 | 13 | 16 | 19 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /origin/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | ENV PATH $PATH:/usr/local/nginx/sbin 5 | 6 | ENV NGINX_VERSION 1.13.3 7 | ENV NGINX_TS_VERSION 0.1.1 8 | 9 | EXPOSE 8080 10 | EXPOSE 0-65535/udp 11 | 12 | RUN mkdir /src /config /logs /data 13 | RUN mkdir /var/media /var/media/hls /var/media/dash 14 | 15 | RUN set -x && \ 16 | apt-get update && \ 17 | apt-get upgrade -y && \ 18 | apt-get clean && \ 19 | apt-get install -y --no-install-recommends build-essential \ 20 | wget software-properties-common && \ 21 | apt-get install -y --no-install-recommends libpcre3-dev \ 22 | zlib1g-dev libssl-dev wget 23 | 24 | WORKDIR /src 25 | RUN set -x && \ 26 | wget http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \ 27 | tar zxf nginx-${NGINX_VERSION}.tar.gz && \ 28 | rm nginx-${NGINX_VERSION}.tar.gz && \ 29 | wget https://github.com/arut/nginx-ts-module/archive/v${NGINX_TS_VERSION}.tar.gz && \ 30 | tar zxf v${NGINX_TS_VERSION}.tar.gz && \ 31 | rm v${NGINX_TS_VERSION}.tar.gz 32 | 33 | WORKDIR /src/nginx-${NGINX_VERSION} 34 | RUN set -x && \ 35 | ./configure --with-http_ssl_module \ 36 | --add-module=/src/nginx-ts-module-${NGINX_TS_VERSION} \ 37 | --with-http_stub_status_module \ 38 | --conf-path=/config/nginx.conf \ 39 | --error-log-path=/logs/error.log \ 40 | --http-log-path=/logs/access.log && \ 41 | make && \ 42 | make install 43 | 44 | COPY nginx-origin.conf /config/nginx.conf 45 | 46 | WORKDIR / 47 | CMD "nginx" 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple Video CDN 2 | A minimal CDN for load balance studies purposes. 3 | 4 | ![Architecture](/images/architecture.png) 5 | 6 | 7 | #### Docker services 8 | 9 | - *simple-video-cdn_origin_1:* ingest/packager/origin 10 | - *simple-video-cdn_cache_N:* cache server N 11 | - *simple-video-cdn_lb_1:* load balancer 12 | - *simple-video-cdn_healthchecker_1:* go application that do the health check 13 | - *simple-video-cdn_redis_1*: redis db that stores the health and load data 14 | 15 | 16 | ## Running 17 | 18 | #### Delivery 19 | Delivery HLS and Dash video (two cache instances): 20 | ```bash 21 | make run 22 | ``` 23 | 24 | 25 | #### Ingest 26 | - Ingest video from ffmpeg filter: 27 | ```bash 28 | make ingest 29 | ``` 30 | 31 | Or ingest another video to http://0.0.0.0:8080/ingest/signal-1. 32 | 33 | #### Consume 34 | - Consume the HLS playlist: 35 | ```bash 36 | curl -s http://0.0.0.0:80/live/hls/signal-1/index.m3u8 37 | ``` 38 | - Consume the Dash play list: 39 | ```bash 40 | curl -s http://0.0.0.0:80/live/dash/signal-1/index.mpd 41 | ``` 42 | 43 | ## Built With 44 | - [ffmpeg](https://github.com/FFmpeg/FFmpeg) - audio/video handler 45 | - [nginx](https://github.com/nginx/nginx) - HTTP server and reverse proxy 46 | - [nginx-ts-module](https://github.com/arut/nginx-ts-module) - receives MPEG-TS and serves HLS and DASH over HTTP 47 | - [nginx-module-vts](https://github.com/vozlt/nginx-module-vts) - fetch host traffic status 48 | - [Golang](https://golang.org/) - compiled language 49 | - [Lua](https://www.lua.org/) - script language 50 | - [Redis](https://redis.io/) - in-memory database 51 | 52 | ## Authors 53 | Ana Carolina Castro - Initial work - Globo.com 54 | 55 | ## Acknowledgments 56 | This is not a resilient architecture. 57 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | lb: 5 | build: ./lb 6 | links: 7 | - cache 8 | - redis 9 | ports: 10 | - "80:8080" 11 | depends_on: 12 | - cache 13 | - redis 14 | networks: 15 | service1_net: 16 | ipv4_address: 172.22.0.101 17 | environment: 18 | LB_ALGORITM: "${LB_ALGORITM}" 19 | CACHE_PORTS_RANGE: "${CACHE_PORTS_RANGE}" 20 | NODES: "${NODES}" 21 | REPLICAS_PER_CACHE: "${REPLICAS_PER_CACHE}" 22 | 23 | cache: 24 | image: marrotte/openresty-vts-sts 25 | links: 26 | - origin:origin 27 | volumes: 28 | - "./nginx-cache.conf:/usr/local/openresty/nginx/conf/nginx.conf" 29 | ports: 30 | - "${CACHE_PORTS_RANGE}:8080" 31 | depends_on: 32 | - origin 33 | 34 | origin: 35 | build: ./origin 36 | volumes: 37 | - "./origin/samples:/var/media" 38 | ports: 39 | - "8080:8080" 40 | 41 | redis: 42 | image: redis 43 | ports: 44 | - "6379:6379" 45 | networks: 46 | service1_net: 47 | ipv4_address: 172.22.0.100 48 | 49 | # lint: 50 | # command: sh -c "luacheck -q ." 51 | # build: ./lb 52 | # volumes: 53 | # - ".:/lua/" 54 | # working_dir: "/lua" 55 | 56 | healthchecker: 57 | image: golang:1.12 58 | volumes: 59 | - ./healthchecker:/app 60 | working_dir: /app 61 | command: ./healthchecker 62 | # command: sh -c 'go build healthchecker.go && ./healthchecker' 63 | network_mode: "host" 64 | depends_on: 65 | - cache 66 | - redis 67 | environment: 68 | CACHE_PORTS_RANGE: "${CACHE_PORTS_RANGE}" 69 | 70 | networks: 71 | service1_net: 72 | ipam: 73 | driver: default 74 | config: 75 | - subnet: 172.22.0.0/16 76 | -------------------------------------------------------------------------------- /nginx-cache.conf: -------------------------------------------------------------------------------- 1 | events { 2 | worker_connections 256; 3 | } 4 | 5 | error_log stderr; 6 | 7 | http { 8 | vhost_traffic_status_zone; 9 | 10 | upstream backend { 11 | server origin:8080; 12 | } 13 | 14 | proxy_cache_path /tmp levels=1:2 keys_zone=cdn_cache:10m max_size=10g inactive=60m; 15 | log_format cache '$remote_addr - $upstream_cache_status [$time_local] ' 16 | '"$request" $status $body_bytes_sent ' 17 | '"$http_referer" "$http_user_agent"'; 18 | 19 | server { 20 | listen 8080; 21 | access_log /dev/stdout cache; 22 | 23 | add_header 'Access-Control-Allow-Origin' '*'; 24 | add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; 25 | add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; 26 | add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; 27 | 28 | location /healthcheck { 29 | return 200 'WORKING'; 30 | } 31 | 32 | location /status { 33 | vhost_traffic_status_display; 34 | vhost_traffic_status_display_format json; 35 | access_log off; 36 | } 37 | 38 | location ~ "\.(m3u8|mpd)$" { 39 | proxy_pass http://backend; 40 | proxy_set_header Host $host; 41 | proxy_buffering on; 42 | proxy_cache cdn_cache; 43 | proxy_cache_key $scheme$proxy_host$request_uri; 44 | proxy_cache_lock on; 45 | proxy_cache_valid 200 9s; # this should be less than the chunk size 46 | proxy_cache_use_stale error timeout invalid_header updating 47 | http_500 http_502 http_503 http_504; 48 | } 49 | 50 | location ~ "\.(ts|mp4)$" { 51 | proxy_pass http://backend; 52 | proxy_set_header Host $host; 53 | proxy_buffering on; 54 | proxy_cache cdn_cache; 55 | proxy_cache_key $scheme$proxy_host$request_uri; 56 | proxy_cache_lock on; 57 | proxy_cache_valid 200 10m; 58 | proxy_cache_use_stale error timeout invalid_header updating 59 | http_500 http_502 http_503 http_504; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: benchmark 2 | 3 | CACHE_PORTS_RANGE ?= 8090-8091 4 | CACHE_POOL_SIZE ?= 2 5 | LB_ALGORITM ?= round_robin 6 | SIGNALS ?= 5 7 | NODES ?= 100 8 | REPLICAS_PER_CACHE ?= 4 9 | 10 | available-algoritms: 11 | @echo random round_robin least_conn consistent_hash consistent_hash_bound_load 12 | 13 | build-origin: 14 | docker build -t nginx-rtmp . 15 | 16 | run-origin: build-origin 17 | docker run -it -p 1935:1935 -p 8080:8080 --rm nginx-rtmp 18 | 19 | build: 20 | LB_ALGORITM=$(LB_ALGORITM) CACHE_PORTS_RANGE=$(CACHE_PORTS_RANGE) docker-compose build 21 | 22 | run: build 23 | NODES=$(NODES) CACHE_POOL_SIZE=$(CACHE_POOL_SIZE) REPLICAS_PER_CACHE=$(REPLICAS_PER_CACHE) LB_ALGORITM=$(LB_ALGORITM) CACHE_PORTS_RANGE=$(CACHE_PORTS_RANGE) docker-compose up --scale cache=$(CACHE_POOL_SIZE) 24 | 25 | lint: 26 | NODES=$(NODES) REPLICAS_PER_CACHE=$(REPLICAS_PER_CACHE) LB_ALGORITM=$(LB_ALGORITM) CACHE_PORTS_RANGE=$(CACHE_PORTS_RANGE) docker-compose run --rm lint 27 | 28 | down: 29 | NODES=$(NODES) REPLICAS_PER_CACHE=$(REPLICAS_PER_CACHE) LB_ALGORITM=$(LB_ALGORITM) CACHE_PORTS_RANGE=$(CACHE_PORTS_RANGE) docker-compose down 30 | 31 | ingest: 32 | docker run --net="host" --rm -v $(shell pwd):/files jrottenberg/ffmpeg:4.1 -hide_banner \ 33 | -re -f lavfi -i "testsrc2=size=1280x720:rate=30" -pix_fmt yuv420p \ 34 | -c:v libx264 -x264opts keyint=30:min-keyint=30:scenecut=-1 \ 35 | -tune zerolatency -profile:v high -preset veryfast -bf 0 -refs 3 \ 36 | -b:v 1400k -bufsize 1400k \ 37 | -vf "drawtext=fontfile='/files/fonts/OpenSans-Bold.ttf':text='%{localtime}:box=1:fontcolor=black:boxcolor=white:fontsize=100':x=40:y=400'" \ 38 | -utc_timing_url "https://time.akamai.com/?iso" -use_timeline 0 -media_seg_name 'chunk-stream-$RepresentationID$-$Number%05d$.m4s' \ 39 | -init_seg_name 'init-stream1-$RepresentationID$.m4s' \ 40 | -window_size 5 -extra_window_size 10 -remove_at_exit 1 -adaptation_sets "id=0,streams=v id=1,streams=a" -f mpegts http://127.0.0.1:8080/ingest/signal-1 41 | 42 | benchmark: 43 | ./benchmark.sh $(LB_ALGORITM) $(SIGNALS) 44 | 45 | build-plot: 46 | docker build results -t vts-plot 47 | 48 | plot:build-plot 49 | docker run --env LB_ALGORITM=$(LB_ALGORITM) --env CACHE_PORTS_RANGE=$(CACHE_PORTS_RANGE) -it -v $(PWD)/results:/files --network host --rm vts-plot 50 | -------------------------------------------------------------------------------- /healthchecker/healthchecker.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "os" 9 | "strconv" 10 | "strings" 11 | "time" 12 | 13 | "github.com/go-redis/redis" 14 | ) 15 | 16 | // PORTS correspond to the cache ports range 17 | var PORTS = getEnv("CACHE_PORTS_RANGE", "8090-8091") 18 | var redisClient = getRedis() 19 | 20 | type Status struct { 21 | Connection Connection `json:"connections"` 22 | } 23 | 24 | type Connection struct { 25 | Active int `json:"active"` 26 | Reading int `json:"reading"` 27 | Writing int `json:"writing"` 28 | Waiting int `json:"waiting"` 29 | Accepted int `json:"accepted"` 30 | Handled int `json:"handled"` 31 | Requests int `json:"requests"` 32 | } 33 | 34 | func main() { 35 | firstPort, lastPort := portsRange() 36 | for { 37 | for port := firstPort; port <= lastPort; port++ { 38 | go statusCheck(port) 39 | } 40 | time.Sleep(1 * time.Second) 41 | } 42 | } 43 | 44 | func getRedis() *redis.Client { 45 | client := redis.NewClient(&redis.Options{ 46 | Addr: "localhost:6379", 47 | Password: "", 48 | DB: 0, 49 | }) 50 | 51 | return client 52 | } 53 | 54 | func setLoad(port, value string) { 55 | key := port 56 | redisClient.Set(key, value, 5*time.Second) 57 | } 58 | 59 | func statusCheck(port int) { 60 | server := fmt.Sprintf("http://0.0.0.0:%d", port) 61 | serverUp, status := vtsStatus(server) 62 | if serverUp { 63 | setLoad(fmt.Sprint(port), fmt.Sprint(status.Connection.Active)) 64 | // fmt.Printf("Server %s has load %d\n", server, status.Connection.Active) 65 | } 66 | } 67 | 68 | func vtsStatus(server string) (bool, Status) { 69 | resp, err := http.Get(server + "/status") 70 | 71 | if err == nil && resp.StatusCode == 200 { 72 | var status Status 73 | 74 | body, _ := ioutil.ReadAll(resp.Body) 75 | json.Unmarshal(body, &status) 76 | 77 | return true, status 78 | } 79 | fmt.Printf("%#v\n", err.Error()) 80 | 81 | return false, Status{} 82 | } 83 | 84 | func getEnv(key, defaultValue string) string { 85 | value, found := os.LookupEnv(key) 86 | if found { 87 | return value 88 | } 89 | return defaultValue 90 | } 91 | 92 | func portsRange() (int, int) { 93 | ports := strings.Split(PORTS, "-") 94 | firstPort, _ := strconv.Atoi(ports[0]) 95 | lastPort, _ := strconv.Atoi(ports[1]) 96 | 97 | return firstPort, lastPort 98 | } 99 | -------------------------------------------------------------------------------- /results/benchmark-plot.py: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | from datetime import datetime 4 | from subprocess import call 5 | 6 | SIGNALS = 10 7 | ALGORITHMS = ["round_robin", "least_conn", "random", "consistent_hash", "consistent_hash_bound_load"] 8 | 9 | def make_table(type, caption): 10 | t = open("./benchmark-"+type+"-table.txt", "w") 11 | 12 | t.write("% ---- " + datetime.now().strftime("%d/%m/%Y %H:%M:%S") + " ----\n") 13 | t.write("\\begin{center}\n") 14 | t.write("\\begin{center}\n") 15 | t.write("\\captionsetup{justification=centering}\n") 16 | t.write("\\captionof{table}"+ caption+"\n") 17 | t.write("\\begin{tabular}{ccccccccccc}\n") 18 | t.write("\\textbf{Signal} &\\textbf{Random} &\\textbf{Round Robin} &\\textbf{Least Conn} &\\textbf{CH} &\\textbf{CHBL}\n") 19 | t.write("\\\\\n") 20 | t.write("\\hline\n") 21 | 22 | all_data = list() 23 | count = [0] * 5 24 | 25 | for i in range(SIGNALS): 26 | data = list() 27 | signal = str(i + 1) 28 | for k in range(len(ALGORITHMS)): 29 | algoritm = ALGORITHMS[k] 30 | file = open("results/benchmark/signal-"+algoritm+"-"+signal+".log") 31 | res = file.readlines() 32 | if type == "err": 33 | data.append( 34 | int(res[-1].replace("Number of Errors:\t", "").replace("\n", ""))) 35 | 36 | elif type == "avg": 37 | avg = res[-4].replace("Avg Req Time:\t\t", "").replace("ms\n", "") 38 | if avg.endswith("s\n"): 39 | avg = avg.replace("s\n", "") 40 | avg = float(avg) 41 | else: 42 | avg = float(avg) 43 | avg = avg/1000 44 | data.append(float(format(avg, '.4f'))) 45 | 46 | count[k] += data[k] 47 | all_data.append(data) 48 | 49 | t.write("signal-"+signal+" & " + str(all_data[i][0]) + " & " + str(all_data[i][1]) + " & " + str(all_data[i][2]) + " & " + str(all_data[i][3]) + " & " + str(all_data[i][4]) + "\\\\\n") 50 | 51 | t.write("\\hline\n") 52 | if type == "err": 53 | t.write("\\textit{Total} & \\textit{" + str(count[0]) + "} & \\textit{" + str(count[1]) + "} & \\textit{" + str( 54 | count[2]) + "} & \\textit{" + str(count[3]) + "} & \\textit{" + str(count[4]) + "}\\\\\n") 55 | elif type == "avg": 56 | t.write("\\textit{Media} &\\textit{" + str(count[0]/SIGNALS) + "} &\\textit{" + str(count[1]/SIGNALS) + "} &\\textit{" + str( 57 | count[2]/SIGNALS) + "} &\\textit{" + str(count[3]/SIGNALS) + "} &\\textit{" + str(count[4]/SIGNALS) + "}\\\\\n") 58 | 59 | t.write("\\end{tabular}\n") 60 | t.write("\\end{center}\n") 61 | t.write("\\vspace{3mm}\n") 62 | t.write("Fonte: A autora, \\UERJano.\n") 63 | t.write("\\end{center}\n") 64 | t.write("\\vspace{3mm}\n") 65 | t.close() 66 | 67 | 68 | make_table("avg", "{Tempo médio(em segundos) de resposta por sinal para os algoritmos estudados.}\\label{tab: avg_req}") 69 | make_table("err", "{Números de erros por sinal para os algoritmos estudados.}\\label{tab: err_req}") 70 | -------------------------------------------------------------------------------- /results/vts-plot.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from plotnine import * 3 | import urllib.request 4 | import json 5 | import os 6 | from datetime import datetime 7 | 8 | def get_json(url): 9 | req = urllib.request.Request(url) 10 | opener = urllib.request.build_opener() 11 | f = opener.open(req) 12 | return json.loads(f.read()) 13 | 14 | ports_range = os.environ['CACHE_PORTS_RANGE'].split('-') 15 | 16 | algoritm = os.environ['LB_ALGORITM'] 17 | title_algoritm = os.environ['LB_ALGORITM'].capitalize().replace("_", " ") 18 | 19 | f = open("/files/" + algoritm + ".txt", "w") 20 | f.write("---- " + datetime.now().strftime("%d/%m/%Y %H:%M:%S") + " ----\n") 21 | f.write("---- " + title_algoritm + " ----\n") 22 | 23 | t = open("/files/" + algoritm + "-table.txt", "w") 24 | t.write("\\begin{center}\n") 25 | t.write("\\begin{center}\n") 26 | t.write("\\captionsetup{justification=centering}\n") 27 | t.write("\\captionof{table}{Estatisticas de cache para o algoritmo \\textit{" + title_algoritm + "}.}\label{tab:"+title_algoritm+"}\n") 28 | t.write("\\begin{tabular}{ ccccccccccc }\n") 29 | t.write("\\textbf{Cache}&\\textbf{Port}&\\textbf{Hit}&\\textbf{Expire}&\\textbf{Updating}&\\textbf{Miss}\n") 30 | t.write("\\\\\n") 31 | t.write("\hline\n") 32 | 33 | data = [] 34 | first_port = int(ports_range[0]) 35 | last_port = int(ports_range[1]) 36 | 37 | total_hit = 0 38 | total_expired = 0 39 | total_updating = 0 40 | total_miss = 0 41 | 42 | requests_total = 0 43 | 44 | for i, port in enumerate(range(first_port, last_port + 1)): 45 | url = "http://0.0.0.0:"+str(port)+"/status" 46 | res = get_json(url) 47 | 48 | has_cache = res.get('cacheZones', False) 49 | if has_cache: 50 | hit = res['cacheZones']['cdn_cache']['responses']['hit'] 51 | expired = res['cacheZones']['cdn_cache']['responses']['expired'] 52 | updating = res['cacheZones']['cdn_cache']['responses']['updating'] 53 | miss = res['cacheZones']['cdn_cache']['responses']['miss'] 54 | else: 55 | hit = 0 56 | expired = 0 57 | updating = 0 58 | miss = 0 59 | 60 | total = hit + expired + updating + miss 61 | total_hit += hit 62 | total_expired += expired 63 | total_updating += updating 64 | total_miss += miss 65 | requests_total += total 66 | 67 | cache_id = i + 1 68 | 69 | data.append({"id": cache_id, "Cache status": "hit", "count": hit}) 70 | data.append({"id": cache_id, "Cache status": "expire", "count": expired}) 71 | data.append({"id": cache_id, "Cache status": "updating", "count": updating}) 72 | data.append({"id": cache_id, "Cache status": "miss", "count": miss}) 73 | 74 | t.write(str(cache_id) + "&" + str(port) + "&" + str(hit) + "&" + 75 | str(expired) + "&" + str(updating) + "&" + str(miss) + "\\\\\n") 76 | 77 | f.write("[CACHE " + str(i+1) + "] (port " + str(port) +")\n") 78 | f.write("hit: " + str(hit) + "\n") 79 | f.write("expire: " + str(expired) + "\n") 80 | f.write("updating: " + str(updating) + "\n") 81 | f.write("miss: " + str(miss) + "\n") 82 | f.write("sum: " + str(total) + "\n\n") 83 | 84 | 85 | df = pd.DataFrame(data) 86 | 87 | f.write("total requests: " + str(requests_total) + "\n\n") 88 | f.close() 89 | 90 | t.write("\\hline\n") 91 | t.write("all&-&" + str(total_hit) + "&" + str(total_expired) + "&" + str(total_updating) + "&" + str(total_miss) + "\\\\\n") 92 | t.write("\\end{tabular}\n") 93 | t.write("\\end{center}\n") 94 | t.write("\\vspace{3mm}\n") 95 | t.write("Fonte: A autora, \\UERJano.\n") 96 | t.write("\\end{center}\n") 97 | t.write("\\vspace{3mm}\n") 98 | t.close() 99 | 100 | # p = (ggplot(df, aes(x='Cache status', y='count')) + 101 | # geom_bar(aes(fill = 'factor(id)'), stat='identity') + 102 | # labs(fill="Cache") + 103 | # ggtitle(title_algoritm) 104 | # ) 105 | 106 | # ggsave(plot=p, filename=algoritm, path="/files/") 107 | -------------------------------------------------------------------------------- /lb/load_balancer.lua: -------------------------------------------------------------------------------- 1 | local redis = require "resty.redis" 2 | 3 | local load_balancer = {} 4 | local index_reference = 1 5 | local redis_timeout = 5000 6 | local nodes = tonumber(os.getenv("NODES")) 7 | local replicas_per_cache = tonumber(os.getenv("REPLICAS_PER_CACHE")) 8 | 9 | local function redis_conn() 10 | local red = redis:new() 11 | red:set_timeout(redis_timeout) 12 | red:connect("172.22.0.100", 6379) 13 | 14 | return red 15 | end 16 | 17 | -- get first and last port from the string range 18 | local function get_first_and_last_ports() 19 | local ports_range = os.getenv("CACHE_PORTS_RANGE") 20 | local first = string.sub(ports_range,1,4) 21 | local last = string.sub(ports_range,6,9) 22 | 23 | return first, last 24 | end 25 | 26 | -- list all health servers from redis 27 | local function check_server_health(port) 28 | local red = redis_conn() 29 | 30 | local conns = red:get(port) 31 | red:set_keepalive(10000,100) 32 | 33 | if tonumber(conns) then 34 | return true 35 | end 36 | 37 | return false 38 | end 39 | 40 | local function get_health_servers() 41 | local red = redis_conn() 42 | 43 | local first, last = get_first_and_last_ports() 44 | local a = {} 45 | 46 | for i=0, (last-first) do 47 | local port = first+i 48 | local conns = red:get(port) 49 | 50 | if conns then 51 | a[i+1] = math.floor(port) 52 | end 53 | end 54 | 55 | red:set_keepalive(10000, 100) 56 | return a 57 | end 58 | 59 | local function get_hash(string) 60 | local resty_md5 = require "resty.md5" 61 | local md5 = resty_md5:new() 62 | md5:update(string) 63 | local digest = md5:final() 64 | 65 | local str = require "resty.string" 66 | local digest_hex = str.to_hex(digest) 67 | local digest_int = tonumber(string.sub(digest_hex, -10), 16) 68 | 69 | return digest_int 70 | end 71 | 72 | 73 | local function get_hash_key(string) 74 | local hash = get_hash(string) 75 | local key = hash % nodes + 1 76 | 77 | return key 78 | end 79 | 80 | local function set_ring() 81 | ngx.log(ngx.DEBUG, "Setting up ring") 82 | local ring = {} 83 | local first, last = get_first_and_last_ports() 84 | 85 | for c=1, nodes do 86 | ring[c] = nil 87 | end 88 | 89 | for i=0, (last-first) do 90 | local port = first+i 91 | 92 | for r=1, replicas_per_cache do 93 | local vport = tostring(port) .. tostring(r) 94 | local key = get_hash_key(vport) 95 | ring[key] = port 96 | end 97 | end 98 | 99 | return ring 100 | end 101 | 102 | local ring = set_ring() 103 | 104 | local function set_load(port) 105 | local ports_load = ngx.shared.ports_load 106 | 107 | ports_load:incr(port, 1, 0) 108 | ports_load:incr("load", 1, 0) 109 | end 110 | 111 | local function get_total_load() 112 | local ports_load = ngx.shared.ports_load 113 | local sum = ports_load:get("load") 114 | 115 | if sum == nil then 116 | sum = 0 117 | end 118 | 119 | return sum 120 | end 121 | 122 | local function get_load(port) 123 | local ports_load = ngx.shared.ports_load 124 | local res = ports_load:get(port) 125 | 126 | if res == nil then 127 | res = 0 128 | end 129 | 130 | return res 131 | end 132 | 133 | local function get_all_loads() 134 | local load = {} 135 | local first, last = get_first_and_last_ports() 136 | for i=0, (last-first) do 137 | local port = first+i 138 | load[port] = get_load(port) 139 | end 140 | 141 | return load 142 | end 143 | 144 | local function load_ok(port) 145 | local load = get_all_loads() 146 | local total_load = get_total_load() 147 | local avg = math.ceil((total_load + 1)/5) -- / 148 | local max_load = avg * 1.25 149 | 150 | -- ngx.log(ngx.DEBUG, "port: " .. port .. "| avg: " .. avg .. " | total load: " .. total_load .. " | load: " .. load[port] .. " | max load: " .. max_load) 151 | 152 | if (load[port]+1) <= max_load then 153 | return true 154 | end 155 | 156 | return false 157 | end 158 | 159 | -- call the method for the decision algoritmn chosen 160 | load_balancer.cache = function() 161 | local cache = load_balancer[os.getenv("LB_ALGORITM")]() 162 | 163 | return ngx.redirect(cache .. ngx.var.uri); 164 | end 165 | 166 | -- all functions are desions make algoritms till the end of file 167 | load_balancer.random = function() 168 | local ports = get_health_servers() 169 | local port = ports[math.random(1,#ports)] 170 | 171 | return "http://0.0.0.0:" .. port 172 | end 173 | 174 | load_balancer.round_robin = function() 175 | local ports = get_health_servers() 176 | local port_index = math.fmod(index_reference,#ports) + 1 177 | local port = ports[port_index] 178 | index_reference = index_reference + 1 179 | 180 | return "http://0.0.0.0:" .. port 181 | end 182 | 183 | load_balancer.least_conn = function() 184 | local red = redis:new() 185 | red:set_timeout(redis_timeout) 186 | local ok, err = red:connect("172.22.0.100", 6379) 187 | 188 | if not ok then 189 | ngx.log(ngx.ERR, "Fail to connect to redis: " .. err) 190 | return 191 | end 192 | 193 | local first, last = get_first_and_last_ports() 194 | 195 | local least_conn_port = first 196 | local least_conn_conns = tonumber(red:get(first)) 197 | 198 | for i=1, (last-first) do 199 | local port = first+i 200 | local conns = tonumber(red:get(port)) 201 | 202 | if conns == nil then 203 | ngx.log(ngx.ERR, "Port is nil") 204 | end 205 | 206 | if least_conn_conns == nil then 207 | ngx.log(ngx.ERR, "least_conn_conns is nil ") 208 | end 209 | 210 | if conns < least_conn_conns then 211 | least_conn_port = port 212 | least_conn_conns = conns 213 | end 214 | end 215 | 216 | red:set_keepalive(10000, 100) 217 | 218 | return "http://0.0.0.0:" .. least_conn_port 219 | end 220 | 221 | load_balancer.consistent_hash = function() 222 | local signal_name = ngx.var.signal 223 | local key = get_hash_key(signal_name) 224 | local found = false 225 | local k = key 226 | local port 227 | local flag = false 228 | 229 | while not found do 230 | port = ring[k] 231 | 232 | if port then 233 | local health = check_server_health(port) 234 | if health then 235 | found = true 236 | end 237 | else 238 | if k == key and flag then -- wrap around 239 | return 240 | end 241 | end 242 | 243 | -- try the next node 244 | k = k + 1 245 | if k > nodes then 246 | k = 1 247 | end 248 | 249 | flag = true 250 | end 251 | 252 | -- ngx.log(ngx.ERR, signal_name .. "->" .. port) 253 | 254 | if false then -- port == nil then 255 | local ports = get_health_servers() 256 | port = ports[math.random(1,#ports)] 257 | end 258 | 259 | return "http://0.0.0.0:" .. port 260 | end 261 | 262 | load_balancer.consistent_hash_bound_load = function() 263 | local signal_name = ngx.var.signal 264 | local key = get_hash_key(signal_name) 265 | local found = false 266 | local k = key 267 | local port 268 | local flag = false 269 | 270 | while not found do 271 | port = ring[k] 272 | 273 | if port then 274 | -- ngx.log(ngx.ERR, "port[".. k .. "] = " .. port) 275 | local health = check_server_health(port) 276 | if health and load_ok(port) then 277 | found = true 278 | end 279 | else 280 | if k == key and flag then -- wrap around 281 | return 282 | end 283 | end 284 | 285 | -- try the next node 286 | k = k + 1 287 | if k > nodes then 288 | k = 1 289 | end 290 | 291 | flag = true 292 | end 293 | 294 | 295 | if false then -- port == nil then 296 | local ports = get_health_servers() 297 | 298 | if #ports == 0 then 299 | ngx.log(ngx.ERR, "SEM SERVERS SAUDAVEIS") 300 | end 301 | 302 | port = ports[math.random(1,#ports)] 303 | else 304 | set_load(port) 305 | end 306 | 307 | return "http://0.0.0.0:" .. port 308 | end 309 | 310 | -- returns the load_balancer object 311 | return load_balancer 312 | --------------------------------------------------------------------------------