1 điểm bởi GN⁺ 2024-06-25 | 1 bình luận | Chia sẻ qua WhatsApp
  • Điều quan trọng trong video trực tiếp và hội thoại trên Internet không phải bản thân việc “truyền không tin cậy”, mà là đẩy dữ liệu cũ ra và chuyển dữ liệu mới nhất đúng lúc
  • Nếu router không loại bỏ các gói bị tắc nghẽn mà để chúng xếp hàng quá lâu trong queue, sẽ xảy ra bufferbloat, gây ra độ trễ còn tệ hơn cả buffering đối với dịch vụ thời gian thực
  • Nếu tự xây giao thức trực tiếp trên UDP, bạn sẽ phải triển khai lại truyền lại, điều khiển tắc nghẽn, mã hóa, ước lượng RTT, xác thực đường đi, điều khiển luồng... nên dùng thư viện QUIC sẽ an toàn hơn
  • Chỉ với QUIC, cũng có thể tạo ra tính kịp thời mà không cần datagram bằng cách kết hợp điều khiển tắc nghẽn dựa trên độ trễ, phân tách stream độc lập và gán mức ưu tiên
  • Dù các tiêu chuẩn QUIC, WebTransport và MoQ đều đang bổ sung hỗ trợ datagram, kết luận là tốt hơn nên đi theo luồng Media over QUIC thay vì lại chồng một giao thức video mới lên trên UDP

Mục tiêu không phải là “tính không ổn định” mà là tính kịp thời

  • Việc chọn TCP hay UDP thường được giải thích là giữa “truyền tin cậy” và “truyền không tin cậy”, nhưng điều ứng dụng thực sự cần không phải là bản thân tính không ổn định
  • Trong video trực tiếp hay hội thoại trên Internet, việc dữ liệu mới nhất đến trước quan trọng hơn là nhận đủ toàn bộ dữ liệu cũ
  • Trong hội thoại thời gian thực, cần tránh tình huống hiện vòng xoay buffering trên khuôn mặt hoặc nghe thấy âm thanh từ 5 giây trước
  • Ngành video trực tiếp và ngành game thường dùng UDP datagram thay cho TCP stream để đạt được tính kịp thời như vậy

Datagram và hàng đợi mạng

  • Datagram là một phong bì chứa các bit 0 và 1 được gửi từ địa chỉ nguồn đến địa chỉ đích, và thông thường 1200 byte được xem là kích thước an toàn
  • Datagram có thể bị mất một cách âm thầm, và cũng có thể đến không đúng thứ tự
  • Ở tầng vật lý, dữ liệu được biến thành tín hiệu tương tự để đi qua môi trường truyền dẫn; trong quá trình đó có thể xảy ra tuần tự hóa, giải tuần tự, buffering, xếp hàng, truyền lại, loại bỏ, hỏng dữ liệu, trì hoãn, sắp xếp lại, trùng lặp và mất mát
  • Khi quá nhiều dữ liệu đi vào mạng, router sẽ loại bỏ dữ liệu ở ranh giới gói tin chứ không phải ở mức bit ngẫu nhiên

Bufferbloat và điều khiển tắc nghẽn

  • Nếu router không loại bỏ gói ngay mà tích chúng lại trong queue, bufferbloat sẽ xảy ra
  • bufferbloat có thể làm chậm mọi gói tin đến vài giây, tạo ra tình huống tệ nhất cho truyền tải thời gian thực
  • Để tránh queueing, cần ước lượng mức xếp hàng của router thông qua phản hồi về thời điểm gói đến, rồi bên gửi phải giảm lượng truyền để làm trống queue
  • Lĩnh vực này thuộc về điều khiển tắc nghẽn, và cách gửi gói ở tốc độ không giới hạn có thể dẫn đến thảm họa

Những chức năng phải gánh khi tự xây trên UDP

Tạo tính kịp thời bằng QUIC stream

  • Có thể tóm tắt cách đạt được tính kịp thời trong QUIC thành ba điểm
    • Tránh phình bộ đệm: điều khiển tắc nghẽn dựa trên độ trễ như BBR sẽ phát hiện queueing và giảm lượng truyền
    • transport-wide-cc của WebRTC có thể được xem là một ví dụ về cách làm tốt hơn
    • Phân tách stream: byte trong mỗi stream có thứ tự và được truyền tin cậy; mỗi stream có thể là một đơn vị nguyên tử như khung hình video, bản cập nhật game, tin nhắn chat hay JSON blob
    • Gán ưu tiên cho stream: các stream là độc lập nên có thể đến không theo thứ tự, và có thể chỉ thị cho QUIC stack chuyển các stream quan trọng trước
    • Các stream ưu tiên thấp có thể bị đói tài nguyên, và có thể đóng chúng để tránh lãng phí băng thông
  • Đây là cốt lõi của Media over QUIC
  • Tính chất fire-and-forget của datagram chỉ phù hợp khi thực sự cần độ trễ thời gian thực; ngoài ra có thể dùng QUIC stream

Những đánh đổi và ngoại lệ quanh datagram

  • QUIC và các tiêu chuẩn liên quan cũng bao gồm hỗ trợ datagram
  • Hỗ trợ datagram có thể được đưa vào vì việc triển khai khá đơn giản và cho phép thử nghiệm
  • OPUS có tích hợp hỗ trợ FEC, nên đây là ví dụ cho việc MoQ hỗ trợ gửi mỗi “frame” âm thanh dưới dạng datagram
  • Giao thức cũ như DNS có thể được xem là ngoại lệ, nhưng với thiết kế mới thì tốt hơn nên đi theo hướng như DNS over HTTPS
  • Kết luận là thay vì lại xây một giao thức video mới trên UDP, hãy tham gia Media over QUIC

1 bình luận

 
GN⁺ 2024-06-25
Ý kiến trên Hacker News
  • Vấn đề của TCP thường được nhắc đến trong các lĩnh vực băng thông lớn và nhạy cảm với độ trễ như HFT hay video, nhưng TCP cũng không đặc biệt tốt trên các mạng băng thông thấp, độ trễ cao
    Ví dụ, trong môi trường như NB-IoT, nơi độ trễ khứ hồi trong trường hợp xấu nhất là 10 giây, thời gian khứ hồi bị lãng phí cho handshake và dò MTU; TCP vẫn cố truyền cả dữ liệu không còn hữu ích nữa; và khi vùng phủ sóng xấu đi làm độ trễ tăng, TCP xem đó là mất gói do tắc nghẽn và giảm băng thông
    Ngoài ra, load balancer hoặc middlebox có thể ngắt kết nối vì nghĩ rằng “không có phản hồi trong 4 giây thì chắc nó biến mất rồi”, và việc TCP chia gói mà không xét đến cấu trúc dữ liệu, khiến không thể diễn giải cho đến khi nhận đủ toàn bộ, cũng là một điểm đáng tiếc
    • TCP giả định mọi dữ liệu đến tuần tự dưới dạng linear stream, và nếu không nhận được gói thứ n thì cũng không đưa gói thứ n+1 cho ứng dụng
      Trong một số trường hợp điều này hữu ích, nhưng có nhiều trường hợp vẫn có thể tận dụng gói n+1 dù gói n chưa có
      Khi truyền tệp lớn, có thể dùng erasure coding để tự xử lý mất 5% gói, hoặc dùng fountain code để gửi cho đến khi bên nhận nói “đã nhận đủ”
      Fountain code là cách các tàu thăm dò không gian sâu gửi dữ liệu, và độ trễ tới Sao Mộc hay Sao Hỏa là khá nghiêm trọng
    • Dùng TLS thì đặc biệt đúng như vậy, và ngày nay TLS gần như là mặc định trong các ca sử dụng chính
      Phải hoàn tất TCP handshake rồi mới có thể bắt đầu TLS handshake, nhưng QUIC có hỗ trợ ở cấp giao thức để xử lý đàm phán TLS ngay trong handshake ban đầu
      Việc có thể kết hợp lỏng lẻo giao thức mạng và mã hóa trông có vẻ thanh nhã hơn, nhưng trong một thế giới mà gần như mọi truyền tải đều được mã hóa, lợi ích thực tế của việc giảm một vòng khứ hồi cho mỗi kết nối có vẻ lớn hơn
    • Tôi tự hỏi liệu ngày nay tầng Wi-Fi bên dưới TCP có thường tự truyền lại đối với các mất mát do tín hiệu yếu hoặc nhiều nhiễu hay không
    • Tôi tự hỏi NB-IoT thực sự còn được dùng hiện nay không. Tôi nhớ có một thời nó được quảng bá rất rầm rộ, nhưng sau đó cảm giác như không còn được nhắc tới nữa
  • Với streaming dữ liệu cảm biến tần số cao thì cứ dùng UDP datagram
    Bên R&D đã làm một hệ thống mới dùng QUIC và giải quyết được phần lớn vấn đề dữ liệu đến sai thứ tự, nhưng các cảm biến bên thứ ba cần được hỗ trợ trực tiếp mà không qua adapter lại chỉ dùng được UDP, nên cuối cùng vẫn dùng UDP datagram cho mọi thứ
    • Gần như toàn bộ các hệ thống media art trên thế giới cũng dùng OSC trên UDP
    • Nhắc đến dữ liệu cảm biến tần số cao, tôi tự hỏi có con số nào về tiết kiệm điện so với TCP không
    • Tôi tò mò hệ thống đó được làm bằng ngôn ngữ nào. Nghe khá hay
    • Để có độ tin cậy trên UDP thì cũng có thể dùng RoCE
  • Nghe có thể như bắt bẻ vặt, nhưng tôi thấy có vấn đề khi gọi UDP là unreliable
    Cách diễn đạt phổ biến hơn và tốt hơn là best-effort: UDP cố gắng hết mức để chuyển datagram, chỉ là datagram có thể bị bỏ
    Điều đó không có nghĩa UDP về bản chất là không đáng tin cậy
    https://en.wikipedia.org/wiki/Best-effort_delivery
    • best-effort là một cách nói giảm nói tránh và dễ gây nhầm lẫn với người ngoài lĩnh vực này, thậm chí có thể còn hơn thế với người bản ngữ tiếng Anh
      Trên thực tế nó không có nghĩa là cố gắng đến cùng để gửi thông điệp từ A đến B, mà gần với “cũng đã cố rồi” hơn
      Nếu router trên đường đi bị tắc nghẽn, hoặc do link flap tạo ra một blackhole khoảng 50ms trước khi định tuyến lại nhanh, thì cũng thành “ừ thì đã thử rồi”
      Ngược lại, truyền tải đáng tin cậy của TCP sẽ thử lại nhiều lần và cung cấp cho ứng dụng một luồng dữ liệu đúng thứ tự
      reliable/unreliable cũng có thể là thuật ngữ tệ, nhưng khó nói best-effort là tốt hơn
      Các hệ thống không đáng tin cậy thì khoảng 95% là rất tốt và cũng tốt cho thông lượng thô, nhưng 5% cuối cùng thường tạo ra khác biệt rất lớn
    • Trong networking, best effort delivery là một thuật ngữ né tránh chẳng tốt hơn unreliable, đến mức có thể bỏ đi cũng được
      “Nỗ lực” thường hàm ý một mức độ bền bỉ nào đó trước khó khăn, nhưng việc vứt gói khi gặp vấn đề tài nguyên thì khó gọi là nỗ lực, càng không phải best effort
      “best efforts” trong ngôn ngữ pháp lý/kinh doanh yếu hơn một cam kết chắc chắn, nhưng không phải là công khai buông tay; cách dùng trong networking thì khá khác
      Riêng checksum của UDP và TCP cũng không bảo đảm tốt tính toàn vẹn khi datagram được chuyển tới, chỉ nhỉnh hơn phần cứng một chút
    • Tôi cứ nghĩ “datagram có thể bị bỏ” chính là nghĩa của unreliable, nên không rõ đang muốn tránh hiểu lầm nào
    • Gọi tầng truyền tải là unreliable không phải cách diễn đạt hay. Độ tin cậy là thuộc tính của hệ thống, không phải của phương thức truyền tải; có thể tạo hệ thống không đáng tin cậy bằng TCP, và cũng có thể tạo hệ thống đáng tin cậy bằng UDP
      Tuy nhiên best-effort lại tạo cảm giác rằng có nỗ lực nào đó để bảo đảm chuyển phát, trong khi thực tế thì những gói trông có vẻ bất thường hoặc xui xẻo gặp buffer đầy sẽ bị vứt luôn
      Tôi thích lossy hơn, nhưng đây là vấn đề đặt tên thuộc loại “chỉ có hai bài toán khó”
    • Từ thập niên 80 người ta đã gọi là unreliable transport, và thực tế đúng là vậy
      Nếu gói cần phải đến nơi thì dùng TCP, còn nếu không quá quan trọng thì dùng UDP
      Dù là giải thích đơn giản hóa, best effort là một thuật ngữ ngớ ngẩn, và trong đó chẳng có nỗ lực nào cả
  • Tôi cho rằng stream abstraction khiến việc viết ra các chương trình mong manh, phục hồi chậm hoặc không thể phục hồi khi kết nối bị đứt trở nên quá dễ dàng, đồng thời áp đặt quá nhiều ràng buộc lên tầng truyền tải
    Kiểm soát tắc nghẽn rõ ràng là cần thiết, nhưng ngoài chuyện đó thì có rất nhiều điều đáng nghi
    Nếu là một thế giới datagram-first, chúng ta đã có thể ghép nhiều data link với hiệu quả rất cao, hoặc roaming qua các ranh giới mạng mà không cần ngắt kết nối
    Nhiều ứng dụng có thể xử lý frame đến sai thứ tự mà không tốn thêm chi phí, và nếu viết theo mô hình UDP thì có thể nhanh hơn nhiều
    • Lập luận rằng TCP quá tiện nên phần mềm không được viết đúng, rồi lại yêu cầu tin rằng trong một thế giới datagram-first phức tạp hơn nhiều sẽ xuất hiện phần mềm hoàn toàn vững chắc và hiệu quả, là điều không mấy thuyết phục
      Trên thực tế, chuyển sang phương thức truyền tải kém tin cậy hơn không tự động khiến phần mềm trở nên đáng tin cậy hơn hay hiệu quả hơn

Ngược lại, số chế độ lỗi và độ phức tạp mà nhóm phải xử lý tăng lên đáng kể

  • Với các ứng dụng có mã sửa lỗi phù hợp, kiểm soát tắc nghẽn cũng có thể là tùy chọn
    Tuy nhiên, nếu đâu đó trong kết nối có một nút thắt hẹp, thì việc tạo ra rất nhiều gói tin rồi dù sao cũng sẽ bị loại bỏ ở nút thắt đó có vẻ không có nhiều ý nghĩa
  • Tôi tò mò không biết đang nghĩ đến loại ứng dụng nào. Trong các hệ thống hiện nay thường được viết bằng TCP, cái gì có thể chuyển sang UDP?
    Website, âm thanh, video nhìn chung không hợp lắm với các frame bị đảo thứ tự, và phần lớn mọi người không muốn âm thanh hay video bị giật
    Một số video game có thể bỏ qua các gói bị thiếu, nhưng những trường hợp đó vốn đã được viết bằng UDP rồi
  • Một điểm không thường được nhắc đến là khi xảy ra tắc nghẽn, nhiều mạng sẽ loại bỏ gói UDP trước
    Vì người ta cho rằng những gói đó sẽ không được truyền lại, nên đây là cách hiệu quả để giảm lưu lượng dư thừa
    Giờ đã có các giao thức trên UDP truyền lại một cách tích cực, tôi tò mò điều này đã thay đổi tình hình ra sao
    Tôi cũng nhớ vài năm trước QUIC từng gặp vấn đề truyền lại so với HTTP/1·HTTP/2 vì lý do này
  • Tôi đã cố đổi tiêu đề câu click bằng cách dùng chính cách diễn đạt trong bài viết
    Nếu tìm được một cụm từ tiêu biểu hơn trong bài thì có thể đổi lại
    Điều này theo hướng dẫn tiêu đề của HN: “dùng tiêu đề gốc, trừ khi nó gây hiểu lầm hoặc mang tính câu kéo”: https://news.ycombinator.com/newsguidelines.html
  • Tôi không đồng ý với tiền đề của bài viết này. UDP không tồn tại vì bản thân tính không đáng tin cậy, mà là một sự đánh đổi: chọn chuyển phát theo best-effort thay cho các bảo đảm để đổi lấy tốc độ và hiệu quả
    Tùy ứng dụng mà điều đó hợp lý
    Ví dụ trong game multiplayer thời gian thực, nếu xử lý bị tụt lại, các mục bị trễ không còn quan trọng nữa vì trạng thái game đã thay đổi rồi
    Các ứng dụng giao dịch tốc độ cao trong một số tình huống cũng chỉ cần dữ liệu thị trường mới nhất, chứ không phải chuyện của 100ms trước
    • Đó không phải là tiền đề của bài, mà là một quan niệm phổ biến mà tác giả sửa lại ngay sau đó
      Bài viết cũng nêu game và video trực tiếp làm ví dụ về nơi UDP phù hợp
    • Nếu đọc tiếp thì về cơ bản bài cũng nói như vậy
      Cấu trúc là ban đầu đưa ra “quan niệm phổ biến” rồi phản bác nó
  • Những thứ cần phải dựa trên datagram là khám phá cục bộ, broadcast, và đóng gói gói tin
    Ví dụ gồm khám phá cục bộ như DHCP, SLAAC, UPnP, mDNS, tinc, BitTorrent; broadcast như streaming mạng cục bộ; và đóng gói như WireGuard, IPSec, OpenVPN, VLAN
    • Một mục còn thiếu là media thời gian thực
      Việc truyền lại, thậm chí chỉ cần buffering để sắp xếp lại thứ tự, cũng làm tăng độ trễ, nên tốt hơn là chấp nhận mất mát bằng sửa lỗi hoặc che giấu mất gói
    • Với tư cách là người không có nhiều kiến thức mạng cấp thấp, tôi tò mò liệu có thể giải thích vì sao các use case này cần datagram không
    • Game cũng thuộc nhóm này
  • Tiêu đề là clickbait ngớ ngẩn, và tác giả cũng thừa nhận ở phần đầu
    UDP và TCP có hành vi và các điểm đánh đổi khác nhau, nên tất cả chỉ là cần hiểu trước khi chọn cho phù hợp với use case
    Không cần kiểu gác cổng “tuyệt đối đừng làm X”
    • Nếu dấu sao trước chữ “never” trong tiêu đề không phải được thêm vào trong 10 phút sau khi bình luận được đăng, thì dấu sao đó rõ ràng là dấu hiệu cho thấy có điều kiện chi tiết
      Chỉ nhìn tiêu đề cũng khá rõ rằng bài không nhằm gác cổng cấm dùng UDP
      Thực tế ở cuối bài, tác giả đề xuất dùng QUIC, vốn dựa trên UDP
  • Hầu hết ứng dụng và trường hợp sẽ dùng kết nối dựa trên phiên, nhưng cũng có mục đích dùng trực tiếp datagram, nên không cần sợ
    Tất nhiên bạn sẽ phải tự lo nhiều chi tiết hơn rất nhiều
    Thêm nữa, đây cũng là cách tốt để học các khía cạnh cấp thấp của mạng
    • SteamNetworkingMessages API cho phát triển game giúp dùng tốt cách này trong use case đó mà không cần bận tâm đến phần bên trong