time_wait & close_wait
Giới thiệu: TIME_WAIT là một trạng thái trong quá trình đóng kết nối TCP, nó được hình thành như sau: 1 Chủ động đóng phần cuối A: gửi FIN, nhập trạng thái FIN-WAIT-1 và đợi ... 2 Đóng thụ động phần cuối P : Sau khi nhận được FIN, nó phải gửi ngay ACK, nhập trạng thái CLOSE_WAIT và đợi.
TIME_WAIT là một trạng thái trong quá trình đóng kết nối TCP, được hình thành cụ thể như sau:
- A Chủ động đóng: gửi FIN, nhập trạng thái FIN-WAIT-1 và đợi ...
- P Đóng thụ động : nhận ACK phải được gửi ngay sau khi FIN, nhập trạng thái CLOSE_WAIT và chờ ..
- A Chủ động đóng : Sau khi nhận được ACK, hãy nhập trạng thái FIN-WAIT-2 và chờ ...
- P Đóng kết thúc một cách thụ động: Gửi FIN, nhập trạng thái LAST_ACK và đợi ..
- A Chủ động đóng kết thúc : Sau khi nhận được FIN, nó phải gửi ACK ngay lập tức, nhập trạng thái TIME_WAIT và kết thúc Socket
- sau khi đợi 2MSL. P Kết thúc đóng thụ động: Sau khi nhận Ổ cắm kết thúc ACK
Do đó, trạng thái TIME_WAIT xuất hiện tại điểm mà kết nối được chủ động bắt đầu để đóng và không liên quan đến ai đã khởi tạo kết nối. Nó có thể là phía máy khách hoặc phía máy chủ.
Và từ trạng thái TIME_WAIT đến trạng thái CLOSED, có một cài đặt thời gian chờ, cài đặt thời gian chờ này là 2 * MSL (RFC793 định nghĩa MSL là 2 phút, Linux được đặt thành 30 giây)
Tại sao tôi cần TIME_WAIT?
Có hai lý do chính:
1) Để đảm bảo rằng cả hai đầu có thể đóng hoàn toàn kết nối.
Giả sử rằng máy chủ A đang chủ động đóng kết nối và máy chủ B là bên bị động. Nếu không có trạng thái TIME_WAIT, máy chủ A sẽ gửi ACK cuối cùng và chuyển sang trạng thái CLOSED. Nếu ACK không được đồng đẳng nhận, đồng đẳng không thể hoàn thành quá trình đóng. Nếu đầu đối diện không nhận được ACK, nó sẽ truyền lại FIN. Lúc này, kết nối bị đóng và FIN không thể nhận ACK. Nếu có TIME_WAIT, ACK sẽ được truyền lại để đảm bảo rằng đầu đối diện có thể đóng kết nối bình thường.
2) Để đảm bảo rằng các kết nối tiếp theo sẽ không nhận được "dữ liệu bẩn"
vừa được đề cập rằng sau khi kết thúc hoạt động nhập TIME_WAIT, hãy đợi 2MSL và sau đó là CLOSE, nơi MSL đề cập đến (thời gian tồn tại của phân đoạn tối đa, hạt nhân của chúng ta thường là 30 giây, 2MSL 1 phút), Vòng đời lớn nhất của gói dữ liệu trên mạng. Điều này là để tạo kết nối có cùng thông số (IP nguồn / PORT, IP / PORT đích) sau khi tất cả các phân đoạn trùng lặp cũ xuất hiện do quá trình truyền lại trên mạng biến mất. Nếu thời gian chờ không đủ lâu, hãy tạo lại . Cùng một kết nối, và sau đó nhận được phân đoạn cũ trùng lặp, dữ liệu không theo thứ tự.
TIME_WAIT có thể gây ra sự cố gì?
1) Kết nối mới không thành công từ
TIME_WAIT đến CLOSED và mất 2MSL = 60 giây. Thời gian này còn rất dài. Phải mất 60 giây để giải phóng hoàn toàn mỗi kết nối sau khi dịch vụ kết thúc. Nếu chế độ kết nối ngắn được áp dụng trong doanh nghiệp, nó sẽ gây ra rất nhiều kết nối ở trạng thái TIME_WAIT, điều này sẽ chiếm một số tài nguyên, chủ yếu là tài nguyên cổng cục bộ.
Các cổng khả dụng cục bộ của máy chủ bị giới hạn, có hàng chục nghìn cổng, được điều khiển bởi tham số này:
sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768 61000
Khi máy chủ có nhiều kết nối TIME_WAIT, các cổng cục bộ là tất cả Nếu nó bị chiếm, nó không thể bắt đầu một kết nối mới để kết nối với các máy chủ khác.
Ở đây cần lưu ý rằng vấn đề này gặp phải khi bên chủ động khởi tạo kết nối và bắt đầu tắt máy.
Nếu phía máy chủ chủ động đóng kết nối do phía máy khách thiết lập và tạo ra một số lượng lớn kết nối TIME_WAIT, sự cố này sẽ không xảy ra. Trừ khi có hàng chục nghìn kết nối TIME_WAIT cho một ứng dụng khách nhất định tham gia.
2) Mục nhập TIME_WAIT vượt quá
giới hạn, được kiểm soát bởi tham số hạt nhân:
sysctl net.ipv4.tcp_max_tw_buckets
net.ipv4.tcp_max_tw_buckets = 5000 Nếu
vượt quá giới hạn này, nhật ký hạt nhân cấp INFO sẽ được báo cáo và sau đó kết nối sẽ tiếp tục bị đóng. Nó không có tác động đặc biệt lớn, nó chỉ làm tăng nguy cơ nhận dữ liệu bẩn vừa được đề cập.
Một rủi ro khác là sau khi đóng kết nối TIME_WAIT, nếu ACK vừa được gửi bởi đầu đối diện không được nhận, khi gói FIN được truyền lại, ACK không thể được trả về một cách chính xác, nhưng gói RST được trả lại, khiến chương trình kết thúc ngược lại báo lỗi, nói rằng đặt lại kết nối.
Do đó, không nên thay đổi thông số net.ipv4.tcp_max_tw_buckets thành giá trị nhỏ hơn. Thay đổi kích thước thành giá trị nhỏ hơn sẽ mang lại rủi ro và không có lợi. Chỉ là TIME_WAIT nhìn thấy qua netstat trên bề mặt là ít hơn. việc sử dụng?
Và, gợi ý là tăng giá trị này khi không có đủ mục nhập, nó chỉ lãng phí một chút bộ nhớ.
3) Cách giải quyết time_wait?
1) Giải pháp tốt nhất là áp dụng chuyển đổi kết nối dài, nhưng nó thường không áp dụng được.
2) Sửa đổi thông số khôi phục hệ thống và
đặt các thông số sau
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_recycle = 1
Điều gì sẽ xảy ra nếu tham số này được thiết lập?
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_tw_recycle = 1
Nếu hai tham số này được bật cùng lúc, nó sẽ xác minh xem dấu thời gian được mang trong gói từ ip nguồn có tăng lên hay không. Nếu không tăng, three -way bắt tay sẽ không thành công., biểu hiện cụ thể là khi bạn thấy syn gửi ra khi chụp gói tin thì server không phản hồi lại syn ack
, nói chung một mạng cục bộ có nhiều client cùng truy cập vào bạn. Nếu thời gian của một khách hàng chậm hơn so với các khách hàng khác, nó sẽ Cách không thành công để
điều trị các triệu chứng nhưng không phải là nguyên nhân gốc rễ của việc thành lập liên minh không thành công :
mở rộng phạm vi cổng
sysctl net.ipv4.ip_local_port_range
net.ipv4.ip_local_port_range = 32768 61000
phóng to giới hạn thời gian_wait
sysctl net.ipv4.tcp_max_tw_buckets
net.ipv4.tcp_max_tw_buckets = 180000
Về việc liệu net.ipv4.tcp_max_tw_buckets có nên được phóng to hay không, hầu hết các ecs trên đám mây hiện được đặt 5.000, cá nhân tôi nghĩ rằng nó nhỏ
Trong các tình huống đặc biệt (khi cơ hội này khởi tạo một số lượng lớn các liên kết ngắn)
1. nginx kết hợp với php-fpm cần khởi động cổng cục bộ,
2. tạo ngược nginx chẳng hạn như (java, container, v.v.)
như thể hiện trong hình bên dưới,
tham số tcp_tw_reuse cần được kết hợpss với net.ipv4 .tcp_timestamps = 1 Khi được sử dụng cùng nhau
, máy chủ là máy khách và khi nó cũng là máy chủ,
tham số tcp_tw_reuse được sử dụng để đặt liệu ổ cắm ở trạng thái TIME_WAIT có thể được sử dụng lại trong một kết nối mới. Lưu ý rằng số cổng được sử dụng bởi ổ cắm TIME_WAIT được sử dụng lại, không phải bộ nhớ của ổ cắm TIME_WAIT. Tham số này có ý nghĩa đối với máy khách. Khi chủ động khởi tạo kết nối, nó sẽ kiểm tra xem socket ở trạng thái TIME_WAIT có thể được sử dụng lại trong lệnh gọi inet_hash_connect () hay không. Nếu bạn đặt thông số này trong phần máy chủ, nó không có tác dụng, vì ổ cắm ở trạng thái ĐÃ THIẾT LẬP ở phía máy chủ và IP cục bộ và số cổng của ổ cắm nghe là giống nhau, và không có khái niệm sử dụng lại. Nhưng nó không có nghĩa là không có ổ cắm trạng thái TIME_WAIT ở phía máy chủ.
Do đó, khuyến nghị cuối cùng cho loại cảnh này là
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_max_tw_buckets = 30000
net.ipv4.ip_local_port_range = 15000 65000
Như hình trên, trạng thái CLOSE_WAIT là sau khi chương trình máy chủ / máy khách nhận được FIN từ bên ngoài, nó sẽ phản hồi lại gói ACK, sau đó đi vào trạng thái CLOSE_WAIT. Nói chung, nếu mọi thứ diễn ra bình thường, chương trình máy chủ / máy khách cần gửi gói FIN sau đó chuyển sang trạng thái LAST_ACK. Sau khi nhận ACK từ đầu đối diện, toàn bộ quá trình đóng kết nối TCP đã hoàn tất.
Lưu ý: Cho dù đó là máy chủ hay máy khách, miễn là bên thụ động nhận được FIN đầu tiên sẽ vào trạng thái CLOSE_WAIT
Nhận xét
Đăng nhận xét