Vũ khí bí mật của TCP: Kiểm soát luồng mạng và kiểm soát tắc nghẽn mạng.

Vận chuyển độ tin cậy TCP
Chúng ta đều quen thuộc với giao thức TCP như một giao thức vận chuyển đáng tin cậy, nhưng làm thế nào nó đảm bảo tính đáng tin cậy của việc vận chuyển?

Để đạt được khả năng truyền tải đáng tin cậy, cần phải xem xét nhiều yếu tố, chẳng hạn như lỗi dữ liệu, mất mát, trùng lặp và các phân vùng không theo thứ tự. Nếu không giải quyết được những vấn đề này, việc truyền tải đáng tin cậy sẽ không thể thực hiện được.

Do đó, TCP sử dụng các cơ chế như số thứ tự, phản hồi xác nhận, kiểm soát gửi lại, quản lý kết nối và kiểm soát cửa sổ để đạt được khả năng truyền tải đáng tin cậy.

Trong bài viết này, chúng ta sẽ tập trung vào cửa sổ trượt, điều khiển luồng và điều khiển tắc nghẽn của TCP. Cơ chế truyền lại sẽ được trình bày riêng trong phần tiếp theo.

Kiểm soát luồng mạng
Kiểm soát luồng mạng, hay còn gọi là kiểm soát lưu lượng mạng, thực chất là biểu hiện của mối quan hệ tinh tế giữa nhà sản xuất và người tiêu dùng. Có lẽ bạn đã gặp tình huống này rất nhiều trong công việc hoặc trong các cuộc phỏng vấn. Nếu khả năng sản xuất của nhà sản xuất vượt xa khả năng tiêu thụ của người tiêu dùng, nó sẽ khiến hàng đợi tăng lên vô hạn. Trong trường hợp nghiêm trọng hơn, bạn có thể biết rằng khi các tin nhắn RabbitMQ tích tụ quá nhiều, nó có thể gây suy giảm hiệu suất của toàn bộ máy chủ MQ. Điều tương tự cũng đúng với TCP; nếu không được kiểm soát, quá nhiều tin nhắn sẽ được đưa vào mạng, và người tiêu dùng sẽ vượt quá khả năng của mình, trong khi nhà sản xuất sẽ tiếp tục gửi các tin nhắn trùng lặp, điều này sẽ ảnh hưởng nghiêm trọng đến hiệu suất của mạng.

Để giải quyết hiện tượng này, TCP cung cấp một cơ chế cho phép người gửi kiểm soát lượng dữ liệu được gửi dựa trên khả năng tiếp nhận thực tế của người nhận, được gọi là điều khiển luồng. Người nhận duy trì một cửa sổ nhận, trong khi người gửi duy trì một cửa sổ gửi. Cần lưu ý rằng các cửa sổ này chỉ dành cho một kết nối TCP duy nhất và không phải tất cả các kết nối đều dùng chung một cửa sổ.

Giao thức TCP cung cấp khả năng kiểm soát luồng bằng cách sử dụng một biến cho cửa sổ nhận. Cửa sổ nhận cho người gửi biết lượng không gian bộ nhớ cache còn trống. Người gửi kiểm soát lượng dữ liệu được gửi đi dựa trên khả năng tiếp nhận thực tế của người nhận.

Máy chủ nhận thông báo cho máy chủ gửi về kích thước dữ liệu mà nó có thể nhận, và máy chủ gửi sẽ gửi dữ liệu trong giới hạn này. Giới hạn này chính là kích thước cửa sổ, bạn còn nhớ tiêu đề TCP chứ? Có một trường cửa sổ nhận, được sử dụng để chỉ ra số byte mà máy chủ nhận có thể hoặc sẵn sàng nhận.

Máy chủ gửi sẽ định kỳ gửi một gói thăm dò cửa sổ, được sử dụng để phát hiện xem máy chủ nhận có còn khả năng nhận dữ liệu hay không. Khi bộ đệm của máy nhận có nguy cơ bị tràn, kích thước cửa sổ sẽ được đặt thành một giá trị nhỏ hơn để hướng dẫn máy chủ gửi kiểm soát lượng dữ liệu được gửi đi.

Đây là sơ đồ điều khiển luồng mạng:

Kiểm soát giao thông

Kiểm soát tắc nghẽn mạng
Trước khi giới thiệu về kiểm soát tắc nghẽn, chúng ta cần hiểu rằng ngoài cửa sổ nhận và cửa sổ gửi, còn có cửa sổ tắc nghẽn, chủ yếu được sử dụng để giải quyết vấn đề tốc độ mà bên gửi bắt đầu gửi dữ liệu đến cửa sổ nhận. Do đó, cửa sổ tắc nghẽn cũng được duy trì bởi bên gửi TCP. Chúng ta cần một thuật toán để quyết định lượng dữ liệu phù hợp để gửi, vì gửi quá ít hoặc quá nhiều dữ liệu đều không lý tưởng, do đó mới có khái niệm về cửa sổ tắc nghẽn.

Trong phương pháp kiểm soát luồng mạng trước đây, điều chúng ta tránh được là việc người gửi làm đầy bộ nhớ cache của người nhận bằng dữ liệu, nhưng chúng ta không biết điều gì đang xảy ra trong mạng. Thông thường, mạng máy tính hoạt động trong môi trường chia sẻ. Do đó, có thể xảy ra tắc nghẽn mạng do sự giao tiếp giữa các máy chủ khác.

Khi mạng bị tắc nghẽn, nếu tiếp tục gửi một lượng lớn gói dữ liệu, điều này có thể gây ra các vấn đề như độ trễ và mất gói. Lúc này, TCP sẽ truyền lại dữ liệu, nhưng việc truyền lại sẽ làm tăng gánh nặng cho mạng, dẫn đến độ trễ lớn hơn và mất gói nhiều hơn. Điều này có thể tạo thành một vòng luẩn quẩn và ngày càng trầm trọng hơn.

Do đó, TCP không thể bỏ qua những gì đang xảy ra trên mạng. Khi mạng bị tắc nghẽn, TCP sẽ hy sinh bằng cách giảm lượng dữ liệu gửi đi.

Do đó, cơ chế kiểm soát tắc nghẽn được đề xuất, nhằm mục đích tránh việc toàn bộ mạng bị lấp đầy bởi dữ liệu từ phía người gửi. Để điều chỉnh lượng dữ liệu mà người gửi nên gửi đi, TCP định nghĩa một khái niệm gọi là cửa sổ tắc nghẽn. Thuật toán kiểm soát tắc nghẽn sẽ điều chỉnh kích thước của cửa sổ tắc nghẽn theo mức độ tắc nghẽn của mạng, để kiểm soát lượng dữ liệu được người gửi gửi đi.

Cửa sổ tắc nghẽn là gì? Điều này có liên quan gì đến cửa sổ gửi?

Cửa sổ tắc nghẽn là một biến trạng thái do bên gửi duy trì, xác định lượng dữ liệu mà bên gửi có thể gửi đi. Cửa sổ tắc nghẽn thay đổi linh hoạt tùy thuộc vào mức độ tắc nghẽn của mạng.

Cửa sổ gửi (Sending Window) là kích thước cửa sổ được thỏa thuận giữa người gửi và người nhận, cho biết lượng dữ liệu mà người nhận có thể nhận được. Cửa sổ tắc nghẽn (congestion window) và cửa sổ gửi có mối liên hệ với nhau; cửa sổ gửi thường bằng giá trị nhỏ nhất của cửa sổ tắc nghẽn và cửa sổ nhận, tức là swnd = min(cwnd, rwnd).

Thông số cửa sổ tắc nghẽn cwnd thay đổi như sau:

Nếu không có tắc nghẽn trong mạng, tức là không xảy ra lỗi hết thời gian chờ truyền lại, thì cửa sổ tắc nghẽn sẽ tăng lên.

Nếu mạng bị tắc nghẽn, khoảng thời gian tắc nghẽn sẽ giảm đi.

Bên gửi xác định xem mạng có bị tắc nghẽn hay không bằng cách quan sát xem gói tin xác nhận ACK có được nhận trong khoảng thời gian quy định hay không. Nếu bên gửi không nhận được gói tin xác nhận ACK trong khoảng thời gian quy định, thì mạng được coi là bị tắc nghẽn.

Ngoài cửa sổ tắc nghẽn, đã đến lúc thảo luận về thuật toán kiểm soát tắc nghẽn TCP. Thuật toán kiểm soát tắc nghẽn TCP bao gồm ba phần chính:

Khởi đầu chậm:Ban đầu, cửa sổ tắc nghẽn cwnd tương đối nhỏ, và người gửi tăng cửa sổ tắc nghẽn theo cấp số nhân để nhanh chóng thích ứng với dung lượng của mạng.
Tránh tắc nghẽn giao thông:Sau khi cửa sổ tắc nghẽn vượt quá một ngưỡng nhất định, người gửi sẽ tăng cửa sổ tắc nghẽn một cách tuyến tính để làm chậm tốc độ tăng trưởng của cửa sổ tắc nghẽn và tránh quá tải mạng.
Phục hồi nhanh chóng:Nếu xảy ra tắc nghẽn, bên gửi sẽ giảm một nửa cửa sổ tắc nghẽn và chuyển sang trạng thái phục hồi nhanh để xác định vị trí phục hồi mạng thông qua các gói xác nhận trùng lặp đã nhận được, sau đó tiếp tục tăng cửa sổ tắc nghẽn.

Khởi đầu chậm
Khi thiết lập kết nối TCP, cửa sổ tắc nghẽn cwnd ban đầu được đặt ở giá trị MSS (kích thước phân đoạn tối đa) tối thiểu. Bằng cách này, tốc độ gửi ban đầu vào khoảng MSS/RTT byte/giây. Băng thông thực tế khả dụng thường lớn hơn nhiều so với MSS/RTT, vì vậy TCP muốn tìm tốc độ gửi tối ưu, điều này có thể đạt được bằng cách sử dụng cơ chế khởi động chậm (slow-start).

Trong quy trình khởi động chậm, giá trị của cửa sổ tắc nghẽn cwnd sẽ được khởi tạo là 1 MSS, và mỗi khi phân đoạn gói tin được xác nhận, giá trị của cwnd sẽ tăng lên 1 MSS, tức là giá trị của cwnd sẽ trở thành 2 MSS. Sau đó, giá trị của cwnd sẽ tăng gấp đôi cho mỗi lần truyền thành công một phân đoạn gói tin, và cứ thế tiếp diễn. Quá trình tăng trưởng cụ thể được thể hiện trong hình dưới đây.

 Kiểm soát tắc nghẽn mạng

Tuy nhiên, tốc độ gửi không phải lúc nào cũng tăng; sự tăng trưởng phải có lúc kết thúc. Vậy, khi nào thì tốc độ gửi tăng lên sẽ dừng lại? Phương pháp khởi động chậm thường kết thúc sự tăng trưởng tốc độ gửi theo một trong số các cách sau:

Cách thứ nhất là trường hợp mất gói tin trong quá trình gửi dữ liệu theo cơ chế khởi động chậm. Khi xảy ra mất gói tin, TCP sẽ đặt cửa sổ tắc nghẽn cwnd của bên gửi thành 1 và khởi động lại quá trình khởi động chậm. Tại thời điểm này, khái niệm ngưỡng khởi động chậm ssthresh được giới thiệu, có giá trị ban đầu bằng một nửa giá trị của cwnd gây ra mất gói tin. Tức là, khi phát hiện tắc nghẽn, giá trị của ssthresh bằng một nửa giá trị cửa sổ.

Cách thứ hai là liên hệ trực tiếp với giá trị ngưỡng khởi động chậm ssthresh. Vì giá trị của ssthresh bằng một nửa giá trị cửa sổ khi phát hiện tắc nghẽn, nên có thể xảy ra mất gói với mỗi lần tăng gấp đôi khi cwnd lớn hơn ssthresh. Do đó, tốt nhất là nên đặt cwnd bằng ssthresh, điều này sẽ khiến TCP chuyển sang chế độ kiểm soát tắc nghẽn và kết thúc quá trình khởi động chậm.

Cách cuối cùng để kết thúc hiện tượng khởi động chậm là khi phát hiện ba gói ACK dư thừa, TCP sẽ thực hiện truyền lại nhanh và chuyển sang trạng thái phục hồi. (Nếu chưa rõ lý do tại sao lại có ba gói ACK, điều này sẽ được giải thích riêng trong cơ chế truyền lại.)

Tránh tắc nghẽn
Khi TCP chuyển sang trạng thái kiểm soát tắc nghẽn, cwnd được đặt bằng một nửa ngưỡng tắc nghẽn ssthresh. Điều này có nghĩa là giá trị của cwnd không thể tăng gấp đôi mỗi khi nhận được một phân đoạn gói tin. Thay vào đó, một phương pháp tương đối thận trọng được áp dụng, trong đó giá trị của cwnd chỉ tăng lên một MSS (chiều dài phân đoạn gói tin tối đa) sau mỗi lần truyền hoàn tất. Ví dụ, ngay cả khi 10 phân đoạn gói tin được xác nhận, giá trị của cwnd cũng chỉ tăng lên một MSS. Đây là mô hình tăng trưởng tuyến tính và nó cũng có giới hạn trên về tốc độ tăng trưởng. Khi xảy ra mất gói tin, giá trị của cwnd được thay đổi thành MSS, và giá trị của ssthresh được đặt bằng một nửa của cwnd. Hoặc nó cũng sẽ dừng sự tăng trưởng của MSS khi nhận được 3 phản hồi ACK dư thừa. Nếu vẫn nhận được ba phản hồi ACK dư thừa sau khi giảm một nửa giá trị của cwnd, giá trị của ssthresh được ghi nhận bằng một nửa giá trị của cwnd và trạng thái phục hồi nhanh được kích hoạt.

Phục hồi nhanh chóng
Ở trạng thái Khôi phục Nhanh, giá trị của cửa sổ tắc nghẽn cwnd được tăng thêm một MSS cho mỗi ACK dư thừa nhận được, tức là ACK không đến theo trình tự. Điều này nhằm tận dụng tối đa các phân đoạn gói tin đã được truyền thành công trong mạng để cải thiện hiệu quả truyền dẫn.

Khi nhận được gói tin ACK về phân đoạn gói tin bị mất, TCP sẽ giảm giá trị của cwnd và sau đó chuyển sang trạng thái tránh tắc nghẽn. Điều này nhằm kiểm soát kích thước của cửa sổ tắc nghẽn và tránh làm tăng thêm tình trạng tắc nghẽn mạng.

Nếu xảy ra lỗi hết thời gian chờ sau khi chuyển sang trạng thái kiểm soát tắc nghẽn, tình trạng mạng sẽ trở nên nghiêm trọng hơn và TCP chuyển từ trạng thái tránh tắc nghẽn sang trạng thái khởi động chậm. Trong trường hợp này, giá trị của cửa sổ tắc nghẽn cwnd được đặt thành 1 MSS, độ dài phân đoạn gói tối đa, và giá trị của ngưỡng khởi động chậm ssthresh được đặt bằng một nửa của cwnd. Mục đích của việc này là để tăng dần kích thước của cửa sổ tắc nghẽn sau khi mạng phục hồi nhằm cân bằng tốc độ truyền tải và mức độ tắc nghẽn mạng.

Bản tóm tắt
Là một giao thức vận chuyển đáng tin cậy, TCP thực hiện vận chuyển đáng tin cậy bằng cách sử dụng số thứ tự, xác nhận, kiểm soát truyền lại, quản lý kết nối và kiểm soát cửa sổ. Trong đó, cơ chế kiểm soát luồng điều khiển lượng dữ liệu được gửi bởi người gửi dựa trên khả năng nhận thực tế của người nhận, giúp tránh các vấn đề tắc nghẽn mạng và suy giảm hiệu suất. Cơ chế kiểm soát tắc nghẽn tránh xảy ra tắc nghẽn mạng bằng cách điều chỉnh lượng dữ liệu được gửi bởi người gửi. Khái niệm cửa sổ tắc nghẽn và cửa sổ gửi có liên quan đến nhau, và lượng dữ liệu tại người gửi được kiểm soát bằng cách điều chỉnh động kích thước của cửa sổ tắc nghẽn. Khởi động chậm, tránh tắc nghẽn và phục hồi nhanh là ba phần chính của thuật toán kiểm soát tắc nghẽn TCP, điều chỉnh kích thước của cửa sổ tắc nghẽn thông qua các chiến lược khác nhau để thích ứng với dung lượng và mức độ tắc nghẽn của mạng.

Trong phần tiếp theo, chúng ta sẽ xem xét chi tiết cơ chế truyền lại của TCP. Cơ chế truyền lại là một phần quan trọng của TCP để đạt được khả năng truyền tải đáng tin cậy. Nó đảm bảo việc truyền tải dữ liệu đáng tin cậy bằng cách truyền lại dữ liệu bị mất, bị hỏng hoặc bị chậm trễ. Nguyên tắc và chiến lược thực hiện của cơ chế truyền lại sẽ được giới thiệu và phân tích chi tiết trong phần tiếp theo. Hãy đón xem!


Thời gian đăng bài: 24/02/2025