Menangani 100+ Kamera dalam Satu Backend Go
Mengawasi 120 kamera dengan Go: atur sambungan, kapasitas kirim NVR, dan jeda sambung ulang agar perekam tidak dibanjiri permintaan.
Untuk Tim Teknis

Daftar isi
Dalam sistem dengan sekitar 120 kamera ini, jumlah goroutine bukan batas pertama yang saya temui. Kapasitas kirim dan jumlah sesi perekam lebih menentukan, terutama ketika sambungan pulih bersamaan setelah listrik padam. Rancang sambungan bersama untuk tayangan yang sama, beri jeda saat mencoba ulang, dan tentukan batas tayangan berdasarkan pengukuran.
Kesimpulan ini datang dari sistem yang baru saya bangun untuk sebuah gedung dengan sekitar 120 kamera. Kamera-kamera itu terhubung ke tiga NVR (network video recorder, perangkat penyimpan rekaman), dan diawasi dari beberapa PC operator di ruang kontrol. Berikut letak batas yang sebenarnya, serta pola penanganan sambungan ketika kamera bermasalah.
Seperti apa susunan sistemnya?
Ada satu aturan yang menentukan hampir semua keputusan: hanya server yang berhubungan dengan kamera dan perekam. PC operator cukup berbicara dengan server. Enam operator yang menonton kamera lift dengan profil video yang sama dapat memakai satu tarikan video dari NVR.
Dari perekam keluar dua jenis lalu lintas. Video dikirim lewat RTSP, protokol streaming yang umum dipakai kamera. Keanehannya pernah saya bahas di artikel integrasi kamera ONVIF dan RTSP. Kejadian, misalnya "ada gerakan di kanal video 12", datang lewat satu sambungan HTTP yang dibiarkan terbuka lama. Setiap kali ada perubahan, NVR menulis satu baris di sambungan itu.
Perantara videonya memakai go2rtc, server streaming sumber terbuka berlisensi MIT yang juga ditulis dengan Go. Satu tayangan, yaitu kombinasi kamera dan profil video yang sama, ditarik sekali dari NVR lalu dibagikan ke peramban yang meminta. Backend Go mengatur tayangan apa saja yang ada, siapa yang boleh menonton, dan apa yang terjadi saat sebuah kamera menghilang.
Apakah satu tugas per kamera terlalu banyak?
Goroutine memungkinkan beberapa pekerjaan berlangsung secara konkuren di Go; pekerjaan tersebut tidak selalu berjalan paralel pada saat yang sama. Go mengatur goroutine di atas thread sistem operasi. Menurut FAQ resmi Go, ukuran awal stack (memori kerja) setiap goroutine hanya beberapa KB dan dapat bertambah. Angka ini bukan total memori satu sambungan kamera: penampung data, struktur protokol, dan sumber daya jaringan juga perlu dihitung.
Yang perlu dihitung adalah jumlah sambungan ke perangkat. Batas sambungan NVR dapat tercapai sebelum jumlah goroutine menjadi kendala. Hitung per jenis pekerjaan:
| Pekerjaan | Rancangan naif | Yang dipakai | Alasan |
|---|---|---|---|
| Kejadian gerakan | 1 sambungan per kamera (120) | 1 per NVR (3) | Satu sambungan kejadian di NVR sudah mencakup semua kanal videonya |
| Video langsung | 1 per penonton per kamera | 1 per tayangan yang sedang ditonton | Perantara membagikan satu tarikan ke banyak penonton |
| Gambar kecil (thumbnail) | Tiap PC mengambil sendiri | Server mengambil sekali per interval | Dipakai bersama oleh semua PC |
| Putar ulang rekaman | Per permintaan | Satu pemegang akses per kamera; hingga 16 kamera per NVR | Aplikasi berbagi satu sesi putar ulang NVR dan mencegah permintaan yang bertentangan pada kamera yang sama |
Jumlah goroutine kira-kira mengikuti kolom "yang dipakai". Beban di perekam juga ikut turun dengan pola yang sama, dan itu yang lebih penting.
Di mana sistem mulai kewalahan?
Pada jalur tayangan langsung, server meneruskan data video tanpa mendekode gambar atau mengodekannya ulang. Kapasitas perekam dan kemampuan PC operator tetap perlu diperiksa. Jalur opsional untuk putar mundur yang lebih mulus memakai FFmpeg untuk mendekode dan mengodekan ulang video. Jalur ini dimatikan secara bawaan pada konfigurasi yang ditinjau; putar mundur biasa memakai gambar kunci dari perekam. Jalur opsional tersebut memerlukan pengaturan aktivasi, satu kamera NVR, kecepatan −1× atau −2×, dan pengode yang siap.
Spesifikasi model NVR di lokasi ini mencantumkan kapasitas kirim 400 Mbps dan hanya satu pengguna putar ulang per unit. Batas tayangan langsung tertulis "10 pengguna". Setelah diuji, yang dimaksud ternyata sepuluh sesi: semua kanal video yang dibuka dengan kunci sesi yang sama dihitung satu. Pada uji lapangan 29 September 2026, satu NVR melayani 27 kanal video 1080p sekaligus lewat satu sesi, dan 26 di antaranya mengirim gambar.
Uji ini menunjukkan pentingnya kapasitas kirim dan perilaku sesi perekam. Hasilnya tidak menetapkan batas untuk semua model NVR. Akibat praktisnya:
- Gunakan profil video rendah untuk tampilan berkotak. Tampilan 5×5 berisi video beresolusi penuh membebani NVR dan PC operator. Kotak kecil memakai sub-stream, yaitu profil tayangan beresolusi rendah; klik dua kali membuka versi HD.
- Hindari konversi video jika tidak diperlukan. Mendekode dan mengodekan ulang video (transcoding) memerlukan pemrosesan tambahan. Meneruskan video tanpa konversi menghindari pekerjaan tersebut, tetapi tetap memakai jaringan, prosesor, dan memori.
- Tentukan batas berdasarkan pengukuran. Pengaturan batas tayangan per NVR pada sistem ini secara bawaan nonaktif. Jika hasil pengukuran menunjukkan perekam kewalahan, aktifkan batas yang sesuai kapasitasnya.
Hitungan kapasitas penyimpanan untuk lokasi sejenis ada di artikel ukuran penyimpanan CCTV.
Bagaimana menyambung ulang tanpa membebani perekam?
Sambungan kamera dapat terputus. Switch menyala ulang, listrik berkedip, atau kabel dicabut orang yang ingin mengisi baterai ponsel. Setelah listrik padam, empat puluh kamera bisa hidup kembali pada detik yang sama. Kalau semuanya mencoba lagi setiap detik, NVR dibanjiri permintaan masuk tepat ketika kondisinya paling lemah.
Sistem ini memakai jeda bertingkat, pemeriksaan aktivitas media, dan jeda saat autentikasi terus ditolak. Penambahan nilai acak pada jeda adalah rekomendasi berikutnya; loop sumber yang ditinjau belum menerapkannya. Berikut pola dan batasnya:
- Jeda yang makin panjang (exponential backoff). Setiap kali gagal, tunggu lebih lama: 3, 9, 27, lalu 81 detik, dengan jeda dasar maksimal 5 menit. Pada contoh dengan nilai acak di bawah, jeda total dapat mendekati 6 menit. Kamera yang mati cukup "mengetuk" sekali dalam beberapa menit, bukan setiap beberapa detik.
- Nilai aktivitas media, bukan hanya lamanya sambungan. Kamera mati di belakang NVR yang hidup bisa menerima sambungan, lalu diam sampai batas waktu habis semenit kemudian. Penghitung bita media membantu menentukan kapan jeda kembali ke 3 detik. Namun, penghitung pada implementasi ini mencakup paket RTP dan RTCP; kenaikannya tidak membuktikan gambar berhasil didekode atau ditampilkan. Untuk status gambar, periksa paket video atau hasil dekode secara terpisah.
- Pertimbangkan nilai acak pada setiap jeda (jitter). Analisis Marc Brooker di AWS Architecture Blog (Maret 2015) menunjukkan jeda yang diacak jauh mengurangi perebutan dibanding jeda bertingkat biasa. Tanpa acakan, empat puluh kamera yang gagal bersama akan mencoba ulang bersama pula.
- Berhenti sejenak jika kata sandi ditolak berulang kali. Pada sambungan kejadian, tiga kegagalan autentikasi HTTP 401 berturut-turut setelah penanganan autentikasi membuat NVR itu didiamkan 15 menit. Tantangan awal autentikasi Digest tidak dihitung sebagai kata sandi yang salah. Perilaku penguncian akun bergantung pada model dan pengaturan perekam. Akun admin yang terkunci di lokasi jauh lebih merepotkan daripada jeda singkat pada data kejadian.
Contoh berikut menyederhanakan loop jeda ulang dan menambahkan rekomendasi jitter. Contoh ini memakai math/rand/v2 (Go 1.22 atau lebih baru), bukan salinan lengkap kode produksi. received menghitung bita media; pull harus menangani pembatalan context dan penutupan sambungan. Jeda autentikasi 15 menit dan penjaga waktu HTTP diterapkan terpisah:
wait := 3 * time.Second
for ctx.Err() == nil {
before := received.Load()
err := pull(ctx, stream, &received) // selesai saat sambungan berakhir
if ctx.Err() != nil {
return
}
if received.Load() > before { // ada aktivitas media; bukan bukti gambar tampil
wait = 3 * time.Second
}
jitter := time.Duration(rand.Int64N(int64(wait / 5)))
delay := wait + jitter
log.Printf("%s: %v (ulang dalam %s)", stream, err, delay)
select {
case <-ctx.Done():
return
case <-time.After(delay):
}
wait = min(wait*3, 5*time.Minute)
}
Masih ada satu kegagalan yang perlu dijaga, yaitu sambungan yang mati diam-diam. Sambungan kejadian ke NVR bisa tampak "terbuka" padahal tidak ada data yang mengalir, misalnya setelah switch menyala ulang. Penjaga waktu pada sistem ini menutupnya setelah 10 menit tanpa satu bita pun, lalu menyambung lagi. Ini kebijakan pemulihan, bukan bukti pasti bahwa perangkat mati: sambungan tanpa kejadian juga dapat sepi. Sesuaikan ambang dengan perilaku pesan penanda aktif (heartbeat) dari model NVR yang dipakai.
Apa yang terjadi jika satu PC operator lambat?
Di sini berlaku konsep backpressure, yaitu cara sistem bersikap ketika penerima tidak bisa mengimbangi pengirim. Bayangkan antrean di kasir supermarket. Satu pembeli yang menghitung uang receh tidak boleh membuat semua kasir lain ikut berhenti.
Kejadian gerakan dikirim ke semua PC operator yang tersambung. Setiap PC punya penampung kecil berisi 64 kejadian. Jika penampung satu PC penuh, kejadian untuk PC itu dibuang, dan pengiriman ke PC lain tetap berjalan. Potongan berikut hanya menunjukkan pengiriman tanpa menunggu; akses daftar pelanggan dan siklus hidup kanal harus disinkronkan, seperti dengan mutex pada kode sumber:
for ch := range subscribers {
select {
case ch <- event:
default: // PC lambat: buang untuk PC ini saja, jangan tahan yang lain
}
}
Pengiriman langsung ini dapat kehilangan kejadian pada PC yang lambat. Kejadian gerakan dicatat di basis data, tetapi jalur sambung ulang yang ditinjau hanya memutar ulang hingga 200 kejadian terakhir dari memori. Riwayat itu hilang saat server dimulai ulang dan tidak menjamin pemulihan seluruh kejadian. PC yang tetap tersambung setelah penampungnya penuh juga belum tentu menerima ulang kejadian yang terbuang. Jika pemulihan lengkap diperlukan, rancang pembacaan riwayat persisten berdasarkan nomor urut dan penanganan celah data. Untuk alarm keselamatan jiwa, kebutuhan pengiriman berbeda; lihat rancangan nurse call dan code blue.
Dua penjaga lain menahan lonjakan dari sisi operator:
- Pesan dulu, baru hitung. Saat operator membuka tampilan 25 kotak, 25 permintaan tiba dalam hitungan milidetik, sebelum perantara video sempat mencatat satu pun. Pemeriksaan batas yang hanya membaca "tayangan aktif" akan meloloskan semuanya. Karena itu, setiap tayangan yang disetujui dipesan selama 15 detik agar permintaan yang datang bersamaan saling terlihat.
- Tahan tayangan sebentar setelah penonton terakhir pergi. Operator sering berpindah tampilan. Jika tayangan tetap tersambung satu menit setelah penonton terakhir pergi, operator dapat kembali tanpa membuka sambungan RTSP baru ke NVR. Gambar tetap dapat terlambat muncul karena gambar kunci, pengiriman data, atau proses tampilan di peramban. Selama semenit itu, sambungan tetap memakai kapasitas jaringan, pemrosesan, dan penampung data. Manfaatnya adalah menghindari pembukaan ulang sambungan saat operator kembali.
Bagaimana mencegah tugas latar yang tak pernah selesai?
Goroutine yang bocor adalah tugas yang menunggu selamanya sesuatu yang tidak akan pernah terjadi: channel yang tidak pernah diisi, atau sambungan yang tidak pernah ditutup. Kamera di sistem ini bisa ditambah, diubah, dan dihapus dari layar admin. Karena itu, setiap pengawas kamera harus punya jalan keluar.
Polanya adalah satu context yang bisa dibatalkan untuk setiap kamera atau NVR. Saat kamera diubah, context-nya dibatalkan. Fungsi pembaca secara eksplisit menutup sambungan ketika menerima sinyal ctx.Done(), sehingga perulangannya dapat berhenti. Pembatalan context saja tidak otomatis menutup semua koneksi jaringan. Perulangan baru kemudian memakai pengaturan terbaru, dan catatan pengawas lama dibersihkan saat tugasnya selesai.
Fungsi pembaca yang ditinjau masih memiliki celah pembersihan: setiap percobaan sambungan membuat tugas pembantu yang menunggu berakhirnya context kamera. Jika sambungan putus lebih dahulu, menutup soket tidak menghentikan tugas pembantu tersebut. Percobaan ulang dapat menumpuk tugas yang menunggu hingga context kamera dibatalkan. Perbaikannya adalah memakai context khusus per percobaan sambungan dan membatalkannya saat percobaan selesai, agar tugas pembantu ikut berhenti. Ini rekomendasi perbaikan, bukan perilaku yang sudah dimiliki implementasi tersebut.
Dua perubahan Go berikut membantu di bagian ini:
- Go 1.26 (Februari 2026) menambah profil eksperimental
goroutineleak. Profil ini melaporkan goroutine yang tertahan di channel atau mutex dan tidak mungkin lepas lagi. Fitur ini dinyalakan saat kompilasi denganGOEXPERIMENT=goroutineleakprofile. Pada Go 1.26, fitur ini dapat dicoba saat kompilasi di lingkungan pengujian untuk program pengawas yang berjalan lama. Profil tersebut tidak mendeteksi semua jenis kebocoran. - Go 1.25 (Agustus 2025) membuat
GOMAXPROCS, batas jumlah CPU logis yang menjalankan kode Go secara bersamaan, mempertimbangkan batas CPU container di Linux secara bawaan. Misalnya, batas 2 CPU dapat membatasi paralelisme meski mesin memiliki 16 CPU logis. Pengaturan manualGOMAXPROCSatau kompatibilitas modul dapat menonaktifkan perilaku bawaan ini.
Daftar periksa sebelum menambah kamera ke-121
| Periksa | Pertanyaan yang perlu dijawab |
|---|---|
| Sambungan per perangkat | Apakah kamera baru menambah sambungan ke NVR, atau memakai sambungan bersama per NVR? |
| Batas perekam | Berapa batas kapasitas kirim, sesi, dan putar ulang di lembar spesifikasi, dan sudahkah diuji di lokasi? |
| Jeda sambung ulang | Apakah kamera mati memakai jeda bertingkat, dan apakah penambahan jeda acak sudah diterapkan serta diuji? |
| Tanda sehat | Apakah aktivitas media dibedakan dari bukti bahwa gambar dapat ditampilkan? |
| PC lambat | Bisakah PC lambat menghambat PC lain, dan bagaimana kejadian yang terlewat dipulihkan? |
| Lonjakan permintaan | Apakah 25 permintaan kotak yang datang bersamaan saling terlihat sebelum disetujui? |
| Siklus hidup | Apakah mengubah atau menghapus kamera ikut menghentikan goroutine dan sambungannya? |
Go membantu mengelola pekerjaan yang berlangsung bersamaan. Ketahanan sistem saat listrik padam tetap bergantung pada kapasitas perekam, pengaturan sambungan ulang, dan pemulihan kejadian yang terlewat. Untuk memantau kesehatan kamera di luar video, seperti uptime dan status port, gabungkan dengan pemantauan CCTV lewat SNMP.
Jika jaringan kamera atau perangkat Anda sudah melampaui kemampuan perangkat lunaknya, mari bahas backend yang dibutuhkan.
Artikel Terkait
Perlu bantuan menerapkan solusi ini?
Pengembangan Sistem Pemantauan Perangkat IoT
Satukan data meter, sensor, dan perangkat lain dalam satu dasbor. Pantau pembacaan terbaru, riwayat data, dan gangguan sesuai kebutuhan operasional.
Lihat layanan terkaitCeritakan kendala operasional Anda agar kita dapat membahas langkah yang sesuai.