Câu chuyện về việc thiếu gói DNS từ bộ phận hỗ trợ kỹ thuật của Google Cloud

Từ Trình chỉnh sửa blog của Google : Bạn đã bao giờ tự hỏi các kỹ sư của Giải pháp kỹ thuật đám mây (TSE) của Google xử lý các yêu cầu hỗ trợ của bạn như thế nào chưa? Các kỹ sư hỗ trợ kỹ thuật của TSE chịu trách nhiệm xác định và khắc phục các nguồn vấn đề do người dùng báo cáo. Một số vấn đề trong số này khá đơn giản, nhưng đôi khi bạn gặp phải một vấn đề đòi hỏi sự chú ý của nhiều kỹ sư cùng một lúc. Trong bài viết này, một trong những nhân viên của TSE sẽ kể cho chúng ta nghe về một vấn đề rất phức tạp trong quá trình làm việc gần đây của anh ấy - trường hợp thiếu gói DNS. Trong câu chuyện này, chúng ta sẽ xem các kỹ sư đã giải quyết tình huống như thế nào và họ đã học được những điều mới gì khi sửa lỗi. Chúng tôi hy vọng câu chuyện này không chỉ giúp bạn biết về một lỗi sâu xa mà còn cung cấp cho bạn thông tin chi tiết về các quy trình gửi yêu cầu hỗ trợ với Google Cloud.

Câu chuyện về việc thiếu gói DNS từ bộ phận hỗ trợ kỹ thuật của Google Cloud

Khắc phục sự cố vừa là khoa học vừa là nghệ thuật. Tất cả bắt đầu bằng việc xây dựng một giả thuyết về lý do dẫn đến hành vi không chuẩn của hệ thống, sau đó nó được kiểm tra sức mạnh. Tuy nhiên, trước khi hình thành một giả thuyết, chúng ta phải xác định rõ ràng và hình thành chính xác vấn đề. Nếu câu hỏi nghe có vẻ quá mơ hồ thì bạn sẽ phải phân tích mọi thứ một cách cẩn thận; Đây chính là “nghệ thuật” xử lý sự cố.

Trong Google Cloud, các quy trình như vậy trở nên phức tạp hơn theo cấp số nhân vì Google Cloud cố gắng hết sức để đảm bảo quyền riêng tư của người dùng. Do đó, các kỹ sư TSE không có quyền truy cập để chỉnh sửa hệ thống của bạn cũng như không có khả năng xem cấu hình một cách rộng rãi như người dùng. Do đó, để kiểm tra bất kỳ giả thuyết nào của chúng tôi, chúng tôi (các kỹ sư) không thể sửa đổi hệ thống một cách nhanh chóng.

Một số người dùng tin rằng chúng tôi sẽ sửa mọi thứ như cơ khí trong dịch vụ ô tô và chỉ cần gửi cho chúng tôi id của máy ảo, trong khi trên thực tế, quá trình này diễn ra ở dạng hội thoại: thu thập thông tin, hình thành và xác nhận (hoặc bác bỏ) các giả thuyết, và cuối cùng, việc quyết định các vấn đề đều dựa trên sự giao tiếp với khách hàng.

Vấn đề đang được đề cập

Hôm nay chúng ta có một câu chuyện với một kết thúc có hậu. Một trong những lý do giúp giải quyết thành công trường hợp được đề xuất là mô tả vấn đề rất chi tiết và chính xác. Dưới đây bạn có thể xem bản sao của vé đầu tiên (đã được chỉnh sửa để ẩn thông tin bí mật):
Câu chuyện về việc thiếu gói DNS từ bộ phận hỗ trợ kỹ thuật của Google Cloud
Tin nhắn này chứa rất nhiều thông tin hữu ích cho chúng tôi:

  • VM cụ thể được chỉ định
  • Bản thân vấn đề đã được chỉ ra - DNS không hoạt động
  • Nó được chỉ ra nơi vấn đề xuất hiện - VM và container
  • Các bước người dùng thực hiện để xác định vấn đề sẽ được chỉ ra.

Yêu cầu đã được đăng ký là “P1: Tác động nghiêm trọng - Dịch vụ không thể sử dụng được trong sản xuất”, nghĩa là phải theo dõi liên tục tình hình 24/7 theo kế hoạch “Theo dõi Mặt trời” (bạn có thể đọc thêm về mức độ ưu tiên của yêu cầu người dùng), với sự chuyển giao từ nhóm hỗ trợ kỹ thuật này sang nhóm hỗ trợ kỹ thuật khác theo mỗi lần thay đổi múi giờ. Trên thực tế, vào thời điểm vấn đề đến với nhóm của chúng tôi ở Zurich, nó đã lan rộng ra toàn cầu. Vào thời điểm này, người dùng đã thực hiện các biện pháp giảm thiểu nhưng lo ngại tình trạng này sẽ lặp lại trong quá trình sản xuất vì nguyên nhân cốt lõi vẫn chưa được tìm ra.

Vào thời điểm vé đến Zurich, chúng tôi đã có trong tay những thông tin sau:

  • Nội dung /etc/hosts
  • Nội dung /etc/resolv.conf
  • Đầu ra iptables-save
  • Được lắp ráp bởi nhóm ngrep tập tin pcap

Với dữ liệu này, chúng tôi đã sẵn sàng bắt đầu giai đoạn “điều tra” và khắc phục sự cố.

Những bước đầu tiên của chúng tôi

Trước hết, chúng tôi đã kiểm tra nhật ký và trạng thái của máy chủ siêu dữ liệu và đảm bảo rằng nó hoạt động chính xác. Máy chủ siêu dữ liệu phản hồi địa chỉ IP 169.254.169.254 và chịu trách nhiệm kiểm soát tên miền. Chúng tôi cũng đã kiểm tra kỹ xem tường lửa có hoạt động chính xác với VM và không chặn gói tin hay không.

Đó là một loại vấn đề kỳ lạ nào đó: kiểm tra nmap đã bác bỏ giả thuyết chính của chúng tôi về việc mất gói UDP, vì vậy chúng tôi đã nghĩ ra thêm một số tùy chọn và cách để kiểm tra chúng:

  • Các gói có bị loại bỏ có chọn lọc không? => Kiểm tra quy tắc iptables
  • Có phải nó quá nhỏ không? MTU? => Kiểm tra đầu ra ip a show
  • Có phải sự cố chỉ ảnh hưởng đến gói UDP hoặc TCP không? => Lái xe đi dig +tcp
  • Các gói được tạo ra có được trả lại không? => Lái xe đi tcpdump
  • libdns có hoạt động chính xác không? => Lái xe đi strace để kiểm tra việc truyền gói tin theo cả hai hướng

Ở đây chúng tôi quyết định gọi cho người dùng để khắc phục sự cố trực tiếp.

Trong cuộc gọi, chúng tôi có thể kiểm tra một số điều:

  • Sau nhiều lần kiểm tra, chúng tôi loại trừ các quy tắc iptables khỏi danh sách các lý do
  • Chúng tôi kiểm tra giao diện mạng và bảng định tuyến, đồng thời kiểm tra kỹ xem MTU có đúng không
  • Chúng tôi khám phá ra rằng dig +tcp google.com (TCP) hoạt động như bình thường, nhưng dig google.com (UDP) không hoạt động
  • Đã lái xe đi tcpdump nó vẫn đang hoạt động dig, chúng tôi thấy rằng các gói UDP đang được trả lại
  • Chúng tôi lái xe đi strace dig google.com và chúng ta thấy cách gọi dig chính xác sendmsg() и recvms(), tuy nhiên cái thứ hai bị gián đoạn do hết thời gian chờ

Thật không may, ca làm việc đã đến và chúng tôi buộc phải chuyển vấn đề sang múi giờ tiếp theo. Tuy nhiên, yêu cầu này đã thu hút sự quan tâm trong nhóm của chúng tôi và một đồng nghiệp đề xuất tạo gói DNS ban đầu bằng cách sử dụng mô-đun Python vụn.

from scapy.all import *

answer = sr1(IP(dst="169.254.169.254")/UDP(dport=53)/DNS(rd=1,qd=DNSQR(qname="google.com")),verbose=0)
print ("169.254.169.254", answer[DNS].summary())

Đoạn này tạo gói DNS và gửi yêu cầu đến máy chủ siêu dữ liệu.

Người dùng chạy mã, phản hồi DNS được trả về và ứng dụng nhận được mã đó, xác nhận rằng không có vấn đề gì ở cấp độ mạng.

Sau một “chuyến đi vòng quanh thế giới” khác, yêu cầu sẽ quay trở lại nhóm của chúng tôi và tôi hoàn toàn chuyển nó cho chính mình, vì nghĩ rằng sẽ thuận tiện hơn cho người dùng nếu yêu cầu ngừng luân chuyển từ nơi này sang nơi khác.

Trong thời gian chờ đợi, người dùng vui lòng đồng ý cung cấp ảnh chụp nhanh của hình ảnh hệ thống. Đây là một tin rất vui: khả năng tự kiểm tra hệ thống giúp việc khắc phục sự cố nhanh hơn rất nhiều, vì tôi không còn phải yêu cầu người dùng chạy lệnh, gửi cho tôi kết quả và phân tích chúng, tôi có thể tự mình làm mọi việc!

Các đồng nghiệp của tôi đang bắt đầu ghen tị với tôi một chút. Trong bữa trưa, chúng tôi thảo luận về việc chuyển đổi, nhưng không ai biết chuyện gì đang xảy ra. May mắn thay, bản thân người dùng đã thực hiện các biện pháp để giảm thiểu hậu quả và không vội vàng nên chúng tôi có thời gian mổ xẻ vấn đề. Và vì chúng tôi có hình ảnh nên chúng tôi có thể chạy bất kỳ thử nghiệm nào mà chúng tôi quan tâm. Tuyệt vời!

Lùi lại một bước

Một trong những câu hỏi phỏng vấn phổ biến nhất cho vị trí kỹ sư hệ thống là: “Điều gì xảy ra khi bạn ping www.google.com? Câu hỏi này rất hay, vì ứng viên cần mô tả mọi thứ từ shell đến không gian người dùng, kernel hệ thống và sau đó là mạng. Tôi mỉm cười: đôi khi những câu hỏi phỏng vấn hóa ra lại có ích trong cuộc sống thực…

Tôi quyết định áp dụng câu hỏi nhân sự này cho một vấn đề hiện tại. Nói một cách đại khái, khi bạn cố gắng xác định tên DNS, điều sau đây sẽ xảy ra:

  1. Ứng dụng gọi một thư viện hệ thống như libdns
  2. libdns kiểm tra cấu hình hệ thống mà máy chủ DNS sẽ liên hệ (trong sơ đồ là 169.254.169.254, máy chủ siêu dữ liệu)
  3. libdns sử dụng lệnh gọi hệ thống để tạo ổ cắm UDP (SOKET_DGRAM) và gửi các gói UDP có truy vấn DNS theo cả hai hướng
  4. Thông qua giao diện sysctl, bạn có thể định cấu hình ngăn xếp UDP ở cấp kernel
  5. Hạt nhân tương tác với phần cứng để truyền các gói qua mạng thông qua giao diện mạng
  6. Trình ảo hóa bắt và truyền gói đến máy chủ siêu dữ liệu khi tiếp xúc với nó
  7. Máy chủ siêu dữ liệu, bằng phép thuật của nó, xác định tên DNS và trả về phản hồi bằng phương pháp tương tự

Câu chuyện về việc thiếu gói DNS từ bộ phận hỗ trợ kỹ thuật của Google Cloud
Hãy để tôi nhắc bạn những giả thuyết mà chúng tôi đã xem xét:

Giả thuyết: Thư viện bị hỏng

  • Kiểm tra 1: chạy strace trong hệ thống, kiểm tra xem dig có gọi đúng lệnh gọi hệ thống không
  • Kết quả: Các cuộc gọi hệ thống chính xác được gọi
  • Kiểm tra 2: sử dụng srapy để kiểm tra xem chúng tôi có thể xác định tên bỏ qua thư viện hệ thống hay không
  • Kết quả: chúng ta có thể
  • Test 3: chạy RPM –V trên gói libdns và file thư viện md5sum
  • Kết quả: mã thư viện hoàn toàn giống với mã trong hệ điều hành đang làm việc
  • Kiểm tra 4: gắn hình ảnh hệ thống gốc của người dùng vào máy ảo mà không có hành vi này, chạy chroot, xem DNS có hoạt động không
  • Kết quả: DNS hoạt động chính xác

Kết luận dựa trên các bài kiểm tra: vấn đề không nằm ở thư viện

Giả thuyết: Có lỗi trong cài đặt DNS

  • Kiểm tra 1: kiểm tra tcpdump và xem các gói DNS có được gửi và trả về chính xác hay không sau khi chạy dig
  • Kết quả: các gói được truyền chính xác
  • Kiểm tra 2: kiểm tra kỹ trên máy chủ /etc/nsswitch.conf и /etc/resolv.conf
  • Kết quả: mọi thứ đều đúng

Kết luận dựa trên các bài kiểm tra: vấn đề không nằm ở cấu hình DNS

Giả thuyết: lõi bị hư hỏng

  • Kiểm tra: cài kernel mới, kiểm tra chữ ký, khởi động lại
  • Kết quả: hành vi tương tự

Kết luận dựa trên các bài kiểm tra: hạt nhân không bị hỏng

Giả thuyết: hành vi không chính xác của mạng người dùng (hoặc giao diện mạng ảo hóa)

  • Kiểm tra 1: Kiểm tra cài đặt tường lửa của bạn
  • Kết quả: tường lửa chuyển các gói DNS trên cả máy chủ và GCP
  • Kiểm tra 2: chặn lưu lượng truy cập và giám sát tính chính xác của việc truyền và trả lại các yêu cầu DNS
  • Kết quả: tcpdump xác nhận rằng máy chủ đã nhận được gói trả về

Kết luận dựa trên các bài kiểm tra: vấn đề không nằm ở mạng

Giả thuyết: máy chủ siêu dữ liệu không hoạt động

  • Kiểm tra 1: kiểm tra nhật ký máy chủ siêu dữ liệu xem có bất thường không
  • Kết quả: không có bất thường nào trong nhật ký
  • Kiểm tra 2: Bỏ qua máy chủ siêu dữ liệu qua dig @8.8.8.8
  • Kết quả: Độ phân giải bị hỏng ngay cả khi không sử dụng máy chủ siêu dữ liệu

Kết luận dựa trên các bài kiểm tra: vấn đề không nằm ở máy chủ siêu dữ liệu

Điểm mấu chốt: chúng tôi đã thử nghiệm tất cả các hệ thống con ngoại trừ cài đặt thời gian chạy!

Đi sâu vào Cài đặt thời gian chạy hạt nhân

Để cấu hình môi trường thực thi kernel, bạn có thể sử dụng các tùy chọn dòng lệnh (grub) hoặc giao diện sysctl. Tôi nhìn vào /etc/sysctl.conf và nghĩ xem, tôi đã phát hiện ra một số cài đặt tùy chỉnh. Cảm thấy như mình đã nắm được thứ gì đó, tôi loại bỏ tất cả các cài đặt không phải mạng hoặc không phải tcp, còn lại cài đặt núi net.core. Sau đó, tôi đi đến nơi có quyền của máy chủ trong VM và bắt đầu áp dụng từng cài đặt lần lượt với máy ảo bị hỏng, cho đến khi tôi tìm ra thủ phạm:

net.core.rmem_default = 2147483647

Đây rồi, một cấu hình phá DNS! Tôi đã tìm thấy vũ khí giết người. Nhưng tại sao điều này lại xảy ra? Tôi vẫn cần một động cơ.

Kích thước bộ đệm gói DNS cơ bản được cấu hình thông qua net.core.rmem_default. Giá trị điển hình là khoảng 200KiB, nhưng nếu máy chủ của bạn nhận được nhiều gói DNS, bạn có thể muốn tăng kích thước bộ đệm. Nếu bộ đệm đầy khi có gói mới đến, chẳng hạn do ứng dụng không xử lý gói đó đủ nhanh thì bạn sẽ bắt đầu mất gói. Khách hàng của chúng tôi đã tăng kích thước bộ đệm một cách chính xác vì anh ấy sợ mất dữ liệu vì anh ấy đang sử dụng một ứng dụng để thu thập số liệu thông qua các gói DNS. Giá trị anh ấy đặt là lớn nhất có thể: 231-1 (nếu được đặt thành 231, kernel sẽ trả về “ARGUMENT KHÔNG HỢP LỆ”).

Đột nhiên tôi nhận ra tại sao nmap và scapy lại hoạt động chính xác: chúng đang sử dụng các socket thô! Ổ cắm thô khác với ổ cắm thông thường: chúng bỏ qua iptables và không được lưu vào bộ đệm!

Nhưng tại sao "bộ đệm quá lớn" lại gây ra vấn đề? Nó rõ ràng không hoạt động như dự định.

Tại thời điểm này tôi có thể tái tạo vấn đề trên nhiều nhân và nhiều bản phân phối. Vấn đề đã xuất hiện trên kernel 3.x và bây giờ nó cũng xuất hiện trên kernel 5.x.

Thật vậy, khi khởi động

sysctl -w net.core.rmem_default=$((2**31-1))

DNS đã ngừng hoạt động.

Tôi bắt đầu tìm kiếm các giá trị hoạt động thông qua thuật toán tìm kiếm nhị phân đơn giản và nhận thấy rằng hệ thống hoạt động với 2147481343, nhưng số này là một tập hợp số vô nghĩa đối với tôi. Tôi đề nghị khách hàng thử số này và anh ấy trả lời rằng hệ thống đã hoạt động với google.com nhưng vẫn báo lỗi với các tên miền khác nên tôi tiếp tục điều tra.

tôi đã cài đồng hồ đeo tay, một công cụ đáng lẽ phải được sử dụng trước đó: nó hiển thị chính xác vị trí kết thúc của gói trong kernel. Thủ phạm là chức năng udp_queue_rcv_skb. Tôi đã tải xuống các nguồn kernel và thêm một vài chức năng printk để theo dõi chính xác nơi gói tin kết thúc. Tôi nhanh chóng tìm thấy điều kiện phù hợp if, và chỉ nhìn chằm chằm vào nó một lúc, bởi vì đó là lúc mọi thứ cuối cùng kết hợp lại thành một bức tranh hoàn chỉnh: 231-1, một con số vô nghĩa, một miền không hoạt động... Đó là một đoạn mã trong __udp_enqueue_schedule_skb:

if (rmem > (size + sk->sk_rcvbuf))
		goto uncharge_drop;

Xin lưu ý:

  • rmem có kiểu int
  • size có loại u16 (unsigned XNUMX-bit int) và lưu trữ kích thước gói
  • sk->sk_rcybuf có kiểu int và lưu trữ kích thước bộ đệm, theo định nghĩa, bằng giá trị trong net.core.rmem_default

Khi sk_rcvbuf tiến tới 231, việc tính tổng kích thước gói có thể dẫn đến tràn số nguyên. Và vì nó là một số nguyên nên giá trị của nó trở thành số âm, do đó điều kiện trở thành đúng khi lẽ ra nó phải sai (bạn có thể đọc thêm về điều này tại liên kết).

Lỗi có thể được sửa chữa một cách đơn giản: bằng cách truyền unsigned int. Tôi đã áp dụng bản sửa lỗi và khởi động lại hệ thống và DNS đã hoạt động trở lại.

Hương vị chiến thắng

Tôi đã chuyển tiếp những phát hiện của mình cho khách hàng và gửi LKML bản vá hạt nhân. Tôi hài lòng: mọi mảnh ghép đều khớp với nhau, tôi có thể giải thích chính xác lý do tại sao chúng tôi quan sát được những gì chúng tôi quan sát được và quan trọng nhất là chúng tôi có thể tìm ra giải pháp cho vấn đề nhờ tinh thần đồng đội của chúng tôi!

Cần phải thừa nhận rằng trường hợp này rất hiếm và may mắn thay, chúng tôi hiếm khi nhận được những yêu cầu phức tạp như vậy từ người dùng.

Câu chuyện về việc thiếu gói DNS từ bộ phận hỗ trợ kỹ thuật của Google Cloud


Nguồn: www.habr.com

Thêm một lời nhận xét