Blog

Cách chúng tôi đưa triển khai về không có lỗi 502

Mỗi lần chúng tôi triển khai backend của Mythex, một số ít yêu cầu bị lỗi 502 Bad Gateway. Không nhiều — nhưng một lỗi 502 trong lúc triển khai nghĩa là một cú nhấp của ai đó không có tác dụng, hoặc một bản build mà họ đang theo dõi bị đứng một lúc. Chúng tôi truy ra hai vấn đề riêng biệt: một watchdog tự phục hồi tranh chấp với các lần triển khai, và khoảng cách giữa lúc một máy chủ ngừng lắng nghe và lúc load balancer ngừng gửi lưu lượng đến nó. Qua ba lần triển khai production liên tiếp sau khi sửa, số lỗi giảm từ 10 xuống 6 và cuối cùng là 0.

Thiết lập

API và orchestrator của chúng tôi chạy dưới dạng container trên một nhóm máy chủ nhỏ phía sau một Application Load Balancer (ALB) của AWS. Một lần triển khai cập nhật từng máy chủ một: nó rút các container cũ ra, khởi động container mới, rồi chuyển sang máy tiếp theo. Một watchdog trên mỗi máy chủ kiểm tra các container có đang chạy không và khởi động lại bất cứ cái nào không chạy — nó tồn tại để một tiến trình bị crash lúc 3 giờ sáng quay lại mà không cần ai thức dậy.

Cả hai thứ đó đều hợp lý khi đứng riêng. Khi ghép lại, chúng không ăn khớp.

Vấn đề 1: watchdog tranh chấp với triển khai

Watchdog chạy mỗi phút và “tự chữa” khi chỉ một lần kiểm tra sức khỏe thất bại. Một lần triển khai cố ý rút các dịch vụ trong tối đa 150 giây — trong thời gian đó một kiểm tra sức khỏe được kỳ vọng sẽ thất bại. Vì vậy watchdog kích hoạt trong mỗi lần triển khai.

Phần lớn thời gian nó thua cuộc đua một cách vô hại. Có một lần nó thắng: nó viết lại file compose (mô tả những container nào nên chạy) giữa lúc triển khai, và để lại một máy chủ không có container gateway nào — trong khi tác vụ triển khai vẫn báo thành công.

Các sửa đổi:

  • Một khóa. Triển khai giờ lấy cùng một khóa file với script bootstrap của máy chủ, nên watchdog và triển khai không bao giờ chạy cùng lúc.
  • Bốn lần cảnh báo, không phải một. Watchdog cần bốn lần kiểm tra liên tiếp thất bại mới hành động. Một dịch vụ đang được rút không còn bị coi là đã chết.
  • Một định nghĩa. File compose giờ chỉ có một nguồn duy nhất, được công bố lên các máy chủ, thay vì các bản sao có thể lệch nhau.
  • Xác minh, đừng tin. Tác vụ triển khai không còn qua chỉ vì một lệnh đã trả về. Nó kiểm tra API, orchestrator, gateway và worker xuất bản trên mọi máy chủ trước khi có thể thành công.

Vấn đề 2: máy chủ rời đi trước khi lưu lượng rời đi

Vấn đề thứ hai âm thầm hơn. Khi một lần triển khai rút một máy chủ, máy chủ bắt đầu trả về 503 trên endpoint sức khỏe để load balancer đưa nó ra khỏi luồng. Máy của chúng tôi làm vậy trong 5 giây, rồi tắt.

Nhưng ALB chỉ kiểm tra sức khỏe thỉnh thoảng, và cần vài lần thất bại liên tiếp trước khi ngừng định tuyến đến một mục tiêu — tới khoảng 60 giây từ đầu đến cuối. Vì vậy trong khoảng 55 giây, load balancer vẫn gửi yêu cầu thật đến một máy chủ đã ngừng lắng nghe. Đó là các lỗi 502 của chúng tôi.

Cách sửa là làm cho hai dòng thời gian khớp nhau:

  • Target group giờ kiểm tra mỗi 5 giây và đánh dấu một mục tiêu không khỏe sau 2 lần thất bại — khoảng 10 giây để phát hiện.
  • Quá trình rút tiếp tục phục vụ lưu lượng thật trong 15 giây sau khi bắt đầu thất bại kiểm tra sức khỏe, nên luôn có phần chồng lấn.
  • Các cài đặt này nằm trong script cấp phát hạ tầng, không nằm trong một bảng điều khiển mà ai đó đã nhấp một lần.

Làm cho các con số giữ nhau

Các khoảng thời gian chờ như vậy phụ thuộc lẫn nhau. Quá trình rút phải dài hơn thời gian load balancer cần để phát hiện; quá trình rút cộng với tắt máy phải hoàn tất trước khi container bị buộc dừng. Rất dễ để ai đó đổi một con số sáu tháng sau và âm thầm đưa lỗi trở lại.

Vì vậy chúng tôi ghi các mối quan hệ đó thành kiểm thử: quá trình rút phải dài hơn khoảng thời gian kiểm tra sức khỏe nhân với ngưỡng thất bại; thời gian để được đánh dấu khỏe trở lại phải giữ ngắn; toàn bộ quá trình rút phải nằm trong thời gian ân hạn dừng của container. Đổi một con số mà không đổi các con số còn lại thì CI thất bại. Chúng tôi cũng kiểm thử đột biến chính các kiểm thử — đổi mỗi con số thành một giá trị sai và kiểm tra xem có kiểm thử nào bắt được không.

Đo lường triển khai dễ sai

Lần đo đầu tiên của chúng tôi cho thấy một lần triển khai sạch bị hỏng khoảng 3%. Điều đó không đúng. Chúng tôi đang đếm mọi phản hồi không phải 200, và một 503 từ endpoint sức khỏe trong lúc rút không phải là lỗi — đó là quá trình rút đang làm đúng việc của nó, báo cho load balancer không chọn máy chủ đó trong khi nó vẫn phục vụ yêu cầu thật.

Những gì người dùng cảm nhận là một 502: yêu cầu không chạm đến được gì. Chỉ đếm những lỗi đó cho ra bức tranh thật — 10, rồi 6, rồi 0 qua ba lần triển khai production.

Chúng tôi rút ra gì

  • Tự phục hồi cần biết về thời gian ngừng hoạt động có kế hoạch. Một watchdog không phân biệt được triển khai với crash sớm muộn cũng sẽ đánh nhau với triển khai.
  • Rút lưu lượng là một cái bắt tay. Máy chủ phải tiếp tục phục vụ cho đến khi load balancer đã chứng minh được là đã ngừng gửi lưu lượng, và thời điểm đó được đặt trên load balancer, không phải trên máy chủ.
  • Mã hóa các bất biến thành kiểm thử. Các con số vận hành bị lệch dần. Các kiểm thử liên hệ chúng với nhau thì không.
  • Quyết định bạn đang đo gì trước khi đo. “Lỗi” là một chỉ số sai; “yêu cầu không chạm đến được gì” mới là chỉ số đúng.

Nếu bạn xuất bản một ứng dụng trên Mythex, không có điều nào trong số này hiện ra với bạn — đó chính là mục đích. Liên quan: cách ứng dụng đã xuất bản của bạn vẫn hoạt động trong khi được xuất bản lại.

Mythex · Pricing · Xây dựng mọi thứ với AI · Mẫu website và ứng dụng · So sánh Mythex · Thuật ngữ xây dựng ứng dụng bằng AI · Công cụ miễn phí để xây dựng ứng dụng bằng AI · English

English አማርኛ العربية Български বাংলা Bosanski Català Čeština Dansk Deutsch Ελληνικά Español Español (España) Eesti فارسی Suomi Français Français (Canada) ગુજરાતી हिन्दी Hrvatski Magyar Հայերեն Bahasa Indonesia Íslenska Italiano 日本語 ქართული Қазақ тілі ಕನ್ನಡ 한국어 Lietuvių Latviešu Македонски മലയാളം Монгол मराठी Bahasa Melayu မြန်မာ Norsk bokmål Nederlands ਪੰਜਾਬੀ Polski Português (Brasil) Português (Portugal) Română Русский Slovenčina Slovenščina Soomaali Shqip Srpski Svenska Kiswahili தமிழ் తెలుగు ไทย Tagalog Türkçe Українська اردو 简体中文 繁體中文(香港) 繁體中文(台灣)