გადადით მთავარ შინაარსზე
OpenAI

4 მაისი, 2026

ინჟინერია

როგორ უზრუნველყოფს OpenAI დაბალი დაყოვნების მქონე ხმოვანი ხელოვნური ინტელექტის მუშაობას მასშტაბურად

ი ჩჟანი და უილიამ მაკდონალდი, ტექნიკური სპეციალისტები

ხმოვანი ხელოვნური ინტელექტი ბუნებრივად აღიქმება მხოლოდ მაშინ, როცა საუბარს ცოცხალი მეტყველების სიჩქარე აქვს. როგორც კი დაბრკოლებები იჩენს თავს ქსელის მხრივ, ადამიანი ამას მაშინვე ამჩნევს. უხერხული პაუზები, გაწყვეტილი ფრაზები ან საუბარში ჩაჭრის დაგვიანებული რეაქციები ამის ნიშანია. ეს კრიტიკულად მნიშვნელოვანია ChatGPT‑ს ხმოვანი რეჟიმისთვის; დეველოპერებისთვის, რომლებიც Realtime API-ს გამოყენებით ქმნიან პროდუქტებს; აგენტებისთვის, რომლებიც ინტერაქციულ სამუშაო პროცესებში მუშაობენ; და მოდელებისთვის, რომლებსაც აუდიოს დამუშავება სჭირდებათ, სანამ მომხმარებელი ჯერ კიდევ საუბრობს.

OpenAI-ს მასშტაბში ეს სამ კონკრეტულ მოთხოვნად გარდაიქმნება:

  • გლობალური მოცვა 900 მილიონზე მეტი აქტიური მომხმარებლისთვის ყოველკვირეულად
  • კავშირის სწრაფი დამყარება, რომ მომხმარებელმა საუბარი სეანსის დაწყებისთანავე დაიწყოს
  • მედიატრაფიკის აქეთ-იქით მოძრაობის დაბალი და სტაბილური დრო და თრთოლისა და პაკეტების დაკარგვის დაბალი მაჩვენებელი, რომ საუბრის მონაცვლეობა მკაფიოდ იგრძნობოდეს

OpenAI-ს გუნდმა, რომელიც რეალურ დროში ხელოვნურ ინტელექტთან ურთიერთქმედებებზეა პასუხისმგებელი, ახლახან ხელახლა გადააპროექტა WebRTC სტეკი, რომ მოეგვარებინა სამი შეზღუდვა, რომლებიც მასშტაბურ დონეზე მოვიდა ერთმანეთთან წინააღმდეგობაში: მედიასეანსის დასრულება პრინციპით „ერთი პორტი ერთ სეანსზე“ OpenAI-ს ინფრასტრუქტურას კარგად არ ერგება; მდგომარეობის შენახვის უნარიან ICE (Interactive Connectivity Establishment) და DTLS (Datagram Transport Layer Security) სეანსებს სტაბილური ფლობა სჭირდება; და გლობალურმა მარშრუტიზაციამ დაბალი დაყოვნება უნდა შეინარჩუნოს პირველ ტრანზიტულ მონაკვეთზე. ამ პუბლიკაციაში ნაბიჯ-ნაბიჯ განვიხილავთ ჩვენ მიერ აგებულ განცალკევებულ რეტრანსლატორი + ტრანსივერი არქიტექტურას, რომელიც შევქმენით იმისთვის, რომ კლიენტებისთვის WebRTC-ს სტანდარტული ქცევა შეგვენარჩუნებინა, ხოლო OpenAI-ს ინფრასტრუქტურის შიგნით პაკეტების მარშრუტიზაციის ლოგიკა შეგვეცვალა.

WebRTC საშუალებას გვაძლევს, შევქმნათ ხელოვნური ინტელექტის პროდუქტები, რომლებიც რეალურ დროში მუშაობს

WebRTC — ესაა ღია სტანდარტი დაბალი დაყოვნები მქონე ხმის, ვიდეოსა და მონაცემების გადასაცემად ბრაუზერებს, მობილურ აპლიკაციებსა და სერვერებს შორის. მას ხშირად აკავშირებენ პირინგულ ზარებთან, მაგრამ ის ასევე პრაქტიკული საფუძველია რეალურ დროში მომუშავე კლიენტ-სერვერული სისტემებისთვის, რადგან სტანდარტიზაციას უწევს ინტერაქციული მედიის რთულ ნაწილებს, რომლებსაც განეკუთვნება ICE კავშირის დამყარებისთვის და NAT-ის (Network Address Translation) გაკვალვა, DTLS-ი და SRTP (Secure Real-time Transport Protocol) დაშიფრული გადაცემისთვის; კოდეკების შეთანხმება ხმის შეკუმშვისა და დეკოდირებისთვის; RTCP (Real-time Transport Control Protocol) ხარისხის კონტროლისთვის; და კლიენტის მხარის ფუნქციები, როგორიცაა ექოს ჩახშობა და თრთოლის ბუფერიზაცია.

ეს სტანდარტიზაცია მნიშვნელოვანია ხელოვნური ინტელექტის პროდუქტებისთვის. WebRTC-ს გარეშე ყოველ კლიენტს დასჭირდებოდა საკუთარი პასუხი შეკითხვაზე, თუ როგორ დაემყარებინა კავშირი NAT-ების გავლით, დაეშიფრა მედიანაკადი, შეეთანხმებინა კოდეკები (გადაცემისა და დეკომპრესიისთვის შერჩეული კოდერ-დეკოდერები) და ადაპტაცია მოეხდინა ქსელის ცვალებად პირობებთან. WebRTC-ს მეშვეობით შეგვიძლია, დავეყრდნოთ პროტოკოლების სტეკს, რომელიც უკვე რეალიზებულია ბრაუზერებში და მობილურ პლატფორმებზე, ხოლო ჩვენი ძალისხმევა მივმართოთ ინფრასტრუქტურაზე, რომელიც რეალური დროის მედიანაკადებს აკავშირებს მოდელებთან.

ჩვენ თვითონაც WebRTC-ს ეკოსისტემას ვეყრდნობით, მათ შორის, ჩამოყალიბებულ ღია კოდის იმპლემენტაციებსა და სტანდარტიზაციის სამუშაოებს, რომლებიც ბრაუზერების, მობილური აპლიკაციებისა და სერვერების ურთიერთთავსებადობას უზრუნველყოფს. ჯასტინ უბერტის (WebRTC-ს ერთ-ერთი პირველი არქიტექტორისა) და შონ დიუბუას (Pion-ის შემქმნელი და ტექნიკური სპეციალისტი) ფუნდამენტურმა შრომამ შესაძლებელი გახადა, რომ ჩვენს მსგავს გუნდებს გადაწყვეტები შეექმნათ პრაქტიკაში გამოცდილ მედიაინფრასტრუქტურაზე დაყრდნობით და ხელთავიდან არ გამოეგონებინათ დაბალდონიანი სატრანსპორტო ლოგიკა, დაშიფვრა და გადატვირთულობის მართვა. გაგვიმართლა, რომ ჯასტინიცა და შონიც ახლა ჩვენი კოლეგები არიან OpenAI-ში და გვეხმარებიან იმის განსაზღვრაში, თუ როგორ დავაკავშიროთ WebRTC და რეალურ დროში მოქმედი ხელოვნური ინტელექტი ერთმანეთთან უფრო მჭიდროდ.

ხელოვნური ინტელექტისთვის ყველაზე მნიშვნელოვანი თვისება ის არის, რომ აუდიო უწყვეტ ნაკადად მიეწოდება. ხმოვან აგენტს შეუძლია, დაიწყოს ტრანსკრიბირება, მსჯელობა, ხელსაწყოების გამოძახება თუ მეტყველების გენერირება, სანამ მომხმარებელი ჯერ კიდევ საუბრობს და არ დაელოდოს სრულად ატვირთვას. სწორედ ეს განასხვავებს სისტემას, რომელიც საუბრად აღიქმება, სისტემისგან, რომელიც რაციის რეჟიმს ჰგავს.

მედიაარქიტექტურის არჩევა

WebRTC-ს არჩევის შემდეგ გაჩნდა მომდევნო შეკითხვა: სად უნდა მომხდარიყო კავშირის დასრულება (სად მივიღებდით და შევინარჩუნებდით WebRTC კავშირს, მაგალითად, პერიფერიაში) და როგორ დავაკავშირებდით ამ სეანსებს დასკვნების გამოტანის სერვერულ ნაწილთან. დასრულების წერტილი მნიშვნელოვანია, რადგან ის განსაზღვრავს, როგორ ვმართავთ რეალურ დროში სეანსის მდგომარეობას, მედიამონაცემების ტრანსპორტირებას, მარშრუტიზაციას, დაყოვნებასა და შეფერხებათა იზოლაციას.

ვარიანტი 1: SFU მიდგომა ხელოვნურ ინტელექტს მოიცავს როგორც WebRTC-ს მონაწილეს

SFU (Selective Forwarding Unit) არის მედიასერვერი, რომელიც თითოეული მონაწილისგან იღებს ერთ WebRTC ნაკადს, ხოლო დანარჩენებს შერჩევითად უგზავნის ნაკადებს. ამ მოდელში SFU თითოეული მონაწილისთვის წყვეტს ცალკეულ WebRTC კავშირს, ხოლო ხელოვნური ინტელექტი სეანსს კიდევ ერთ მონაწილედ უერთდება. ეს შეიძლება კარგი არჩევანი იყოს პროდუქტებისთვის, რომლებიც თავისი არსით მრავალმომხმარებლიანია. მათ რიცხვს განეკუთვნება ჯგუფური ზარები, სასწავლო ოთახები და თანამშრომლობითი შეხვედრები. ასეთი მიდგომა ერთ ადგილას უყრის თავს აუდიოკოდეკებს, RTCP შეტყობინებებს, მონაცემთა არხებს, ჩაწერასა და ცალკეული ნაკადების პოლიტიკებს.1

„კლიენტი-ხელოვნური ინტელექტი“ ტიპის პროდუქტებშიც კი SFU ხშირად ნაგულისხმევ საწყის წერტილად გამოიყენება, რადგან ის გუნდებს საშუალებას აძლევს, ხელახლა გამოიყენონ ერთი დადასტურებული სისტემა სიგნალის გადაცემისთვის, მედიატრაფიკის მარშრუტიზაციისთვის, ჩაწერისთვის, დაკვირვებადობისა და მომავალი გაფართოებებისთვის, როგორიცაა საუბრის გადაცემა ადამიანისთვის ან სხვა მონაწილეების დამატება.

ვარიანტი 2: ტრანსივერის მიდგომა WebRTC-ს ამთავრებს პერიფერიაზე და მას სერვერულ პროტოკოლად გარდაქმნის

ჩვენი სამუშაო დატვირთვა განსხვავებულია. სეანსების უმეტესობა 1:1 ფორმატისაა (ერთი მომხმარებელი ესაუბრება ერთ მოდელს ან ერთი აპლიკაცია ურთიერთქმედებს ერთ აგენტთან რეალურ დროში) და ყოველ ჯერზე ფიქსირდება მგრძნობელობა დაყოვნების მიმართ. ტრაფიკის ასეთი ფორმისთვის ჩვენ ავირჩიეთ ტრანსივერის მოდელი: WebRTC-ს პერიფერიული სერვისი კლიენტთან კავშირს ამთავრებს და შემდეგ მედიამონაცემებსა და მოვლენებს გარდაქმნის უფრო მარტივ შიდა პროტოკოლებად მოდელის ლოგიკური დასკვნების სისტემის, ტრანსკრიფციის, მეტყველების გენერაციის, ხელსაწყოების გამოყენებისა და ორკესტრირებისთვის.

ამ კონსტრუქციაში ტრანსივერი ერთადერთი მომსახურებაა, რომელიც ფლობს WebRTC სეანსის მდგომარეობას, მათ შორის, ICE კავშირის შემოწმებებს, DTLS კვიტირებას (მიღება-გადაცემის დადასტურებას), SRTP დაშიფვრის გასაღებებსა და სეანსის სასიცოცხლო ციკლს. „დამთავრება“ აქ ნიშნავს, რომ ტრანსივერი არის საბოლოო წერტილი, რომელიც ასრულებს ამ კვიტირებებს და ახდენს მედიამონაცემების დაშიფვრასა და გაშიფვრას. ამ მდგომარეობის ერთ ადგილზე შენახვამ გაამარტივა სეანსის ფლობის გაგება და სერვერულ მომსახურებებს საშუალება მისცა, მასშტაბირება მოეხდინათ როგორც ჩვეულებრივ მომსახურებებს ნაცვლად იმისა, რომ თავად შეესრულებინათ WebRTC-ს ერთრანგიანი ქსელური კვანძების როლი.

გაშლის ძირითადი პრობლემა: WebRTC და Kubernetes

ტრანსივერის მოდელის არჩევის შემდეგ ჩვენი პირველი იმპლემენტაცია გულისხმობდა Go-ში დაწერილ ერთიან მომსახურებას, რომელიც აგებული იყო Pion-ზე. ის ახდენს როგორც სიგნალის გაგზავნას, ისე მედიასეანსების დამთავრებას. ამასთანავე, ის უზრუნველყოფს ChatGPT‑ს ხმოვანი რეჟიმის, Realtime API-ში WebRTC-ს საბოლოო წერტილისა და არაერთი კვლევითი პროექტის მუშაობას.

საოპერაციო თვალსაზრისით, ტრანსივერის მომსახურების მეშვეობით სრულდება ორი სამუშაო:

  • სიგნალის გადაცემა: SDP-ს შეთანხმება, კოდეკების არჩევა, ICE-ის ავტორიზაციის მონაცემები და სეანსის დაყენება
  • მედიამონაცემები: დაღმავალი WebRTC კავშირების დამთავრება და აღმავალი კავშირების შენარჩუნება სერვერულ მომსახურებებთან ლოგიკური დასკვნების გამოტანისა და ორკესტრაციისთვის

გვსურდა, რომ მომსახურებას ჩვენი დანარჩენი ინფრასტრუქტურის მსგავსად ემუშავა: Kubernetes-ში, სადაც სამუშაო დატვირთვებს შეუძლია მასშტაბის გაზრდა და შემცირება და ჰოსტებს შორის გადაადგილება მოთხოვნის ცვლილების შესაბამისად. მაგრამ WebRTC-ს ტრადიციული მოდელი „ერთი პორტი ერთ სეანსზე“ ცუდად ერგება ამ გარემოს, რადგან ის დამოკიდებულია UDP-ს საჯარო პორტების დიდ დიაპაზონებზე, რომელთა გამოქვეყნება, დაცვა და შენარჩუნება რთულია პოდების დამატების, წაშლისა თუ ხელახლა განრიგებისას.2

პორტების ამოწურვა

პირველი პრობლემა იყო თვითონ მოდელი „ერთი პორტი ერთ სეანსზე“. მაღალი პარალელურობის პირობებში ეს ნიშნავს UDP პორტების ძალიან დიდი დიაპაზონის გამოყოფასა და მართვას.

  • ღრუბლოვანი დატვირთვის მაბალანსებლები და Kubernetes-ის მომსახურებები არ არის გათვლილი ათიათასობით საჯარო UDP პორტზე თითო მომსახურებაზე. ყოველი დამატებითი დიაპაზონი ზრდის საოპერაციო სირთულეს დატვირთვის მაბალანსებლის კონფიგურაციაში, მდგომარეობის შემოწმებაში, ფაიერვოლის პოლიტიკასა და გაშლის უსაფრთხოებაში.3
  • UDP პორტების დიდი დიაპაზონების დაცვა რთულია, რადგან ისინი ზრდის გარედან ხელმისაწვდომ ზედაპირს და ართულებს ქსლის პოლიტიკის აუდიტს.
  • ისინი არ გამოდგება არც ავტომასშტაბირებისთვის. Kubernetes-ში მუდმივად ხდება პოდების დამატება, ამოშლა და ხელახლა განრიგება. ამ ელასტიკურობას მყიფეს ხდის იმის მოთხოვნა, რომ თითოეულმა პოდმა პორტების დიდი და სტაბილური დიაპაზონის რეზერვირება და გამოცხადება მოახდინოს.4

სწორედ ამის გამო მრავალი WebRTC სისტემა გადადის მოდელზე „ერთი UDP პორტი ერთ სერვერზე“, ხოლო დემულტიპლექსირება ამ პორტის უკან აპლიკაციის დონეზე სრულდება.5

მდგომარეობის მიმაგრება

ერთ სერვერზე ერთი პორტის მქონე კონსტრუქციები პორტების რაოდენობის პრობლემას აგვარებს, მაგრამ წარმოშობს მეორე პრობლემას, რაც გულისხმობს თითოეული სეანსის ფლობის შენარჩუნებას მთელ სასერვერო პარკში.

ICE და DTLS-ი მდგომარეობის შენახვის უნარიანი პროტოკოლებია. სეანსის შემქმნელმა პროცესმა უნდა განაგრძოს ამ სეანსის პაკეტების მიღება, რომ შეძლოს კავშირის შემოწმებების ვალიდაცია, DTLS კვიტირების შესრულება, SRTP-ის გაშიფვრა და სეანსის შემდგომი ისეთი ცვლილებების დამუშავება, როგორიცაა ICE-ის ხელახლა გაშვებები. თუ ერთი და იმავე სეანსის პაკეტები სხვა პროცესში მოხვდება, შეიძლება ვერ მოხერხდეს დაყენება ან მედიანაკადი გაწყდეს.

ამან კონკრეტული მიზანი დაგვისახა: საჯარო ინტერნეტისთვის გამოგვეტანა მცირე, ფიქსირებული UDP ზედაპირი, ხოლო თითოეული პაკეტი მაინც მიგვემართა იმ ტრანსივერისკენ, რომელიც შესაბამის WebRTC სეანსს ფლობს.

WebRTC-ს მედიაარქიტექტურების შედარება

ამ მიზნის მისაღწევად რამდენიმე გზა განვიხილეთ, მათ შორის, TURN-ი (Traversal Using Relays around NAT), პროტოკოლი, რომელშიც პერიფერიული რეტრანსლატორი ამთავრებს კლიენტთა ალოკაციებს და მათი სახელით ტრაფიკს ამისამართებს.2

მიდგომა

დადებითი მხარეები

უარყოფითი მხარეები

უნიკალური IP:პორტი ყოველი სეანსისთვის (ასევე ცნობილია როგორც ნატიური პირდაპირი UDP)

მედიამონაცემების პირდაპირი გზა კლიენტიდან სერვერამდე

გადამისამართების შრის არარსებობა მონაცემთა გზაზე

საჭიროებს ერთ საჯარო UDP პორტს თითო სეანსზე

პორტების დიდი დიაპაზონების გამოქვეყნება და დაცვა რთულია

არ გამოდგება Kubernetes-ისთვისა და დატვირთვის ღრუბლოვანი დამაბალანსებლებისთვის

უნიკალური IP:პორტი თითო სერვერზე

გაცილებით უფრო პატარა საჯარო UDP ზედაპირი, ვიდრე თითო სეანსზე ცალკე პორტის გამოყოფის შემთხვევაში

თითო სერვერზე ერთ გაზიარებულ სოკეტს მრავალი სეანსის დემულტიპლექსირება შეუძლია

გამართულად მუშაობს ერთ ჰოსტზე, მაგრამ პირდაპირ არ გამოდგება დატვირთვის მიხედვით დაბალანსებული საზიარო პარკისთვის

ერთ ჰოსტზე სეანსების დემულტიპლექსირება მხოლოდ მას შემდეგ არის ეფექტიანი, რაც პაკეტი ამ ჰოსტამდე მიაღწევს; დატვირთვის მიხედვით დაბალანსებულ პარკში პირველი პაკეტი არასწორ ეგზემპლარზე შეიძლება მოხვდეს მაინც, ამიტომ კვლავ გჭირდებათ დეტერმინისტული გზა, რომ თითოეული სეანსი იმ პროცესისკენ მიმართოთ, რომელიც მას ფლობს


TURN რეტრანსლატორი (პროტოკოლის დამთავრებით)

კლიენტებს მხოლოდ TURN რეტრანსლატორის მისამართსა და პორტზე წვდომა სჭირდებათ

შესაძლებელია პოლიტიკის ცენტრალიზება პერიფერიაზე

TURN-ის ალოკაციები ამატებს ორივე მიმართულებით მოძრაობის დროს დაყენებისას

ალოკაციების გადატანა ან აღდგენა TURN სერვერებს შორის კვლავ რთულია

მდგომარეობის შენახვის უნარის არმქონე რეტრანსლატორი და მდგომარეობის შენახვის უნარიანი ტერმინატორი (OpenAI-ს რეტრანსლატორი და ტრანსივერი)

პატარა საჯარო UDP ზედაპირი

ტრანსივერი კვლავ სრულად ფლობს WebRTC-ს სეანსს

ამატებს გადამისამართების ერთ ნახტომს, სანამ მედიატრაფიკი მფლობელ ტრანსივერამდე მიაღწევს

მოითხოვს მორგებულ კოორდინაციას რეტრანსლატორსა და ტრანსივერს შორის

არქიტექტურის მიმოხილვა: რეტრანსლატორი + ტრანსივერი

ჩვენ მიერ დანერგილი არქიტექტურა ერთმანეთისგან აცალკევებს პაკეტების მარშრუტიზაციასა და პროტოკოლის დამთავრებას. სიგნალიზაცია მაინც აღწევს ტრანსივერამდე სეანსის დასაყენებლად, ხოლო მედიატრაფიკი თავდაპირველად რეტრანსლატორის გავლით შედის. რეტრანსლატორი UDP გადამისამართების მსუბუქი დონეა პატარა საჯარო ზედაპირით, ხოლო ტრანსივერი მდგომარეობის შენახვის უნარიანი WebRTC-ს საბოლოო წერტილია, რომელიც მის უკან დგას.

რეტრანსლატორი მდგომარეობის შენახვის გარეშე ამისამართებს პაკეტებს ტრანსივერისკენ

რეტრანსლატორი არ ახდენს მედიამონაცემების გაშიფვრას, არ უშვებს ICE-ს მდგომარეობათა მანქანებს და არ მონაწილეობს კოდეკების შეთანხმებაში. ის პაკეტის მხოლოდ იმ მეტამონაცემებს კითხულობს, რომლებიც საჭიროა დანიშნულების ადგილის ასარჩევად, ხოლო შემდეგ პაკეტს გადასცემს სეანსის მფლობელ ტრანსივერში. ტრანსივერი WebRTC-ს ჩვეულებრივ ნაკადს ხედავს კვლავ და პროტოკოლის მთელ მდგომარეობას ფლობს. კლიენტის გადმოსახედიდან WebRTC-ს სეანსში არაფერი იცვლება.

ICE-ს ავტორიზაციის მონაცემების მიხედვით მარშრუტიზაცია

პირველი პაკეტის მარშრუტიზაცია საკვანძო ნაბიჯია ამ კონფიგურაციაში. რეტრანსლატორმა კლიენტისგან მიღებული პირველი პაკეტის მარშრუტიზება უნდა მოახდინოს მანამ, სანამ თავად პაკეტის გზაზე რაიმე სეანსი გაჩნდება და დამუშავება არ გააჩეროს ძიების გარე მომსახურების გულისთვის.

WebRTC-ს თითოეული სეანსი უკვე შეიცავს პროტოკოლში ჩაშენებულ მარშრუტიზაციის ჰუკს: ICE-ს მომხმარებლის სახელის ფრაგმენტს, ანუ ufrag-ს, მოკლე იდენტიფიკატორს, რომლის მიმოცვლა ხდება სეანსის დაყენებისას და შემდეგ უკანვე იგზავნება კავშირის STUN-შემოწმებებში. სერვერულ ufrag-ს ისე ვაგენერირებთ, რომ ის შეიცავდეს მხოლოდ იმდენ სამარშრუტო მეტამონაცემს, რამდენიც რეტრანსლატორისთვის საკმარისია დანიშნულების კლასტერისა და მფლობელი ტრანსივერის განსასაზღვრად.

თანმიმდევრობის დიაგრამა აჩვენებს, როგორ მყარდება კავშირი.

სიგნალიზაციის დროს ტრანსივერი გამოყოფს სეანსის მდგომარეობას და რეტრანლატორის გაზიარებულ VIP-მისამართსა და UDP პორტს SDP პასუხში აბრუნებს. 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 პაკეტის მოსვლამდე იყოს შესაძლებელი.

გლობალური რეტრანსლატორი და გეონავიგაციური სიგნალიზაცია

მას შემდეგ, რაც საჯარო UDP ზედაპირი სტაბილური მისამართებისა და პორტების მცირე რაოდენობამდე დავიყვანეთ, რეტრანსლატორის იმავე სქემის დანერგვა მთელ მსოფლიოში შევძელით. გლობალური რეტრანსლატორი გეოგრაფიულად განაწილებული რეტრანსლატორების შესვლის წერტილების პარკია: ყველა მათგანი პაკეტების გადამისამართების ერთსა და იმავე ქცევას ასრულებენ.

შესვლის წერტილების ფართო გეოგრაფიული განაწილება ამოკლებს კლიენტიდან OpenAI-ზე პირველ ნახტომს, რადგან პაკეტს შეუძლია, ჩვენს ქსელში შემოვიდეს იმ რეტრანსლატორის მეშვეობით, რომელიც მომხმარებელთან ახლოსაა როგორც გეოგრაფიულად, ისე ქსელური ტოპოლოგიის თვალსაზრისით, იმის ნაცვლად, რომ ჯერ საჯარო ინტერნეტი გაიაროს შორეულ რეგიონამდე. პრაქტიკული თვალსაზრისით, ეს ნიშნავს უფრო დაბალ დაყოვნებას, ნაკლებ თრთოლასა და პაკეტების უეცარი დაკარგვის შემთხვევების შემცირებას, სანამ ტრაფიკი ჩვენს მაგისტრალურ ქსელამდე მიაღწევს.6

გლობალური რეტრანლატორის შრე პაკეტებს კლიენტისგან იღებს და მათ გადასცემს ტრანსივერების კლასტერს

სიგნალიზაციისთვის ვიყენებთ Cloudflare-ის გეოგრაფიული რეგიონებისა და სიახლოვის მართვის სისტემას, რომ საწყისმა HTTP ან WebSocket მოთხოვნამ ახლომდებარე ტრანსივერების კლასტერს მიაღწიოს. მოთხოვნის კონტექსტი განსაზღვრავს სეანსის მდებარეობას და იმას, თუ გლობალური რეტრანსლატორის რომელი შესასვლელი წერტილი უცხადდება კლიენტს. SDP პასუხი უზრუნველყოფს გლობალური რეტრანსლატორის მისამართს, ხოლო ufrag-ი შეიცავს საკმარის ინფორმაციას იმისთვის, რომ გლობალურმა რეტრანსლატორმა მოახდინოს მედიატრაფიკის მარშრუტიზება მითითებულ კლასტერში, ხოლო რეტრანსლატორმა — სამიზნე ტრანსივერამდე.

გეონავიგაციური სიგნალიზაცია და გლობალური რეტრანსლატორი ერთად უზრუნველყოფს როგორც კონფიგურაციის, ისე მედიატრაფიკის გადატანას ახლომდებარე შესასვლელ გზაზე და ამავდროულად, სეანსს ერთ ტრანსივერზე ინარჩუნებს. ეს ამცირებს სიგნალიზაციისა და პირველი ICE კავშირის შემოწმების ორივე მიმართულებით მოძრაობის დროს, რაც პირდაპირ ამოკლებს მომხმარებლის ლოდინის ხანგრძლივობას საუბრის დაწყებამდე.

რეტრანსლატორის იმპლემენტაცია და წარმადობა

რეტრანსლატორის მომსახურება Go-ში დავწერეთ, ხოლო მისი იმპლემენტაციის ფარგლები განზრახ დავავიწროვეთ. Linux-ში ბირთვის ქსელური სტეკი იღებს UDP პაკეტებს მანქანის ქსელური ინტერფეისიდან და გადასცემს მათ სოკეტს, ოპერაციული სისტემის საბოლოო წერტილს, რომლიდანაც პროცესი კითხულობს მონაცემებს IP:Port-ის მიბმის შემდეგ. რეტრანსლატორი სამომხმარებლო სივრცეში მუშაობს, ამიტომ Go-ს ჩვეულებრივი პროცესი კითხულობს პაკეტების თავსართებს აღნიშნული სოკეტიდან, აახლებს ნაკადის მდგომარეობის მცირე ნაწილს და პაკეტებს აგზავნის WebRTC-ს დამთავრების გარეშე. ჩვენ არ დაგვჭირდა ბირთვის გვერდის ასავლელი სამუშაო გარსი, რომელიც სამომხმარებლო სივრცის პროცესს მისცემდა საშუალებას, პაკეტების დამუშავების უფრო მაღალი სიჩქარის მისაღწევად პირდაპირ გამოეკითხა ქსელური რიგები, მაგრამ ამავდროულად, ოპერაციულ სირთულესაც დაამატებდა.

საკვანძო საპროექტო გადაწყვეტილებები:

  • პროტოკოლის დამთავრება არ ხდება: რეტრანსლატორი აანალიზებს მხოლოდ STUN თავსართებს/ufrag-ს; შემდგომი DTLS-ის, RTP-სა და RTCP-სთვის ის იყენებს კეშირებულ მდგომარეობას და პაკეტებს გაუმჭვირვალედ ტოვებს.
  • ეფემერული მდგომარეობა: რეტრანსლატორი მეხსიერებაში ინახავს დროის მოკლე ლიმიტის მქონე პატარა ცხრილს კლიენტის მისამართსა და ტრანსივერის დანიშნულების ადგილამდე. ეს აუცილებელია ნაკადების მართვისა და დაკვირვებადობისთვის.
  • ჰორიზონტალური მასშტაბირებადობა: რეტრანსლატორის ბევრი ეგზემპლარი პარალელურად მუშაობს დატვირთვის მაბალანსებლის უკან. ეს მდგომარეობა არ არის WebRTC-ს ხისტი მდგომარეობა, რესტარტები იწვევს ტრაფიკის მინიმალურ დანაკარგებს და ნაკადების სწრაფ აღდგენას.

ეფექტიანობის ზომები:

  • SO_REUSEPORT არის Linux-ის სოკეტის ვარიანტი, რომელიც ერთსა და იმავე კომპიუტერზე რამდენიმე რეტრანსლატორის მუშა ერთეულს ერთი და იმავე UDP პორტის მიბმის საშუალებას აძლევს. შემდეგ ბირთვი შემომავალ პაკეტებს ამ მუშა ერთეულებს შორის ანაწილებს, რაც საშუალებას იძლევა, თავიდან იქნეს აცილებული სუსტი რგოლი ერთი წაკითხვის ციკლში.
  • runtime.LockOSThread UDP-ს წამკითხავ თითოეულ გოურუტინას ოპერაციული სისტემის კონკრეტულ ნაკადზე ამაგრებს. SO_REUSEPORT-თან ერთად ეს, როგორც წესი, ერთი და იმავე ნაკადიდან მოსულ პაკეტებს (საწყისი და საბოლოო IP:Port-ი, დამატებული პროტოკოლი) CPU-ს ერთსა და იმავე ბირთვზე ტოვებს, რაც აუმჯობესებს კეშის ლოკალურობას და ამცირებს კონტექსტის გადართვას.
  • წინასწარ გამოყოფილი ბუფერები და მინიმალური კოპირება გარჩევისა და მეხსიერების ალოკაციის დამატებით ხარჯს დაბალ დონეზე ინარჩუნებს, რომ Go-ში ნაგვის დაგროვება თავიდან იქნეს აცილებული.

ეს იმპლემენტაცია გაუმკლავდა რეალური დროის გლობალურ მედიატრაფიკს რეტრანსლატორების შედარებით მცირე ინფრასტრუქტურული დატვირთვის პირობებში, ამიტომ უფრო მარტივი კონსტრუქცია შევინარჩუნეთ იმის ნაცვლად, რომ ბირთვისთვის გვერდის ავლაზე გადავსულიყავით.

შედეგები და დასკვნები

ეს არქიტექტურა საშუალებას გვაძლევს, WebRTC-ს მედიატრაფიკი Kubernetes-ში გავუშვათ ისე, რომ ათასობით UDP პორტი არ გავხსნათ. ეს მნიშვნელოვანია, რადგან უფრო მცირე და ფიქსირებული UDP ზედაპირის უსაფრთხოების უზრუნველყოფა და დატვირთვის დაბალანსება უფრო მარტივია და ის ინფრასტრუქტურას საშუალებას აძლევს, მასშტაბირება მოახდინოს საჯარო პორტების დიდი დიაპაზონების რეზერვირების გარეშე. Kubernetes-ის მიერ უზრუნველყოფილი უკეთესი ინფრასტრუქტურული მხარდაჭერით და შეტევის შემცირებული ზედაპირის გამო გაზრდილი უსაფრთხოებით ეს კონსტრუქცია ინარჩუნებს WebRTC-ს სტანდარტულ ქცევას კლიენტებისთვის და ადასტურებს, რომ ჩვენი სამუშაო დატვირთვისთვის სწორი ნაგულისხმევი არჩევანი იყო კონსტრუქცია SFU-ს გარეშე. ჩვენი სეანსების უმეტესობა წერტილი-წერტილის ტიპისაა, მგრძნობიარეა დაყოვნების მიმართ და უფრო ადვილად მასშტაბირდება, როცა დასკვნების გამოტანის მომსახურებებს WebRTC-ს სრულუფლებიანი ქსელური კვანძების როლის მორგება არ სჭირდება.

უფრო ზოგადი დასკვნა ისაა, რომ სირთულის დასამატებლად საუკეთესო ადგილი მარშრუტიზაციის თხელი შრეა და არა თითოეული სერვერული მომსახურება თუ კლიენტის მორგებული ქცევა. პროტოკოლისთვის განკუთვნილ ველში მარშრუტიზაციის მეტამონაცემების კოდირებამ მოგვცა პირველი პაკეტის დეტერმინისტული მარშრუტიზაცია, პატარა საჯარო UDP ზედაპირი და საკმარისი მოქნილობა, რომ შესასვლელი წერტილები მომხმარებლებთან ახლოს განგვეთავსებინა მსოფლიოს მასშტაბით.

რამდენიმე არჩევანი განსაკუთრებით მნიშვნელოვანი იყო:

  • პროტოკოლის სემანტიკის შენარჩუნება პერიფერიაზე. კლიენტები უწინდებურად სტანდარტულ WebRTC-ს იყენებენ, რაც ბრაუზერებსა და მობილურ მოწყობილობებთან ურთიერთთავსებადობას ინარჩუნებს.
  • სეანსის რთული მდგომარეობების ერთ ადგილას შენახვა. ტრანსივერი ფლობს ICE-ს, DTLS-ს, SRTP-სა და სეანსის სასიცოცხლო ციკლს; რეტრანსლატორი უბრალოდ ამისამართებს პაკეტებს.
  • მარშრუტიზება კონფიგურაციაში უკვე არსებული ინფორმაციის საფუძველზე. ICE ufrag-მა მოგვცა პირველი პაკეტის მარშრუტიზაციის ჰუკი ისე, რომ ძიებაზე დამოკიდებულება არ დაუმატებია კრიტიკულ გზაზე.
  • ტიპური შემთხვევისთვის ოპტიმიზება ბირთვისთვის გვერდის ავლაზე გადასვლამდე. ვიწრო იმპლემენტაცია Go-ში SO_REUSEPORT-ის ფრთხილი გამოყენებით, ნაკადების ჩამაგრება და დაბალი ალოკაციის პირობებში გარჩევა საკმარისი აღმოჩნდა ჩვენი სამუშაო დატვირთვისთვის.

რეალურ დროში ხმოვანი ხელოვნური ინტელექტი მხოლოდ მაშინ მუშაობს, როცა ინფრასტრუქტურა დაყოვნებას შეუმჩნეველს ხდის. ჩვენთვის ეს ნიშნავდა WebRTC-ს გაშლის სტრუქტურის შეცვლას ისე, რომ არ შეცვლილიყო ის, რასაც კლიენტები თვითონ WebRTC-სგან ელიან.