Nếu mạng ở giữa không chịu nổi thì sao?
TCP biết mình đang gửi quá nhiều dữ liệu vào mạng bằng cách nào?
Ở bài trước, máy nhận có thể nói:
rwnd = 1 MB
nghĩa là nó vẫn còn chỗ nhận thêm khoảng 1 MB dữ liệu.
Nhưng dữ liệu từ máy gửi tới máy nhận thường phải đi qua nhiều router.
Máy nhận còn chỗ không có nghĩa là mạng ở giữa cũng còn chịu được.
Nếu dữ liệu đi vào nhanh hơn đi ra thì sao?
Giả sử một router nhận dữ liệu từ nhiều kết nối với tổng tốc độ:
100 Mbps
nhưng đường truyền phía sau nó chỉ chuyển tiếp được:
20 Mbps
Router không thể đẩy hết dữ liệu đi ngay.
Phần chưa gửi kịp phải nằm trong hàng đợi:
nhiều dữ liệu đi vào
↓
↓
[ hàng đợi ]
↓
đường ra 20 Mbps
Router chỉ chuyển đi được 3 gói mỗi lượt
-
3 gói tới
Routerđi hết, hàng đợi trống
-
6 gói tới
Router3 gói phải chờ
-
Gói vẫn tới dồn
Router ✕ bị bỏhàng đợi đầy, gói mới bị bỏ
Nếu chỉ xảy ra trong chốc lát thì không sao.
Nhưng nếu dữ liệu liên tục đi vào nhanh hơn đi ra, hàng đợi sẽ dài dần. Gói tin phải chờ lâu hơn.
Đến khi hàng đợi đầy, router buộc phải bỏ bớt gói tin.
Đó là nghẽn mạng.
Máy gửi không biết mạng chịu được bao nhiêu
Khi một kết nối TCP mới bắt đầu, máy gửi không biết đường tới máy nhận đang rộng hay hẹp.
Nó cũng không biết có bao nhiêu người khác đang dùng chung đường truyền đó.
Nếu gửi quá ít, đường truyền bị bỏ phí.
Nếu gửi quá nhiều, hàng đợi ở một router nào đó có thể đầy.
TCP vì vậy phải tự dò:
gửi một ít
↓
thấy vẫn ổn
↓
gửi nhiều hơn
↓
thấy dấu hiệu nghẽn
↓
giảm xuống
Để làm việc này, TCP giữ một giới hạn gọi là cửa sổ nghẽn (cwnd).
Ví dụ:
cwnd = 16 KB
có nghĩa là máy gửi chỉ cho phép khoảng 16 KB dữ liệu đang ở trên mạng mà chưa được xác nhận.
Khi xác nhận (ACK) quay về, TCP biết một phần dữ liệu đã tới nơi và có thể gửi thêm.
Lúc đầu TCP tăng khá nhanh
TCP chưa biết mạng chịu được bao nhiêu, nên nó bắt đầu tương đối thận trọng.
Giả sử ban đầu chỉ cho phép một phần dữ liệu đang trên đường:
■
Dữ liệu tới nơi, xác nhận quay về.
TCP tăng giới hạn:
■ ■
Nếu vẫn ổn:
■ ■ ■ ■
rồi:
■ ■ ■ ■ ■ ■ ■ ■
Giai đoạn này gọi là khởi động chậm (slow start).
Mỗi ACK cho cwnd thêm 1 đoạn
- RTT 1 cwnd = 1
- RTT 2 cwnd = 2
- RTT 3 cwnd = 4
- RTT 4 cwnd = 8
Tên là “chậm”, nhưng sau khi bắt đầu thì lượng dữ liệu được phép gửi tăng khá nhanh.
Có thể hình dung đơn giản:
1 → 2 → 4 → 8 → 16
TCP đang nhanh chóng dò xem mạng còn chịu được tới đâu.
Nhưng không thể tăng mãi
Giả sử mạng hiện chỉ chịu được khoảng:
20 phần dữ liệu
TCP lại thử:
8 → 16 → 32
Ở mức 16 vẫn ổn.
Nhưng khi tiến lên 32, phần dư bắt đầu tích lại trong hàng đợi của router.
Đầu tiên, dữ liệu mất nhiều thời gian hơn để tới nơi.
Nếu hàng đợi đầy, một số gói tin bị bỏ.
Đó là tín hiệu cho TCP rằng:
mình đang gửi quá nhiều
TCP phải giảm xuống.
Gần giới hạn thì tăng chậm hơn
Sau khi đã tiến gần tới khả năng của mạng, TCP không tiếp tục tăng kiểu:
8 → 16 → 32
nữa.
Nó chuyển sang tăng từ từ hơn:
8 → 9 → 10 → 11 → 12
Cách này gọi là tránh nghẽn (congestion avoidance).
Ý tưởng rất đơn giản:
mạng vừa chịu được mức 10
→ thử 11
vẫn ổn
→ thử 12
thay vì vừa thấy ổn đã thử gấp đôi.
TCP biết mạng nghẽn bằng cách nào?
Máy gửi không nhìn thấy hàng đợi bên trong các router.
Nó chỉ nhìn được những gì xảy ra với dữ liệu mình đã gửi.
Một tín hiệu rất quan trọng là mất gói tin.
Giả sử TCP gửi:
101
102
103
104
105
nhưng gói 103 bị bỏ ở một router.
Máy nhận vẫn có thể nhận:
101
102
104
105
Các xác nhận quay về cho máy gửi cho thấy đang thiếu một đoạn ở giữa.
TCP có thể gửi lại gói bị mất, đồng thời giảm cửa sổ nghẽn vì đây có thể là dấu hiệu mạng đang quá tải.
Nếu tình trạng nghiêm trọng đến mức phải chờ rất lâu mà vẫn không nhận được xác nhận, TCP sẽ giảm mạnh hơn nữa.
TCP tăng và giảm lượng dữ liệu đang gửi như thế nào?
Vì vậy cửa sổ nghẽn thường có dạng:
tăng dần
tăng dần
tăng dần
↓
phát hiện nghẽn
↓
giảm xuống
↓
lại tăng dần
TCP cứ lặp lại quá trình này để tìm mức gửi phù hợp với tình trạng mạng hiện tại.
Có nhất thiết phải mất gói mới biết mạng đang nghẽn không?
Không.
Một số mạng hỗ trợ thông báo nghẽn rõ ràng (ECN).
Khi hàng đợi bắt đầu đầy, router có thể đánh dấu gói tin để báo:
đường phía trước đang bắt đầu nghẽn
Máy gửi nhận được tín hiệu đó và giảm tốc trước khi router phải bỏ gói.
Nhưng dù phát hiện bằng cách nào, ý tưởng vẫn giống nhau:
mạng ổn
→ tăng
mạng bắt đầu quá tải
→ giảm
cwnd không phải là tốc độ mạng
cwnd không có nghĩa là:
100 Mbps
Nó là lượng dữ liệu được phép đang ở trên đường mà chưa được xác nhận.
Ví dụ cùng một:
cwnd = 100 KB
nhưng nếu xác nhận quay về sau 10 mili giây, máy gửi có thể gửi vòng tiếp theo rất sớm.
Nếu phải mất 200 mili giây mới nhận được xác nhận, máy gửi phải chờ lâu hơn.
Khoảng thời gian từ lúc gửi dữ liệu đi cho tới khi tín hiệu phản hồi quay về thường được gọi là thời gian khứ hồi (RTT).
Vì vậy tốc độ truyền thực tế phụ thuộc cả vào:
cửa sổ nghẽn
+
thời gian phản hồi của mạng
Bên gửi
cwnd: tối đa 8 gói chưa được xác nhận
4 gói còn chờ · gửi thêm 4
chưa thấy dấu hiệu nghẽn → tiếp tục tăng
Router
chuyển đi tối đa 3 gói mỗi lượt
hết chỗ: bỏ 1 gói
Bên nhận
vẫn nhận kịp
cwnd qua từng lượt: 12345678↓456
Máy nhận và mạng cùng giới hạn máy gửi
TCP lúc này có hai giới hạn.
Máy nhận có thể báo:
rwnd = 64 KB
nghĩa là:
tôi còn chỗ nhận 64 KB
Trong khi TCP tự tính:
cwnd = 16 KB
nghĩa là:
mạng hiện tại chỉ nên có khoảng
16 KB dữ liệu chưa được xác nhận
Máy gửi phải nghe giới hạn nhỏ hơn.
Trong trường hợp này, dù máy nhận còn rất nhiều chỗ, TCP vẫn chỉ nên để khoảng 16 KB dữ liệu trên mạng.
Hai cơ chế đang bảo vệ hai nơi khác nhau:
rwnd
→ đừng làm máy nhận quá tải
cwnd
→ đừng làm mạng ở giữa quá tải
Đó là cách TCP vừa tận dụng đường truyền, vừa tránh liên tục đẩy quá nhiều dữ liệu vào mạng.
Nhưng TCP còn đưa ra một lời hứa khác: dữ liệu giao cho ứng dụng phải đầy đủ và đúng thứ tự.
Nếu một phần ở giữa chưa tới, dữ liệu phía sau dù đã tới nơi cũng có thể phải chờ.
Có phải ứng dụng nào cũng muốn chờ mọi byte về đủ?