Μετάβαση στο κύριο περιεχόμενο
OpenAI

4 Μαΐου 2026

Πώς η OpenAI παρέχει φωνητική TN χαμηλής καθυστέρησης σε μεγάλη κλίμακα

Από τους Yi Zhang και William McDonald, Μέλη Τεχνικού Προσωπικού

Η φωνητική TN μοιάζει φυσική μόνο όταν η συζήτηση κινείται με την ταχύτητα της ομιλίας. Όταν το δίκτυο παρεμβάλλεται, οι άνθρωποι το αντιλαμβάνονται αμέσως ως αμήχανες παύσεις, κομμένες διακοπές ή καθυστερημένη διακοπή ομιλίας. Αυτό έχει σημασία για τη φωνητική λειτουργία ChatGPT, για προγραμματιστές που χτίζουν με το Realtime API, για πράκτορες που εργάζονται σε διαδραστικές ροές εργασίας και για μοντέλα που πρέπει να επεξεργάζονται ήχο ενώ ο χρήστης εξακολουθεί να μιλά.

Στην κλίμακα της OpenAI, αυτό μεταφράζεται σε τρεις συγκεκριμένες απαιτήσεις:

  • Παγκόσμια κάλυψη για περισσότερους από 900 εκατομμύρια ενεργούς εβδομαδιαίους χρήστες
  • Γρήγορη έναρξη σύνδεσης ώστε ο χρήστης να μπορεί να αρχίσει να μιλά μόλις ξεκινήσει μια περίοδος λειτουργίας
  • Χαμηλός και σταθερός χρόνος διαδρομής μετ’ επιστροφής μέσων, με μικρό jitter και απώλεια πακέτων, ώστε η εναλλαγή σειράς στην ομιλία να είναι άμεση

Η ομάδα της OpenAI που είναι υπεύθυνη για τις αλληλεπιδράσεις TN σε πραγματικό χρόνο ανασχεδίασε πρόσφατα τη στοίβα WebRTC μας για να αντιμετωπίσει τρεις περιορισμούς που άρχισαν να συγκρούονται σε μεγάλη κλίμακα: ο τερματισμός μέσων με μία θύρα ανά περίοδο λειτουργίας δεν ταιριάζει καλά στην υποδομή της OpenAI, οι καταστασιακές περίοδοι λειτουργίας ICE (Interactive Connectivity Establishment) και DTLS (Datagram Transport Layer Security) χρειάζονται σταθερή ιδιοκτησία και η παγκόσμια δρομολόγηση πρέπει να κρατά χαμηλή την καθυστέρηση του πρώτου άλματος. Σε αυτή την ανάρτηση, παρουσιάζουμε τη διαχωρισμένη αρχιτεκτονική relay plus transceiver που δημιουργήσαμε για να διατηρήσουμε την τυπική συμπεριφορά του WebRTC για τους πελάτες, αλλάζοντας παράλληλα τον τρόπο με τον οποίο δρομολογούνται τα πακέτα μέσα στην υποδομή της OpenAI.

Το WebRTC μάς επιτρέπει να δημιουργούμε προϊόντα TN πραγματικού χρόνου

Το WebRTC είναι ένα ανοικτό πρότυπο για την αποστολή ήχου, βίντεο και δεδομένων χαμηλής καθυστέρησης μεταξύ προγραμμάτων περιήγησης, εφαρμογών για κινητά και διακομιστών. Συνδέεται συχνά με κλήσεις peer-to-peer, αλλά αποτελεί επίσης πρακτική βάση για συστήματα πραγματικού χρόνου πελάτη-διακομιστή, επειδή τυποποιεί τα δύσκολα μέρη των διαδραστικών μέσων: ICE για εγκαθίδρυση συνδεσιμότητας και διάσχιση NAT (Network Address Translation), DTLS και SRTP (Secure Real-time Transport Protocol) για κρυπτογραφημένη μεταφορά, διαπραγμάτευση codec για συμπίεση και αποκωδικοποίηση ήχου, RTCP (Real-time Transport Control Protocol) για έλεγχο ποιότητας και λειτουργίες στην πλευρά του πελάτη, όπως ακύρωση ηχούς και buffering jitter.

Αυτή η τυποποίηση έχει σημασία για τα προϊόντα TN. Χωρίς το WebRTC, κάθε πελάτης θα χρειαζόταν διαφορετική απάντηση για το πώς θα εγκαθιστά συνδεσιμότητα μέσω NAT, θα κρυπτογραφεί μέσα, θα διαπραγματεύεται codec (τους κωδικοποιητές-αποκωδικοποιητές που επιλέγονται για μετάδοση και αποσυμπίεση) και θα προσαρμόζεται σε μεταβαλλόμενες συνθήκες δικτύου. Με το WebRTC, μπορούμε να βασιστούμε σε μια στοίβα πρωτοκόλλων που έχει ήδη υλοποιηθεί σε προγράμματα περιήγησης και πλατφόρμες κινητών, εστιάζοντας τη δική μας δουλειά στην υποδομή που συνδέει τα μέσα πραγματικού χρόνου με τα μοντέλα.

Βασιζόμαστε επίσης στο ίδιο το οικοσύστημα του WebRTC, συμπεριλαμβανομένων ώριμων υλοποιήσεων ανοικτού κώδικα και της εργασίας προτυποποίησης που διατηρεί διαλειτουργικά τα προγράμματα περιήγησης, τις εφαρμογές κινητών και τους διακομιστές. Η θεμελιώδης δουλειά των Justin Uberti (ενός από τους αρχικούς αρχιτέκτονες του WebRTC) και Sean DuBois (δημιουργού και συντηρητή του Pion) κατέστησε δυνατό για ομάδες όπως η δική μας να βασιστούν σε δοκιμασμένη υποδομή μέσων αντί να επανεφεύρουν τη χαμηλού επιπέδου μεταφορά, κρυπτογράφηση και συμπεριφορά ελέγχου συμφόρησης. Είμαστε τυχεροί που τόσο ο Justin όσο και ο Sean είναι πλέον συνάδελφοί μας εδώ στην OpenAI, βοηθώντας να καθοδηγηθεί ο τρόπος με τον οποίο φέρνουμε το WebRTC και την TN πραγματικού χρόνου πιο κοντά.

Για την TN, η σημαντικότερη ιδιότητα είναι ότι ο ήχος φτάνει ως συνεχής ροή. Ένας πράκτορας που μιλά μπορεί να αρχίσει μεταγραφή, συλλογιστική, κλήση εργαλείων ή παραγωγή ομιλίας ενώ ο χρήστης εξακολουθεί να μιλά, αντί να περιμένει πλήρη μεταφόρτωση. Αυτή είναι η διαφορά ανάμεσα σε ένα σύστημα που μοιάζει συνομιλιακό και σε ένα που μοιάζει με push-to-talk.

Επιλογή αρχιτεκτονικής μέσων

Αφού επιλέξαμε το WebRTC, το επόμενο ερώτημα ήταν πού να το τερματίζουμε (πού θα δεχόμασταν και θα κατείχαμε τη σύνδεση WebRTC — για παράδειγμα, στο edge) και πώς να συνδέουμε αυτές τις περιόδους λειτουργίας με το backend συμπερασματολογίας. Ο τερματισμός έχει σημασία επειδή καθορίζει πώς διαχειριζόμαστε την κατάσταση της περιόδου λειτουργίας πραγματικού χρόνου, τη μεταφορά μέσων, τη δρομολόγηση, την καθυστέρηση και την απομόνωση αστοχιών.

Επιλογή 1: Η προσέγγιση SFU περιλαμβάνει την TN ως συμμετέχοντα WebRTC

Ένα SFU, ή selective forwarding unit, είναι ένας διακομιστής μέσων που λαμβάνει μία ροή WebRTC από κάθε συμμετέχοντα και προωθεί επιλεκτικά ροές στους υπόλοιπους. Σε αυτό το μοντέλο, το SFU τερματίζει ξεχωριστή σύνδεση WebRTC για κάθε συμμετέχοντα και η TN συμμετέχει ως ακόμη ένας συμμετέχων στην περίοδο λειτουργίας. Αυτό μπορεί να ταιριάζει καλά σε προϊόντα που είναι εγγενώς πολυμερή, όπως ομαδικές κλήσεις, αίθουσες διδασκαλίας ή συνεργατικές συναντήσεις. Κρατά τους κωδικοποιητές ήχου, τα μηνύματα RTCP, τα κανάλια δεδομένων, την καταγραφή και την πολιτική ανά ροή σε ένα μέρος.1

Ακόμη και σε προϊόντα πελάτη προς TN, ένα SFU είναι συχνά το προεπιλεγμένο σημείο εκκίνησης, επειδή επιτρέπει στις ομάδες να επαναχρησιμοποιούν ένα αποδεδειγμένο σύστημα για σηματοδότηση, δρομολόγηση μέσων, καταγραφή, παρατηρησιμότητα και μελλοντικές επεκτάσεις όπως παράδοση σε άνθρωπο ή προσθήκη περισσότερων συμμετεχόντων.

Επιλογή 2: Η προσέγγιση transceiver τερματίζει το WebRTC στο edge και το μετατρέπει σε πρωτόκολλο backend

Ο δικός μας φόρτος εργασίας είναι διαφορετικός. Οι περισσότερες περίοδοι λειτουργίας είναι 1:1 — ένας χρήστης που μιλά με ένα μοντέλο ή μία εφαρμογή που μιλά με έναν πράκτορα πραγματικού χρόνου — με ευαισθησία στην καθυστέρηση σε κάθε εναλλαγή. Για αυτό το σχήμα κίνησης, επιλέξαμε ένα μοντέλο transceiver: μια υπηρεσία edge WebRTC τερματίζει τη σύνδεση του πελάτη και στη συνέχεια μετατρέπει τα μέσα και τα συμβάντα σε απλούστερα εσωτερικά πρωτόκολλα για συμπερασματολογία μοντέλου, μεταγραφή, παραγωγή ομιλίας, χρήση εργαλείων και ενορχήστρωση.

Σε αυτό το σχέδιο, ο transceiver είναι η μόνη υπηρεσία που κατέχει την κατάσταση της περιόδου λειτουργίας WebRTC, συμπεριλαμβανομένων των ελέγχων συνδεσιμότητας ICE, της χειραψίας DTLS, των κλειδιών κρυπτογράφησης SRTP και του κύκλου ζωής της περιόδου λειτουργίας. Ο «τερματισμός» εδώ σημαίνει ότι ο transceiver είναι το τελικό σημείο που ολοκληρώνει αυτές τις χειραψίες και κρυπτογραφεί ή αποκρυπτογραφεί τα μέσα. Η διατήρηση αυτής της κατάστασης σε ένα μέρος έκανε ευκολότερη τη συλλογιστική γύρω από την ιδιοκτησία της περιόδου λειτουργίας και επέτρεψε στις υπηρεσίες backend να κλιμακώνονται όπως συνηθισμένες υπηρεσίες αντί να λειτουργούν οι ίδιες ως ομότιμοι WebRTC.

Το βασικό πρόβλημα ανάπτυξης: το WebRTC συναντά το Kubernetes

Αφού επιλέξαμε το μοντέλο transceiver, η πρώτη μας υλοποίηση ήταν μία υπηρεσία Go βασισμένη στο Pion που χειριζόταν τόσο τη σηματοδότηση όσο και τον τερματισμό μέσων. Τροφοδοτεί τη φωνητική λειτουργία ChatGPT, το τελικό σημείο WebRTC του Realtime API και έναν αριθμό ερευνητικών έργων.

Λειτουργικά, η υπηρεσία transceiver εκτελεί δύο εργασίες:

  • Σηματοδότηση: διαπραγμάτευση SDP, επιλογή codec, διαπιστευτήρια ICE και ρύθμιση περιόδου λειτουργίας
  • Μέσα: τερματισμός καθοδικών συνδέσεων WebRTC και διατήρηση ανοδικών συνδέσεων προς υπηρεσίες backend για συμπερασματολογία και ενορχήστρωση

Θέλαμε η υπηρεσία να εκτελείται όπως και το υπόλοιπο της υποδομής μας: σε Kubernetes, όπου τα φορτία εργασίας μπορούν να αυξομειώνονται και να μετακινούνται μεταξύ κεντρικών υπολογιστών καθώς αλλάζει η ζήτηση. Όμως το συμβατικό μοντέλο WebRTC μίας θύρας ανά περίοδο λειτουργίας ταιριάζει άσχημα σε αυτό το περιβάλλον, επειδή εξαρτάται από μεγάλα εύρη δημόσιων θυρών UDP που είναι δύσκολο να εκτεθούν, να ασφαλιστούν και να διατηρηθούν καθώς pods προστίθενται, αφαιρούνται ή επαναπρογραμματίζονται.2

Εξάντληση θυρών

Το πρώτο πρόβλημα ήταν το ίδιο το μοντέλο μίας θύρας ανά περίοδο λειτουργίας. Σε υψηλή ταυτόχρονη χρήση, αυτό σημαίνει έκθεση και διαχείριση πολύ μεγάλων εύρων θυρών UDP.

  • Οι εξισορροπητές φορτίου cloud και οι υπηρεσίες Kubernetes δεν έχουν σχεδιαστεί γύρω από δεκάδες χιλιάδες δημόσιες θύρες UDP ανά υπηρεσία. Κάθε πρόσθετο εύρος αυξάνει τη λειτουργική πολυπλοκότητα στη ρύθμιση του load balancer, στον έλεγχο υγείας, στην πολιτική τείχους προστασίας και στην ασφάλεια των αναπτύξεων.3
  • Τα μεγάλα εύρη θυρών UDP είναι δύσκολο να ασφαλιστούν επειδή επεκτείνουν την εξωτερικά προσβάσιμη επιφάνεια και καθιστούν δυσκολότερο τον έλεγχο της πολιτικής δικτύου.
  • Είναι επίσης κακή προσαρμογή για την αυτόματη κλιμάκωση. Pods προστίθενται, αφαιρούνται και επαναπρογραμματίζονται συνεχώς στο Kubernetes. Η απαίτηση κάθε pod να δεσμεύει και να διαφημίζει ένα μεγάλο σταθερό εύρος θυρών καθιστά αυτή την ελαστικότητα εύθραυστη.4

Γι’ αυτό πολλά συστήματα WebRTC κινούνται προς μία μόνο θύρα UDP ανά διακομιστή, με αποπολυπλεξία σε επίπεδο εφαρμογής πίσω από αυτή τη θύρα.5

Προσκόλληση κατάστασης

Τα σχέδια μίας θύρας ανά διακομιστή λύνουν τον αριθμό θυρών, αλλά εισάγουν ένα δεύτερο πρόβλημα: τη διατήρηση της ιδιοκτησίας κάθε περιόδου λειτουργίας σε όλο τον στόλο.

Τα ICE και DTLS είναι πρωτόκολλα με κατάσταση. Η διεργασία που δημιούργησε μια περίοδο λειτουργίας πρέπει να συνεχίσει να λαμβάνει τα πακέτα αυτής της περιόδου λειτουργίας ώστε να μπορεί να επικυρώνει ελέγχους συνδεσιμότητας, να ολοκληρώνει τη χειραψία DTLS, να αποκρυπτογραφεί SRTP και να επεξεργάζεται μεταγενέστερες αλλαγές περιόδου λειτουργίας όπως επανεκκινήσεις ICE. Αν τα πακέτα της ίδιας περιόδου λειτουργίας καταλήξουν σε διαφορετική διεργασία, η εγκατάσταση μπορεί να αποτύχει ή τα μέσα να διακοπούν.

Αυτό μάς έδωσε έναν συγκεκριμένο στόχο: να εκθέσουμε μια μικρή, σταθερή επιφάνεια UDP στο δημόσιο διαδίκτυο, ενώ θα εξακολουθούμε να δρομολογούμε κάθε πακέτο στον transceiver που κατέχει την αντίστοιχη περίοδο λειτουργίας WebRTC.

Σύγκριση αρχιτεκτονικών μέσων WebRTC

Αξιολογήσαμε διάφορους τρόπους για να το πετύχουμε, συμπεριλαμβανομένου του TURN (Traversal Using Relays around NAT), όπου ένα edge relay τερματίζει εκχωρήσεις πελάτη και προωθεί την κίνηση για λογαριασμό τους.2

Προσέγγιση

Πλεονεκτήματα

Μειονεκτήματα

Μοναδική IP:θύρα ανά περίοδο λειτουργίας (γνωστή και ως εγγενές άμεσο UDP)

Άμεση διαδρομή μέσων πελάτη-διακομιστή

Χωρίς επίπεδο προώθησης στη διαδρομή δεδομένων

Απαιτεί μία δημόσια θύρα UDP ανά περίοδο λειτουργίας

Τα μεγάλα εύρη θυρών είναι δύσκολο να εκτεθούν και να ασφαλιστούν

Κακή προσαρμογή για Kubernetes και εξισορροπητές φορτίου cloud

Μοναδική IP:θύρα ανά διακομιστή

Πολύ μικρότερο δημόσιο αποτύπωμα UDP από την έκθεση ανά περίοδο λειτουργίας

Ένα κοινόχρηστο socket ανά διακομιστή μπορεί να αποπολυπλέκει πολλές περιόδους λειτουργίας

Λειτουργεί καθαρά σε έναν μόνο κεντρικό υπολογιστή, αλλά όχι από μόνο του σε έναν κοινόχρηστο στόλο πίσω από εξισορρόπηση φορτίου

Η αποπολυπλεξία περιόδων λειτουργίας σε έναν μόνο κεντρικό υπολογιστή βοηθά μόνο αφού ένα πακέτο φτάσει σε αυτόν τον κεντρικό υπολογιστή· σε έναν στόλο με εξισορρόπηση φορτίου, το πρώτο πακέτο μπορεί και πάλι να καταλήξει σε λάθος παρουσία, οπότε εξακολουθείτε να χρειάζεστε έναν ντετερμινιστικό τρόπο για να κατευθύνετε κάθε περίοδο λειτουργίας στη διεργασία που την κατέχει


Relay TURN (με τερματισμό πρωτοκόλλου)

Οι πελάτες χρειάζεται μόνο να φτάνουν στη διεύθυνση και τη θύρα του relay TURN

Μπορεί να συγκεντρώσει την πολιτική στο edge

Οι εκχωρήσεις TURN προσθέτουν διαδρομές μετ’ επιστροφής στη ρύθμιση

Η μετακίνηση ή ανάκτηση εκχωρήσεων μεταξύ διακομιστών TURN εξακολουθεί να είναι δύσκολη

Προωθητής χωρίς κατάσταση + τερματιστής με κατάσταση (relay + transceiver της OpenAI)

Μικρό δημόσιο αποτύπωμα UDP

Ο transceiver εξακολουθεί να κατέχει την πλήρη περίοδο λειτουργίας WebRTC

Προσθέτει ένα άλμα προώθησης πριν τα μέσα φτάσουν στον transceiver που κατέχει τη σύνδεση

Απαιτεί προσαρμοσμένο συντονισμό μεταξύ relay και transceiver

Επισκόπηση αρχιτεκτονικής: relay + transceiver

Η αρχιτεκτονική που διαθέσαμε διαχωρίζει τη δρομολόγηση πακέτων από τον τερματισμό πρωτοκόλλου. Η σηματοδότηση εξακολουθεί να φτάνει στον transceiver για τη ρύθμιση της περιόδου λειτουργίας, ενώ τα μέσα εισέρχονται πρώτα μέσω του relay. Το relay είναι ένα ελαφρύ επίπεδο προώθησης UDP με μικρό δημόσιο αποτύπωμα και ο transceiver είναι το καταστασιακό τελικό σημείο WebRTC πίσω από αυτό.

Το relay προωθεί πακέτα χωρίς κατάσταση στον transceiver

Το relay δεν αποκρυπτογραφεί μέσα, δεν εκτελεί μηχανές κατάστασης ICE και δεν συμμετέχει στη διαπραγμάτευση codec. Διαβάζει αρκετά μεταδεδομένα πακέτου ώστε να επιλέξει προορισμό και μετά προωθεί το πακέτο στον transceiver που κατέχει την περίοδο λειτουργίας. Ο transceiver εξακολουθεί να βλέπει μια κανονική ροή WebRTC και εξακολουθεί να κατέχει όλη την κατάσταση του πρωτοκόλλου. Από την οπτική του πελάτη, τίποτα στη συνεδρία WebRTC δεν αλλάζει.

Δρομολόγηση βάσει διαπιστευτηρίων ICE

Η δρομολόγηση του πρώτου πακέτου είναι το βασικό βήμα σε αυτή τη διάταξη. Ένα relay πρέπει να δρομολογήσει το πρώτο πακέτο από έναν πελάτη πριν υπάρξει οποιαδήποτε περίοδος λειτουργίας στην ίδια τη διαδρομή του πακέτου, αντί να σταματήσει σε μια εξωτερική υπηρεσία αναζήτησης.

Κάθε περίοδος λειτουργίας WebRTC φέρει ήδη ένα εγγενές στο πρωτόκολλο άγκιστρο δρομολόγησης: το ICE username fragment, ή ufrag, έναν σύντομο αναγνωριστικό που ανταλλάσσεται κατά τη ρύθμιση της περιόδου λειτουργίας και επαναλαμβάνεται στους ελέγχους συνδεσιμότητας STUN. Δημιουργούμε το ufrag της πλευράς διακομιστή έτσι ώστε να περιέχει ακριβώς αρκετά μεταδεδομένα δρομολόγησης ώστε το relay να μπορεί να συμπεράνει το σύμπλεγμα προορισμού και τον transceiver που κατέχει τη σύνδεση.

Το διάγραμμα ακολουθίας δείχνει πώς εγκαθίσταται η σύνδεση

Κατά τη σηματοδότηση, ο transceiver εκχωρεί κατάσταση περιόδου λειτουργίας και επιστρέφει ένα κοινό relay VIP και θύρα UDP στην απάντηση SDP. Ένα VIP είναι μια εικονική διεύθυνση IP μπροστά από τον στόλο relay· σε συνδυασμό με τη θύρα, δίνει στον πελάτη έναν ενιαίο σταθερό προορισμό, όπως `203.0.113.10:3478`, παρότι πίσω του βρίσκονται πολλές παρουσίες relay. Το πρώτο πακέτο της διαδρομής μέσων από τον πελάτη είναι συνήθως ένα αίτημα δέσμευσης STUN (Session Traversal Utilities for NAT), το οποίο το ICE χρησιμοποιεί για να επαληθεύσει ότι τα πακέτα μπορούν να φτάσουν στη διαφημιζόμενη διεύθυνση.

Το relay αναλύει μόνο όσο χρειάζεται από αυτό το πρώτο πακέτο STUN για να διαβάσει το ufrag του διακομιστή, να αποκωδικοποιήσει την υπόδειξη δρομολόγησης και να προωθήσει το πακέτο στον transceiver που κατέχει τη σύνδεση. Κάθε transceiver ακούει σε κοινόχρηστο socket UDP, δηλαδή ένα τελικό σημείο λειτουργικού συστήματος δεσμευμένο σε εσωτερική IP:θύρα, όχι ένα socket ανά περίοδο λειτουργίας. Αφού το relay δημιουργήσει μια περίοδο λειτουργίας από την πηγαία IP:θύρα του πελάτη προς αυτόν τον προορισμό transceiver, τα επόμενα πακέτα DTLS, RTP και RTCP ρέουν εντός της περιόδου λειτουργίας χωρίς νέα αποκωδικοποίηση του ufrag.

Η περίοδος λειτουργίας του relay είναι σκόπιμα ελάχιστη και αποτελείται μόνο από μια περίοδο λειτουργίας στη μνήμη για την ενημέρωση της προώθησης πακέτων, μαζί με τους απαραίτητους μετρητές για παρακολούθηση και χρονοδιακόπτες για λήξη και καθαρισμό της περιόδου λειτουργίας. Αυτή η σχεδιαστική επιλογή διατηρεί τη δρομολόγηση πακέτων απευθείας πάνω στη διαδρομή πακέτων. Αν ένα relay επανεκκινηθεί και χάσει την περίοδο λειτουργίας, το επόμενο πακέτο STUN αναδομεί την περίοδο λειτουργίας από την υπόδειξη δρομολόγησης του ufrag. Για να γίνει ακόμη πιο αξιόπιστο, χρησιμοποιείται μια cache Redis για να κρατά την αντιστοίχιση <IP + Θύρα πελάτη, IP + Θύρα transceiver> μόλις εγκαθιδρυθεί η διαδρομή, ώστε να μπορεί να ανακτηθεί πολύ νωρίτερα, πριν φτάσει το επόμενο πακέτο STUN.

Global Relay και σηματοδότηση με γεωγραφική κατεύθυνση

Μόλις μειώσαμε τη δημόσια επιφάνεια UDP σε μικρό αριθμό σταθερών διευθύνσεων και θυρών, μπορέσαμε να αναπτύξουμε το ίδιο μοτίβο relay παγκοσμίως. Το Global Relay είναι ο στόλος μας από γεωγραφικά κατανεμημένα σημεία εισόδου relay που εφαρμόζουν όλα την ίδια συμπεριφορά προώθησης πακέτων.

Η ευρεία γεωγραφική είσοδος συντομεύει το πρώτο άλμα από τον πελάτη προς την OpenAI, επειδή ένα πακέτο μπορεί να εισέλθει στο δίκτυό μας σε relay κοντά στον χρήστη, τόσο γεωγραφικά όσο και ως προς την τοπολογία του δικτύου, αντί να διασχίσει πρώτα το δημόσιο διαδίκτυο προς μια μακρινή περιοχή. Στην πράξη, αυτό σημαίνει χαμηλότερη καθυστέρηση, μικρότερο jitter και λιγότερες αποτρέψιμες εκρήξεις απώλειας πριν η κίνηση φτάσει στο backbone μας.6

Το επίπεδο Global Relay λαμβάνει πακέτα από τον πελάτη και τα προωθεί στο σύμπλεγμα transceiver

Χρησιμοποιούμε γεωγραφική και εγγύτητας δρομολόγηση της Cloudflare για σηματοδότηση ώστε το αρχικό αίτημα HTTP ή WebSocket να φτάνει σε κοντινό σύμπλεγμα transceiver. Το πλαίσιο του αιτήματος υπαγορεύει τη θέση της περιόδου λειτουργίας και ποιο σημείο εισόδου Global Relay διαφημίζεται στον πελάτη. Η απάντηση SDP παρέχει τη διεύθυνση Global Relay, ενώ το ufrag περιέχει αρκετές πληροφορίες ώστε το Global Relay να δρομολογεί τα μέσα στο καθορισμένο σύμπλεγμα και το relay να δρομολογεί στον transceiver προορισμού.

Μαζί, η σηματοδότηση με γεωγραφική κατεύθυνση και το Global Relay βάζουν τόσο τη ρύθμιση όσο και τα μέσα σε κοντινή διαδρομή εισόδου, ενώ διατηρούν την περίοδο λειτουργίας αγκυρωμένη σε έναν transceiver. Αυτό μειώνει τον χρόνο διαδρομής μετ’ επιστροφής για τη σηματοδότηση και για τον πρώτο έλεγχο συνδεσιμότητας ICE, κάτι που συντομεύει άμεσα το πόσο περιμένει ο χρήστης πριν μπορέσει να αρχίσει η ομιλία.

Υλοποίηση και επιδόσεις του relay

Γράψαμε την υπηρεσία relay σε Go και κρατήσαμε επίτηδες στενή την υλοποίηση. Στο Linux, η στοίβα δικτύωσης του πυρήνα λαμβάνει πακέτα UDP από τη διεπαφή δικτύου του μηχανήματος και τα παραδίδει σε socket, το τελικό σημείο λειτουργικού συστήματος από το οποίο μια διεργασία διαβάζει μετά από δέσμευση IP:Port. Το relay εκτελείται σε χώρο χρήστη, οπότε μια κανονική διεργασία Go διαβάζει κεφαλίδες πακέτων από αυτό το socket, ενημερώνει μικρή ποσότητα κατάστασης ροής και προωθεί πακέτα χωρίς να τερματίζει το WebRTC. Δεν χρειαστήκαμε κανένα framework παράκαμψης πυρήνα, το οποίο θα επέτρεπε σε διεργασία χώρου χρήστη να ελέγχει απευθείας ουρές δικτύου για υψηλότερους ρυθμούς πακέτων αλλά θα πρόσθετε και λειτουργική πολυπλοκότητα.

Βασικές σχεδιαστικές επιλογές:

  • Χωρίς τερματισμό πρωτοκόλλου: Το relay αναλύει μόνο κεφαλίδες STUN/ufrag· χρησιμοποιεί cache κατάστασης για τα επόμενα DTLS, RTP και RTCP, κρατώντας τα πακέτα αδιαφανή.
  • Εφήμερη κατάσταση: Διατηρεί έναν μικρό, βραχύχρονου timeout, χάρτη στη μνήμη από διεύθυνση πελάτη σε προορισμό transceiver για κατάσταση ροής και παρατηρησιμότητα.
  • Οριζόντια κλιμακωσιμότητα: Πολλές παρουσίες relay εκτελούνται παράλληλα πίσω από load balancer. Η κατάσταση δεν είναι σκληρή κατάσταση WebRTC, οπότε οι επανεκκινήσεις προκαλούν ελάχιστες πτώσεις κίνησης και γρήγορη αποκατάσταση ροών.

Μέτρα αποδοτικότητας:

  • SO_REUSEPORT είναι μια επιλογή socket του Linux που επιτρέπει σε πολλούς workers relay στο ίδιο μηχάνημα να δεσμεύουν την ίδια θύρα UDP. Ο πυρήνας στη συνέχεια κατανέμει τα εισερχόμενα πακέτα μεταξύ αυτών των workers, αποφεύγοντας έτσι ένα μόνο bottleneck βρόχου ανάγνωσης.
  • runtime.LockOSThread καρφιτσώνει κάθε goroutine ανάγνωσης UDP σε συγκεκριμένο νήμα λειτουργικού συστήματος. Σε συνδυασμό με το SO_REUSEPORT, αυτό τείνει να κρατά πακέτα από την ίδια ροή (την πηγαία και προορισμού IP:Port συν το πρωτόκολλο) στον ίδιο πυρήνα CPU, βελτιώνοντας την τοπικότητα cache και μειώνοντας τις εναλλαγές περιβάλλοντος.
  • Προδεσμευμένα buffers και ελάχιστη αντιγραφή κρατούν χαμηλό το κόστος ανάλυσης και εκχώρησης, ώστε να αποφεύγεται η συλλογή απορριμμάτων στη Go.

Αυτή η υλοποίηση χειρίστηκε την παγκόσμια κίνηση μέσων πραγματικού χρόνου μας με σχετικά μικρό αποτύπωμα relay, οπότε κρατήσαμε τον απλούστερο σχεδιασμό αντί να αναλάβουμε μια πορεία παράκαμψης πυρήνα.

Αποτελέσματα και συμπεράσματα

Αυτή η αρχιτεκτονική μάς επιτρέπει να εκτελούμε μέσα WebRTC στο Kubernetes χωρίς να εκθέτουμε χιλιάδες θύρες UDP. Αυτό έχει σημασία επειδή μια μικρότερη και σταθερή επιφάνεια UDP είναι ευκολότερο να ασφαλιστεί και να εξισορροπηθεί ως προς το φορτίο, και επιτρέπει στην υποδομή να κλιμακώνεται χωρίς να δεσμεύει μεγάλα εύρη δημόσιων θυρών. Με καλύτερη υποστήριξη υποδομής από το Kubernetes και μεγαλύτερη ασφάλεια λόγω μικρότερης επιφάνειας, αυτός ο σχεδιασμός διατηρεί επίσης την τυπική συμπεριφορά WebRTC για τους πελάτες και επιβεβαιώνει ότι ένας σχεδιασμός χωρίς SFU ήταν η σωστή προεπιλογή για τον φόρτο εργασίας μας. Οι περισσότερες περίοδοι λειτουργίας μας είναι point-to-point, ευαίσθητες στην καθυστέρηση και κλιμακώνονται ευκολότερα όταν οι υπηρεσίες συμπερασματολογίας δεν χρειάζεται να συμπεριφέρονται ως ομότιμοι WebRTC.

Το ευρύτερο δίδαγμα είναι ότι το καλύτερο μέρος για να προσθέσεις πολυπλοκότητα είναι ένα λεπτό επίπεδο δρομολόγησης, όχι κάθε υπηρεσία backend και όχι προσαρμοσμένη συμπεριφορά πελάτη. Η κωδικοποίηση μεταδεδομένων δρομολόγησης σε ένα πεδίο εγγενές στο πρωτόκολλο μάς έδωσε ντετερμινιστική δρομολόγηση πρώτου πακέτου, μικρό δημόσιο αποτύπωμα UDP και αρκετή ευελιξία ώστε να τοποθετούμε την είσοδο κοντά στους χρήστες σε όλο τον κόσμο.

Μερικές επιλογές ήταν ιδιαίτερα σημαντικές:

  • Διατήρηση της σημασιολογίας του πρωτοκόλλου στο edge. Οι πελάτες εξακολουθούν να μιλούν τυπικό WebRTC, κάτι που διατηρεί ανέπαφη τη διαλειτουργικότητα προγραμμάτων περιήγησης και κινητών.
  • Διατήρηση των δύσκολων καταστάσεων περιόδου λειτουργίας σε ένα μέρος. Ο transceiver κατέχει ICE, DTLS, SRTP και τον κύκλο ζωής της περιόδου λειτουργίας· το relay απλώς προωθεί πακέτα.
  • Δρομολόγηση βάσει πληροφοριών που υπάρχουν ήδη στη ρύθμιση. Το ICE ufrag μάς έδωσε άγκιστρο δρομολόγησης πρώτου πακέτου χωρίς να προσθέσουμε εξάρτηση αναζήτησης στη θερμή διαδρομή.
  • Βελτιστοποίηση για τη συνηθισμένη περίπτωση πριν στραφούμε σε παράκαμψη πυρήνα. Μια στενή υλοποίηση σε Go με προσεκτική χρήση των SO_REUSEPORT, pinning νημάτων και ανάλυση με χαμηλές εκχωρήσεις ήταν αρκετή για τον φόρτο εργασίας μας.

Η φωνητική TN πραγματικού χρόνου λειτουργεί μόνο όταν η υποδομή κάνει την καθυστέρηση να μοιάζει αόρατη. Για εμάς, αυτό σήμαινε να αλλάξουμε το σχήμα της ανάπτυξης WebRTC χωρίς να αλλάξουμε αυτό που περιμένουν οι πελάτες από το ίδιο το WebRTC.