
Sejak awal, kami merencanakan solusi teknik dan produk sehingga Discord sangat cocok untuk obrolan suara saat bermain dengan teman-teman. Solusi ini memungkinkan untuk meningkatkan skala sistem, memiliki tim kecil dan sumber daya terbatas.
Artikel ini membahas berbagai teknologi yang digunakan Discord untuk obrolan audio / video.
Untuk kejelasan, kami akan memanggil seluruh grup pengguna dan menyalurkan "grup" (serikat) - di klien mereka disebut "server". Sebaliknya, istilah "server" mengacu pada infrastruktur server kami.Prinsip utama
Setiap obrolan audio / video dalam Perselisihan mendukung banyak peserta. Kami menyaksikan seribu orang mengobrol dalam obrolan grup besar. Dukungan semacam itu membutuhkan arsitektur klien-server, karena jaringan peer-to-peer peer-to-peer menjadi sangat mahal dengan peningkatan jumlah peserta.
Routing lalu lintas jaringan melalui server Discord juga memastikan bahwa alamat IP Anda tidak pernah terlihat - dan tidak ada yang akan meluncurkan serangan DDoS. Routing melalui server memiliki kelebihan lain: misalnya, moderasi. Administrator dapat dengan cepat mematikan suara dan video ke pengganggu.
Arsitektur klien
Perselisihan berjalan di banyak platform.
- Web (Chrome / Firefox / Edge, dll.)
- Aplikasi mandiri (Windows, MacOS, Linux)
- Telepon (iOS / Android)
Kami dapat mendukung semua platform ini hanya dalam satu cara: melalui penggunaan kembali kode
WebRTC . Spesifikasi untuk komunikasi waktu-nyata ini mencakup komponen jaringan, audio, dan video. Standar ini diadopsi
oleh World Wide Web Consortium dan
Internet Engineering Group . WebRTC tersedia di semua browser modern dan sebagai pustaka asli untuk implementasi dalam aplikasi.
Audio dan video dalam Discord berjalan di WebRTC. Dengan demikian, aplikasi browser bergantung pada implementasi WebRTC di browser. Namun, aplikasi untuk desktop, iOS dan Android menggunakan mesin multimedia C ++ tunggal yang dibangun di atas pustaka WebRTC mereka sendiri, yang secara khusus disesuaikan dengan kebutuhan pengguna kami. Ini berarti bahwa beberapa fungsi dalam aplikasi berfungsi lebih baik daripada di browser. Misalnya, dalam aplikasi asli kami, kami dapat:
- Bypass Volume Windows Mute secara default, ketika semua aplikasi secara otomatis dimatikan saat menggunakan headset . Ini tidak diinginkan ketika Anda dan teman Anda melakukan razia dan mengoordinasi kegiatan obrolan Discord.
- Gunakan kontrol volume Anda sendiri alih-alih mixer sistem operasi global.
- Memproses data audio asli untuk mendeteksi aktivitas suara dan menyiarkan audio dan video dalam game.
- Kurangi konsumsi bandwidth dan CPU selama periode hening - bahkan dalam obrolan suara paling banyak pada waktu tertentu, hanya beberapa orang yang berbicara pada saat yang sama.
- Menyediakan fungsionalitas seluruh sistem untuk mode push to talk.
- Kirimkan bersama paket audio-video informasi tambahan (misalnya, indikator prioritas dalam obrolan).
Memiliki versi WebRTC Anda sendiri berarti pembaruan yang sering dilakukan untuk semua pengguna: ini adalah proses yang memakan waktu yang kami coba lakukan secara otomatis. Namun, upaya ini terbayar berkat fitur khusus untuk pemain kami.
Dalam Perselisihan, komunikasi suara dan video dimulai dengan memasukkan saluran suara atau panggilan. Artinya, koneksi selalu diprakarsai oleh klien - ini mengurangi kompleksitas bagian klien dan server, dan juga meningkatkan toleransi kesalahan. Jika terjadi kegagalan infrastruktur, peserta dapat menyambung kembali ke server internal baru.
Di bawah kendali kami
Kontrol perpustakaan asli memungkinkan Anda untuk mengimplementasikan beberapa fungsi secara berbeda dari pada implementasi browser WebRTC.
Pertama, WebRTC mengandalkan Session Description Protocol (
SDP ) untuk menegosiasikan audio / video antara peserta (hingga 10 KB per pertukaran paket). Di perpustakaannya sendiri, API tingkat rendah dari WebRTC (
webrtc::Call
) digunakan untuk membuat aliran - masuk dan keluar. Ketika terhubung ke saluran suara, ada pertukaran informasi yang minimal. Ini adalah alamat dan port server backend, metode enkripsi, kunci, codec dan identifikasi aliran (sekitar 1000 byte).
webrtc::AudioSendStream* createAudioSendStream( uint32_t ssrc, uint8_t payloadType, webrtc::Transport* transport, rtc::scoped_refptr<webrtc::AudioEncoderFactory> audioEncoderFactory, webrtc::Call* call) { webrtc::AudioSendStream::Config config{transport}; config.rtp.ssrc = ssrc; config.rtp.extensions = {{"urn:ietf:params:rtp-hdrext:ssrc-audio-level", 1}}; config.encoder_factory = audioEncoderFactory; const webrtc::SdpAudioFormat kOpusFormat = {"opus", 48000, 2}; config.send_codec_spec = webrtc::AudioSendStream::Config::SendCodecSpec(payloadType, kOpusFormat); webrtc::AudioSendStream* audioStream = call->CreateAudioSendStream(config); audioStream->Start(); return audioStream; }
Selain itu, WebRTC menggunakan Interactive Connectivity Establishment (
ICE ) untuk menentukan rute terbaik antara peserta. Karena kami memiliki setiap klien yang terhubung ke server, kami tidak perlu ICE. Ini memungkinkan Anda untuk menyediakan koneksi yang jauh lebih andal jika Anda berada di belakang NAT, dan juga merahasiakan alamat IP Anda dari peserta lain. Klien secara berkala melakukan ping agar firewall mempertahankan koneksi terbuka.
Akhirnya, WebRTC menggunakan Protokol Transport Real-time Aman (
SRTP ) untuk mengenkripsi media. Kunci enkripsi diatur menggunakan protokol Datagram Transport Layer Security (
DTLS ) berdasarkan TLS standar. Pustaka WebRTC bawaan memungkinkan Anda untuk mengimplementasikan lapisan transport Anda sendiri menggunakan
webrtc::Transport
API.
Alih-alih DTLS / SRTP, kami memutuskan untuk menggunakan
enkripsi Salsa20 lebih cepat. Selain itu, kami tidak mengirim data audio selama periode hening - kejadian umum, terutama di ruang obrolan besar. Ini mengarah pada penghematan yang signifikan dalam bandwidth dan sumber daya CPU, namun, baik klien dan server harus siap kapan saja untuk berhenti menerima data dan menulis ulang nomor seri paket audio / video.
Karena aplikasi web menggunakan implementasi
API WebRTC berbasis web, SDP, ICE, DTLS, dan SRTP tidak dapat diabaikan. Klien dan server bertukar semua informasi yang diperlukan (kurang dari 1200 byte saat bertukar paket) - dan sesi SDP dibuat berdasarkan informasi ini untuk klien. Backend bertanggung jawab untuk menyelesaikan perbedaan antara aplikasi desktop dan browser.
Arsitektur backend
Ada beberapa layanan obrolan suara di backend, tetapi kami akan fokus pada tiga: Discord Gateway, Discord Guilds dan Discord Voice. Semua server sinyal kami ditulis dalam
Elixir , yang memungkinkan kami untuk menggunakan kembali kode berulang kali.
Saat Anda online, klien Anda mendukung koneksi WebSocket ke Discord Gateway (kami menyebutnya koneksi
gateway WebSocket). Melalui koneksi ini, klien Anda menerima acara yang terkait dengan grup dan saluran, pesan teks, paket kehadiran, dll.
Saat terhubung ke saluran suara, status koneksi ditampilkan oleh
objek status suara. Klien memperbarui objek ini melalui koneksi gateway.
defmodule VoiceStates.VoiceState do @type t :: %{ session_id: String.t(), user_id: Number.t(), channel_id: Number.t() | nil, token: String.t() | nil, mute: boolean, deaf: boolean, self_mute: boolean, self_deaf: boolean, self_video: boolean, suppress: boolean } defstruct session_id: nil, user_id: nil, token: nil, channel_id: nil, mute: false, deaf: false, self_mute: false, self_deaf: false, self_video: false, suppress: false end
Saat terhubung ke saluran suara, Anda ditugaskan ke salah satu server Voice Discord. Dia bertanggung jawab untuk mentransmisikan suara ke setiap peserta di saluran. Semua saluran suara dalam grup ditugaskan ke satu server. Jika Anda yang pertama mengobrol, server Perselisihan Perselisihan bertanggung jawab untuk menetapkan server Suara Perselisihan untuk seluruh grup menggunakan proses yang dijelaskan di bawah ini.
Perselisihan Tujuan Server Suara
Setiap server Discord Voice secara berkala melaporkan status dan pemuatannya. Informasi ini ditempatkan dalam sistem penemuan layanan (kami menggunakan
etcd ), seperti yang dibahas dalam
artikel sebelumnya .
Server Discord Guilds memonitor sistem penemuan layanan dan memberikan grup Discord Voice server yang paling sedikit digunakan di wilayah tersebut. Ketika dipilih, semua objek status suara (juga didukung oleh server Discord Guilds) ditransfer ke server Voice Discord sehingga dapat mengkonfigurasi penerusan audio / video. Klien diberi tahu server Discord Voice yang dipilih. Kemudian klien membuka koneksi WebSocket
kedua dengan server suara (kami menyebutnya koneksi
suara WebSocket), yang digunakan untuk mengonfigurasi penerusan multimedia dan indikasi ucapan.
Ketika klien menampilkan status
Endpoint Menunggu , ini berarti bahwa server Discord Guilds sedang mencari server Voice Discord yang optimal. Pesan
Voice Connected menunjukkan bahwa klien telah berhasil menukar paket UDP dengan server Voice Discord yang dipilih.
Server Suara Discord berisi dua komponen: modul sinyal dan unit relai multimedia, yang disebut unit penerusan selektif (
SFU ). Modul sinyal sepenuhnya mengontrol SFU dan bertanggung jawab untuk menghasilkan pengidentifikasi aliran dan kunci enkripsi, mengarahkan indikator bicara, dll.
SFU kami (dalam C ++) bertanggung jawab untuk mengarahkan lalu lintas audio dan video antar saluran. Ini dikembangkan sendiri: untuk kasus khusus kami, SFU memberikan kinerja maksimum dan, dengan demikian, penghematan terbesar. Ketika moderator melanggar (membisukan server), paket audio mereka tidak diproses. SFU juga berfungsi sebagai jembatan antara aplikasi asli dan berbasis browser: ia mengimplementasikan transportasi dan enkripsi untuk aplikasi browser dan asli, mengonversi paket selama transmisi. Akhirnya, SFU bertanggung jawab untuk memproses protokol
RTCP , yang digunakan untuk mengoptimalkan kualitas video. SFU mengumpulkan dan memproses laporan RTCP dari penerima - dan memberi tahu pengirim pita mana yang tersedia untuk transmisi video.
Toleransi kesalahan
Karena hanya server Voice Discord yang tersedia langsung dari Internet, kami akan membicarakannya.
Modul sinyal terus memonitor SFU. Jika crash, ia langsung restart dengan jeda minimum dalam layanan (beberapa paket hilang). Status SFU dipulihkan oleh modul sinyal tanpa ada interaksi dengan klien. Meskipun crash SFU jarang terjadi, kami menggunakan mekanisme yang sama untuk memperbarui SFU tanpa gangguan dalam layanan.
Ketika server Voice Discord crash, itu tidak menanggapi ping - dan dihapus dari sistem penemuan layanan. Klien juga melihat server crash karena koneksi suara WebSocket yang rusak, kemudian meminta
ping server suara melalui koneksi gateway WebSocket. Server Discord Guilds mengkonfirmasi kegagalan, berkonsultasi dengan sistem penemuan layanan, dan menetapkan server Voice Discord baru untuk grup. Kelompok Perselisihan kemudian mengirim semua objek status suara ke server suara baru. Semua klien menerima pemberitahuan tentang server baru dan terhubung ke sana untuk memulai pengaturan multimedia.

Cukup sering, server Voice Discord berada di bawah DDoS (kita melihat ini dengan peningkatan cepat dalam paket IP yang masuk). Dalam hal ini, kami melakukan prosedur yang sama seperti ketika server crash: kami menghapusnya dari sistem penemuan layanan, memilih server baru, mentransfer semua objek keadaan komunikasi suara ke sana dan memberi tahu klien tentang server baru. Ketika serangan DDoS mereda, server kembali ke sistem penemuan layanan.
Jika pemilik grup memutuskan untuk memilih wilayah baru untuk pemungutan suara, kami mengikuti prosedur yang sangat mirip. Discord Guilds Server memilih server suara terbaik yang tersedia di wilayah baru dengan berkonsultasi dengan sistem penemuan layanan. Kemudian dia menerjemahkan semua objek dari status komunikasi suara dan memberi tahu klien tentang server baru. Klien memutus koneksi WebSocket saat ini dengan server Voice Discord lama dan membuat koneksi baru dengan server Voice Discord baru.
Scaling
Seluruh infrastruktur Discord Gateway, Discord Guilds dan Discord Voice mendukung penskalaan horizontal. Discord Gateway dan Discord Guilds berfungsi di Google Cloud.
Kami memiliki lebih dari 850 server suara di 13 wilayah (berlokasi di lebih dari 30 pusat data) di seluruh dunia. Infrastruktur ini memberikan redundansi yang lebih besar jika terjadi kegagalan pada pusat data dan DDoS. Kami bekerja dengan beberapa mitra dan menggunakan server fisik kami di pusat data mereka. Baru-baru ini, wilayah Afrika Selatan telah ditambahkan. Berkat upaya rekayasa dalam arsitektur klien dan server, Discord sekarang dapat secara bersamaan melayani lebih dari 2,6 juta pengguna obrolan suara dengan lalu lintas keluar lebih dari 220 Gbit / detik dan 120 juta paket per detik.
Apa selanjutnya
Kami terus memantau kualitas komunikasi suara (metrik dikirim dari sisi klien ke server backend). Di masa depan, informasi ini akan membantu dalam deteksi otomatis dan penghapusan degradasi.
Meskipun kami meluncurkan obrolan dan screencast video setahun yang lalu, tetapi sekarang mereka hanya dapat digunakan dalam pesan pribadi. Dibandingkan dengan audio, video secara signifikan membutuhkan lebih banyak daya CPU dan bandwidth. Tantangannya adalah menyeimbangkan jumlah bandwidth dan sumber daya CPU / GPU yang digunakan untuk memastikan kualitas video terbaik, terutama ketika sekelompok gamer dalam suatu saluran berada di perangkat yang berbeda. Teknologi
Scalable Video Coding (SVC), perpanjangan dari standar AVC H.264 / MPEG-4, dapat menjadi solusi untuk masalah tersebut.
Screencasts bahkan membutuhkan bandwidth lebih banyak daripada video, karena FPS dan resolusi lebih tinggi daripada webcam konvensional. Kami saat ini sedang mengerjakan dukungan untuk encoding video berbasis perangkat keras di aplikasi desktop.