Негізгі мазмұнға өту
OpenAI

2026 ж. 4 мамыр

Инженерия

OpenAI кідірісі төмен дауыстық ЖИ-ді кең ауқымда қалай ұсынады

Yi Zhang және William McDonald, техникалық штат қызметкерлері

Дауыстық ЖИ сөйлесу ауызекі тіл қарқынымен жүргенде ғана табиғи сезіледі. Желі кедергі келтірсе, адамдар оны ыңғайсыз кідірістерден, үзіліп кеткен сөз бөлулерден немесе пайдаланушының сөзге араласуын танудың кешігуінен бірден байқайды. Бұл ChatGPT дауысы үшін, Realtime API арқылы өнім құрастыратын әзірлеушілер үшін, интерактивті жұмыс процестеріндегі агенттер үшін және пайдаланушы әлі сөйлеп жатқанда аудионы өңдеуі қажет модельдер үшін маңызды.

OpenAI ауқымында бұл үш нақты талапқа айналады:

  • Аптасына 900 миллионнан астам белсенді пайдаланушыны қамтитын жаһандық ауқым
  • Пайдаланушы сеанс бастала салысымен сөйлей алуы үшін қосылымды жылдам орнату
  • Медианың бару-қайту кідірісі төмен әрі тұрақты, джиттері мен пакет жоғалуы аз болса, сөз кезегінің алмасуы айқын әрі ширақ сезіледі

OpenAI-да ЖИ-мен нақты уақыттағы өзара әрекеттесуге жауапты команда ауқым өскен сайын бір-біріне кедергі келтіре бастаған үш шектеуді шешу үшін WebRTC стекінің архитектурасын жақында қайта жобалады: әр сеансқа бір порт қағидатымен media termination жасау OpenAI инфрақұрылымына жақсы сай келмейді, күйі сақталатын ICE (Interactive Connectivity Establishment) және DTLS (Datagram Transport Layer Security) сеанстарына тұрақты иелік қажет, ал жаһандық маршрутизация бірінші hop кідірісін төмен деңгейде ұстауы керек. Бұл жазбада біз клиенттер үшін WebRTC стандартты әрекетін сақтай отырып, OpenAI инфрақұрылымы ішінде пакеттердің бағытталу тәсілін өзгерту үшін құрған бөлінген ретранслятор және трансивер архитектурасын қарастырамыз.

WebRTC бізге нақты уақыттағы ЖИ өнімдерін жасауға мүмкіндік береді

WebRTC — браузерлер, мобильді қолданбалар және серверлер арасында кідірісі төмен аудио, бейне және деректерді жіберуге арналған ашық стандарт. Ол көбіне peer-to-peer қоңырауларымен байланыстырылады, бірақ клиент-сервер форматындағы нақты уақыттағы жүйелер үшін де практикалық негіз бола алады, өйткені интерактивті медианың күрделі бөліктерін стандарттайды: байланыс орнату және NAT (Network Address Translation) арқылы өту үшін ICE, шифрланған тасымал үшін DTLS және SRTP (Secure Real-time Transport Protocol), аудионы қысу және декодтау үшін кодек келісімі, сапаны бақылау үшін RTCP (Real-time Transport Control Protocol), сондай-ақ жаңғырықты жою және джиттерді буферлеу сияқты клиент жағындағы мүмкіндіктер.

Мұндай стандарттау ЖИ өнімдері үшін маңызды. WebRTC болмаса, әр клиент NAT арқылы байланыс орнату, медианы шифрлау, кодектерді келісу (жіберу және декомпрессия үшін таңдалатын кодтаушы-декодтаушылар) және өзгеріп отыратын желі жағдайларына бейімделу үшін жеке шешім табуы керек болар еді. WebRTC арқылы біз браузерлер мен мобильді платформаларда бұрыннан іске асырылған протоколдар стекіне сүйеніп, өз жұмысымызды нақты уақыттағы медианы модельдермен байланыстыратын инфрақұрылымға бағыттай аламыз.

Біз WebRTC экожүйесінің өзіне де сүйенеміз: оған ашық кодты жетілген іске асырулар және браузерлер, мобильді қолданбалар мен серверлердің үйлесімді жұмысын қамтамасыз ететін стандарттау жұмысы кіреді. Justin Uberti (WebRTC-тің бастапқы сәулетшілерінің бірі) және Sean DuBois (Pion жобасының жасаушысы әрі мейнтейнері) атқарған іргелі жұмыс біз сияқты командаларға төмен деңгейлі тасымалдау, шифрлау және кептелісті басқару механизмдерін қайта жасаудың орнына, іс жүзінде сыналған медиа инфрақұрылымды негізге алуға мүмкіндік берді. Justin мен Sean қазір OpenAI-да бізбен бірге жұмыс істеп, WebRTC мен нақты уақыттағы ЖИ-ді жақындастыру жолын айқындауға көмектесіп жүргені — біз үшін үлкен мүмкіндік.

ЖИ үшін ең маңызды қасиет — аудионың үздіксіз ағын ретінде келуі. Дауыстық агент аудионың толық жүктелуін күтпей-ақ, пайдаланушы әлі сөйлеп жатқанда транскрипциялауды, ой қорытуды, құралдарды шақыруды немесе сөйлеуді генерациялауды бастай алады. Әңгімелесіп отырғандай әсер беретін жүйе мен push-to-talk режиміндей сезілетін жүйенің айырмашылығы — осында.

Медиа архитектурасын таңдау

WebRTC-ті таңдағаннан кейін келесі сұрақ WebRTC қосылымын қай жерде терминациялауымыз керек екеніне (яғни оны қабылдап, өз иелігімізге алатын нүкте — мысалы, edge деңгейінде) және сол сеанстарды инференс backend-ке қалай қосатынымызға қатысты болды. Терминация маңызды, өйткені ол нақты уақыттағы сеанс күйін, медиа тасымалдауды, маршрутизацияны, кідірісті және ақауларды оқшаулауды қалай басқаратынымызды анықтайды.

1-нұсқа: SFU тәсілі ЖИ-ді WebRTC қатысушысы ретінде қосады

SFU, яғни ағындарды таңдап жіберетін медиа сервер, әр қатысушыдан бір WebRTC ағынын қабылдап, оны басқаларға қажетіне қарай жібереді. Бұл модельде SFU әр қатысушы үшін жеке WebRTC қосылымын терминациялайды, ал ЖИ сеансқа тағы бір қатысушы ретінде қосылады. Бұл топтық қоңыраулар, сыныптар немесе бірлескен жиналыстар сияқты табиғатынан бірнеше қатысушыға арналған өнімдерге жақсы сай келуі мүмкін. Бұл аудио кодектерін, RTCP хабарламаларын, деректер арналарын, жазуды және әр ағынға арналған саясатты бір жерде біріктіреді.1

Тіпті клиент пен ЖИ арасындағы өнімдерде де SFU көбіне әдепкі бастапқы нүкте болады, өйткені ол командаларға сигнал беру, медиа маршрутизациясы, жазу, бақыланымдылық және адам операторына ауыстыру немесе көбірек қатысушы қосу сияқты болашақ кеңейтімдер үшін бір тексерілген жүйені қайта пайдалануға мүмкіндік береді.

2-нұсқа: трансивер тәсілі WebRTC-ті шеткі деңгейде терминациялап, бэкенд протоколына түрлендіреді

Біздің жұмыс жүктемеміз басқаша. Сеанстардың көпшілігі 1:1 форматында өтеді: бір пайдаланушы бір модельмен сөйлеседі немесе бір қолданба нақты уақыттағы бір агентпен байланысады, әрі әр репликада кідіріске сезімтал. Трафиктің осындай сипаты үшін біз трансивер моделін таңдадық: WebRTC edge қызметі клиент қосылымын терминациялайды, содан кейін медиа мен оқиғаларды модель инференсі, транскрипция, сөйлеуді генерациялау, құралдарды пайдалану және оркестрация үшін анағұрлым қарапайым ішкі протоколдарға түрлендіреді.

Бұл дизайнда трансивер — ICE байланыс тексерулерін, DTLS қол алысу процесін, SRTP шифрлау кілттерін және сеанс өмірлік циклін қоса алғанда, WebRTC сеансының күйін өз иелігінде ұстайтын жалғыз қызмет. Мұндағы «терминация» трансивердің сол қол алысу процестерін аяқтайтын және медианы шифрлайтын немесе оның шифрын ашатын соңғы нүкте екенін білдіреді. Бұл күйді бір жерде сақтау сеанс иелігін анық түсінуді жеңілдетті және бэкенд қызметтеріне өздері WebRTC пирлері ретінде әрекет етпей, әдеттегі қызметтер сияқты масштабталуға мүмкіндік берді.

Орналастырудағы негізгі мәселе: WebRTC Kubernetes-пен түйіскенде

Трансивер моделін таңдағаннан кейін алғашқы іске асыруымыз Pion негізінде құрылған, сигнал алмасуды да, медиа терминациясын да өңдейтін бір Go қызметі болды. Ол ChatGPT дауысының, Realtime API WebRTC соңғы нүктесінің және бірқатар зерттеу жобаларының жұмысын қамтамасыз етеді.

Операциялық тұрғыдан алғанда, трансивер қызметі екі міндет атқарады:

  • Сигнал алмасу: SDP келісімі, кодек таңдау, ICE тіркелгі деректері және сеансты орнату
  • Медиа: төмен бағыттағы WebRTC қосылымдарын терминациялау және инференс пен оркестрация үшін бэкенд қызметтеріне жоғары бағыттағы қосылымдарды ұстап тұру

Біз бұл қызметтің инфрақұрылымымыздың басқа бөліктері сияқты Kubernetes-та жұмыс істегенін қаладық: онда жұмыс жүктемелері сұраныс өзгерген сайын масштабын ұлғайтып немесе азайтып, хосттар арасында орын ауыстыра алады. Бірақ әр сеансқа бір порт бөлетін дәстүрлі WebRTC моделі бұл ортаға онша сай келмейді, өйткені ол pod-тар қосылғанда, жойылғанда немесе қайта жоспарланғанда сыртқа шығару, қауіпсіздендіру және сақтап қалу қиын болатын ашық UDP порттарының үлкен диапазондарына тәуелді.2

Порттардың сарқылуы

Бірінші мәселе әр сеансқа бір порт моделінің өзінде болды. Қатар орындалу жоғары болғанда, бұл өте үлкен UDP порт диапазондарын сыртқа шығарып, басқаруды білдіреді.

  • Бұлттық жүктеме теңгергіштері мен Kubernetes қызметтері әр қызметке он мыңдаған ашық UDP портын бөлуге арналып жобаланбаған. Әр қосымша диапазон жүктеме теңгергіші конфигурациясында, денсаулық күйін тексеруде, брандмауэр саясатында және жайылту қауіпсіздігінде операциялық күрделілікті арттырады.3
  • UDP порттарының үлкен диапазондарын қорғау қиын, себебі олар сырттан қолжетімді бетті кеңейтіп, желі саясатының аудитін қиындатады.
  • Олар автоматты масштабтауға да онша сай келмейді. Kubernetes жүйесінде pod-тар үнемі қосылып, жойылып, қайта жоспарланады. Әр pod-тан үлкен әрі тұрақты порт диапазонын резервтеп, жариялауды талап ету бұл икемділікті осал етеді.4

Сондықтан көптеген WebRTC жүйелері әр серверге бір ғана UDP порты моделіне көшеді, ал сол порттың артында қолданба деңгейіндегі демультиплекстеу орындалады.5

Күйдің тұрақты байланысы

Әр серверге бір порт қолданатын архитектуралар порт саны мәселесін шешеді, бірақ екінші мәселені тудырады: серверлер жиынында әр сеанстың иелігін сақтап қалу.

ICE және DTLS — күйі сақталатын протоколдар. Сеансты құрған процесс сол сеанстың пакеттерін қабылдауды жалғастыруы керек, сонда ол байланыс тексерулерін растап, DTLS қол алысу процесін аяқтап, SRTP шифрын ашып, ICE қайта іске қосылулары сияқты кейінгі сеанс өзгерістерін өңдей алады. Егер бір сеанстың пакеттері басқа процеске түссе, орнату сәтсіз болуы немесе медиа ағыны бұзылуы мүмкін.

Бұл бізге нақты мақсат қойды: ашық интернетке шағын әрі тұрақты UDP кіру бетін шығару және әр пакетті тиісті WebRTC сеансына иелік ететін трансиверге бағыттау.

WebRTC медиа архитектураларын салыстыру

Біз оған жетудің бірнеше жолын бағаладық, соның ішінде TURN (Traversal Using Relays around NAT) тәсілі де бар: онда шеткі ретранслятор клиент allocation-дарын терминациялап, олардың атынан трафикті қайта бағыттайды.2

Тәсіл

Артықшылықтары

Кемшіліктері

Әр сеансқа бірегей IP:port мәні (нативті тікелей UDP деп те аталады)

Клиенттен серверге тікелей медиа жолы

Деректер жолында қайта бағыттау қабаты жоқ

Әр сеансқа бір ашық UDP портын қажет етеді

Үлкен порт диапазондарын сыртқа шығару және қауіпсіздендіру қиын

Kubernetes және бұлттық жүктеме теңгергіштері үшін қолайсыз

Әр серверге бірегей IP:port

Әр сеанс бойынша сыртқа шығарумен салыстырғанда ашық UDP ізі әлдеқайда шағын

Әр сервердегі бір ортақ сокет көптеген сеансты демультиплекстей алады

Бір хостта қиындықсыз жұмыс істейді, бірақ өздігінен жүктемесі теңгерілген ортақ серверлер жиынында жұмыс істемейді

Бір хосттағы сеанстарды демультиплекстеу пакет сол хостқа жеткеннен кейін ғана көмектеседі; жүктемесі теңгерілген серверлер жиынында бірінші пакет әлі де дұрыс емес данаға түсуі мүмкін, сондықтан әр сеансты оған иелік ететін процеске бағыттайтын детерминистік тәсіл қажет


TURN ретрансляторы (протоколды терминациялайтын)

Клиенттерге тек TURN ретрансляторының мекенжайы мен портына жету қажет

Саясатты шеткі деңгейде орталықтандыруға болады

TURN-де ресурстарды бөлу орнату кезінде қосымша бару-қайту қадамдарын қосады

TURN серверлері арасында бөлінген ресурстарды көшіру немесе қалпына келтіру әлі де қиын

Күй сақтамайтын бағыттаушы + күйі сақталатын терминатор (OpenAI ретрансляторы + трансивері)

Шағын ашық UDP ізі

Трансивер әлі де толық WebRTC сеансына иелік етеді

Медиа иелік ететін трансиверге жеткенге дейін бір қосымша қайта бағыттау қадамын қосады

Ретранслятор мен трансивер арасындағы арнайы үйлестіруді қажет етеді

Архитектураға шолу: ретранслятор + трансивер

Біз қолданысқа енгізген архитектура пакеттерді бағыттауды протокол терминациясынан бөледі. Сигнал алмасу сеансты орнату үшін әлі де трансиверге жетеді, ал медиа алдымен ретранслятор арқылы кіреді. Ретранслятор — ашық интернеттегі ізі шағын, жеңіл UDP қайта бағыттау қабаты, ал трансивер — оның артындағы күйі сақталатын WebRTC соңғы нүктесі.

Ретранслятор пакеттерді күй сақтамай трансиверге қайта бағыттайды

Ретранслятор медианың шифрын ашпайды, ICE күй машиналарын жүргізбейді және кодектерді келісу процесіне қатыспайды. Ол баратын жерді таңдау үшін пакеттің жеткілікті метадеректерін оқиды, содан кейін пакетті сол сеансқа иелік ететін трансиверге бағыттайды. Трансивер әлі де қалыпты WebRTC ағынын көреді және протокол күйінің бәрін өз иелігінде ұстайды. Клиент тұрғысынан WebRTC сеансында ештеңе өзгермейді.

ICE тіркелгі деректері арқылы бағыттау

Бірінші пакет арқылы бағыттау — осы схемадағы негізгі қадам. Ретранслятор клиенттен келген бірінші пакетті пакет жолының өзінде сеанс әлі қалыптаспай тұрып бағыттауы керек — сыртқы іздеу қызметін күтіп кідірмеуі тиіс.

Әр WebRTC сеансында протоколдың өзіне тән бағыттау тетігі бар: ICE пайдаланушы аты фрагменті немесе ufrag — сеансты орнату кезінде алмасатын және STUN байланыс тексерулерінде қайталанатын қысқа идентификатор. Біз сервер жағындағы ufrag-ті ретранслятор мақсатты кластер мен иелік ететін трансиверді анықтай алатындай жеткілікті бағыттау метадеректерін қамтитын етіп жасаймыз.

Реттілік диаграммасы қосылымның қалай орнатылатынын көрсетеді

Сигнал алмасу кезінде трансивер сеанс күйін бөліп, SDP жауабында ретранслятордың ортақ VIP-і мен UDP портын қайтарады. VIP — ретрансляторлар жиынының алдында тұратын виртуалды IP мекенжайы; портпен бірге ол клиентке 203.0.113.10:3478 сияқты бір тұрақты мақсатты мекенжай береді, ал оның артында көптеген ретранслятор даналары тұрады. Клиенттің медиа жолындағы бірінші пакеті әдетте STUN (Session Traversal Utilities for NAT) binding сұрауы болады. Оны ICE пакеттердің жарияланған мекенжайға жете алатынын тексеру үшін пайдаланады.

Ретранслятор сол бірінші STUN пакетінің сервер ufrag мәнін оқуға, бағыттау нұсқауын декодтауға және пакетті иелік ететін трансиверге жіберуге жеткілікті бөлігін ғана талдайды. Әр трансивер ортақ UDP сокетін тыңдайды, яғни ішкі IP:port мәніне байланыстырылған операциялық жүйенің бір соңғы нүктесін пайдаланады, әр сеансқа бір сокет емес. Ретранслятор клиенттің дереккөз IP:port мәні мен сол трансивердің мақсатты мекенжайы арасында сеанс құрғаннан кейін, кейінгі DTLS, RTP және RTCP пакеттері ufrag мәнін қайта декодтамай-ақ сеанс ішінде өтеді.

Ретранслятордың сеансы әдейі ықшам етіп жасалған: ол пакеттерді қайта бағыттауға қажет деректі ұстайтын жедел жадтағы сеанстан, мониторингке арналған қажетті санауыштардан және сеанстың мерзімі бітуі мен тазалануы үшін қолданылатын таймерлерден ғана тұрады. Бұл дизайн шешімі пакеттерді бағыттауды тікелей пакет жолының өзінде ұстайды. Егер ретранслятор қайта іске қосылып, сеансты жоғалтса, келесі STUN пакеті ufrag бағыттау нұсқауы негізінде сеансты қайта құрады. Оны одан да сенімді ету үшін бағыт анықталғаннан кейін Redis кэші <клиент IP-і + порт, трансивер IP-і + порт> сәйкестігін сақтау үшін пайдаланылады. Осылайша сәйкестікті келесі STUN пакеті келгенге дейін әлдеқайда ертерек қалпына келтіруге болады.

Global Relay және геобағытталған сигнал алмасу

Ашық UDP бетін тұрақты мекенжайлар мен порттардың шағын санына дейін қысқартқаннан кейін, біз дәл сол ретранслятор үлгісін жаһандық деңгейде орналастыра алдық. Global Relay — пакеттерді бірдей қайта бағыттау әрекетін іске асыратын географиялық тұрғыдан таратылған ретранслятор кіру нүктелерінің жиыны.

Географиялық тұрғыдан кең таралған кіру нүктелері клиенттен OpenAI-ге дейінгі бірінші hop-ты қысқартады, өйткені пакет алдымен алыс аймаққа ашық интернет арқылы өтпей, біздің желіге пайдаланушыға географиялық жағынан да, желі топологиясы жағынан да жақын ретранслятор арқылы кіре алады. Практикалық тұрғыдан бұл трафик біздің магистральдық желімізге жеткенге дейін кідіріс төмен, джиттер аз және болдырмауға болатын пакет жоғалуының шоғырлары сирек болады дегенді білдіреді.6

Global Relay қабаты клиенттен пакеттерді қабылдап, оларды трансивер кластеріне қайта бағыттайды

Сигнал алмасу үшін Cloudflare-дің географиялық және жақындыққа негізделген бағыттауын пайдаланамыз, сонда бастапқы HTTP немесе WebSocket сұрауы жақын маңдағы трансивер кластеріне жетеді. Сұрау контексті сеанстың орналасуын және клиентке қай Global Relay кіру нүктесі жарияланатынын анықтайды. SDP жауабы Global Relay мекенжайын береді, ал ufrag ішінде Global Relay медианы белгіленген кластерге, ал ретранслятор оны мақсатты трансиверге бағыттай алуы үшін жеткілікті ақпарат болады.

Геобағытталған сигнал алмасу мен Global Relay бірге сеансты орнатуды да, медианы да жақын маңдағы кіру жолына бағыттайды, ал сеанс бір трансиверге бекітілген күйде қалады. Бұл сигнал алмасу мен алғашқы ICE байланыс тексеруінің бару-қайту уақытын қысқартады, соның нәтижесінде пайдаланушы сөйлеуді бастамас бұрын күтетін уақыт тікелей азаяды.

Ретрансляторды іске асыру және өнімділігі

Ретранслятор қызметін Go тілінде жаздық және оны әдейі тар ауқымды етіп іске асырдық. Linux жүйесінде ядроның желілік стекі UDP пакеттерін машинаның желілік интерфейсінен қабылдап, оларды сокетке жеткізеді. Сокет — процесс IP:Port мәніне байланыстырғаннан кейін оқитын операциялық жүйенің соңғы нүктесі. Ретранслятор userspace деңгейінде жұмыс істейді, сондықтан кәдімгі Go процесі сол сокеттен пакет тақырыптарын оқып, flow күйінің шағын бөлігін жаңартады да, WebRTC-ті терминацияламай пакеттерді қайта бағыттайды. Бізге ядроны айналып өтетін фреймворк қажет болмады: ол пайдаланушы кеңістігіндегі процеске жоғары пакет өткізу жылдамдығы үшін желілік кезектерді тікелей сұрауға мүмкіндік берер еді, бірақ операциялық күрделілікті де арттырар еді.

Негізгі дизайн шешімдері:

  • Протокол терминациясы жоқ: ретранслятор тек STUN тақырыптарын/ufrag мәнін талдайды; кейінгі DTLS, RTP және RTCP үшін кэштелген күйді пайдаланып, пакеттерді ашпай сақтайды.
  • Уақытша күй: ретранслятор ағын күйі мен бақыланымдылық үшін клиент мекенжайын трансивердің мақсатты мекенжайымен сәйкестендіретін, жадта сақталатын шағын әрі қысқа тайм-ауты бар сәйкестік кестесін ұстайды.
  • Көлденең масштабталу: бірнеше ретранслятор данасы жүктеме теңгергішінің артында қатар жұмыс істейді. Күй қатаң WebRTC күйі емес, сондықтан қайта іске қосылулар трафиктің аз ғана үзілуіне әкеліп, flow-дың тез қалпына келуіне мүмкіндік береді.

Тиімділік шаралары:

  • SO_REUSEPORT — бір машинадағы бірнеше ретранслятор жұмысшысына бір UDP портына байланысуға мүмкіндік беретін Linux сокет параметрі. Содан кейін ядро кіріс пакеттерін сол жұмысшылар арасында таратады, бұл бір read-loop тар жерінің пайда болуына жол бермейді.
  • runtime.LockOSThread UDP оқитын әр goroutine-ді нақты OS thread-ке бекітеді. SO_REUSEPORT параметрімен бірге бұл бір flow-ға жататын пакеттерді (дереккөз және мақсатты IP:Port мәндері мен протокол) бір CPU ядросында ұстауға көмектеседі, соның арқасында кэш локалдылығы жақсарып, контекст ауыстыру азаяды.
  • Алдын ала бөлінген буферлер мен көшіруді барынша азайту Go тілінде garbage collection-ды болдырмау үшін талдау және жады бөлу үстеме шығындарын төмен ұстайды.

Бұл іске асыру жаһандық нақты уақыттағы медиа трафигімізді салыстырмалы түрде шағын ретранслятор ізімен өңдей алды, сондықтан kernel bypass жолына көшудің орнына қарапайымдау дизайнды сақтап қалдық.

Нәтижелер мен алған сабақтар

Бұл архитектура бізге Kubernetes ортасында мыңдаған UDP портын сыртқа шығармай-ақ WebRTC медиасын іске қосуға мүмкіндік береді. Бұл маңызды, өйткені шағын әрі тұрақты UDP беті қауіпсіздендіруге және жүктемені теңгеруге жеңілірек, әрі инфрақұрылымға ашық порттардың үлкен диапазондарын резервтемей-ақ масштабталуға мүмкіндік береді. Kubernetes тарапынан инфрақұрылымдық қолдау жақсарып, шағын бет аймағының арқасында қауіпсіздік артқандықтан, бұл дизайн клиенттер үшін стандартты WebRTC әрекетін де сақтайды және біздің жұмыс жүктемеміз үшін SFU-сыз дизайн дұрыс әдепкі таңдау болғанын растайды. Сеанстарымыздың көпшілігі point-to-point форматында, кідіріске сезімтал және инференс қызметтері WebRTC пирлері сияқты әрекет етпегенде оңайырақ масштабталады.

Бұдан шығатын кеңірек сабақ: күрделілікті қосудың ең дұрыс орны — әр бэкенд қызметі немесе клиенттің арнайы әрекеті емес, жұқа бағыттау қабаты. Бағыттау метадеректерін протоколға тән өріске кодтау бізге детерминистік бірінші пакет арқылы бағыттауды, шағын ашық UDP ізін және бүкіл әлемдегі пайдаланушыларға жақын кіру нүктелерін орналастыруға жеткілікті икемділікті берді.

Бірнеше шешім әсіресе маңызды болды:

  • Шеткі деңгейде протокол семантикасын сақтау. Клиенттер әлі де стандартты WebRTC арқылы жұмыс істейді, бұл браузерлер мен мобильді қолданбалар арасындағы үйлесімділікті сақтайды.
  • Қатаң сеанс күйлерін бір жерде ұстау. Трансивер ICE, DTLS, SRTP және сеанс өмірлік циклін өз иелігінде ұстайды; ретранслятор тек пакеттерді қайта бағыттайды.
  • Сеансты орнату кезінде бұрыннан бар ақпарат арқылы бағыттау. ICE ufrag бізге hot path-та lookup тәуелділігін қоспай-ақ бірінші пакет арқылы бағыттау тетігін берді.
  • Ядроны айналып өту тәсіліне жүгінбес бұрын, жиі кездесетін жағдайды оңтайландырыңыз. Біздің жұмыс жүктемеміз үшін Go тіліндегі ықшам іске асыру, SO_REUSEPORT параметрін мұқият қолдану, thread-терді бекіту және жады бөлуді азайтатын талдау жеткілікті болды.

Нақты уақыттағы дауыстық ЖИ инфрақұрылым кідірісті сезілмейтіндей еткенде ғана жұмыс істейді. Біз үшін бұл клиенттер WebRTC-дің өзінен күтетін әрекетті өзгертпей, WebRTC-ді орналастыру тәсілін өзгертуді білдірді.