Cách Chúng Tôi Khắc Phục Lỗi Ghi Nhật Ký Gunicorn Đệ Quy Trong Môi Trường Sản Xuất

By hientd, at: 15:59 Ngày 10 tháng 6 năm 2025

Thời gian đọc ước tính: __READING_TIME__ minutes

How We Fixed a Gunicorn Reentrant Logging Bug in Production
How We Fixed a Gunicorn Reentrant Logging Bug in Production

Tại Glinteco, gần đây chúng tôi đã gặp phải một sự cố sản xuất khó hiểu, trong đó một trong những ứng dụng Flask của khách hàng của chúng tôi bị gián đoạn, mặc dù tất cả các dịch vụ đều đang chạylog không hiển thị lỗi ngay từ cái nhìn đầu tiên. Sau khi tìm hiểu kỹ, chúng tôi đã phát hiện ra một vấn đề nghiêm trọng:

 

RuntimeError: reentrant call inside <_io.BufferedWriter name=''>

 

Trong bài viết này, chúng tôi sẽ hướng dẫn bạn cách:

 

  • Nguyên nhân gây ra lỗi
     

  • Cách chúng tôi gỡ lỗi
     

  • Bản vá lỗi mà chúng tôi đã áp dụng
     

  • Những điểm mấu chốt dành cho bất kỳ nhóm nào sử dụng Gunicorn + logging trong Python

 

 

 

Vấn đề

 

Cấu hình của khách hàng khá phổ biến:

 

  • Ứng dụng Flask chạy phía sau Gunicorn
     

  • Triển khai trên hai máy chủ phía sau một bộ cân bằng tải
     

  • Đã cài đặt giám sát New Relic
     

  • Phiên bản Gunicorn: 20.0.1
     

  • Python phiên bản: 3.6

 

Đột nhiên, người dùng bắt đầu báo cáo việc truy cập liên tục và gián đoạn vào trang web. Nhưng số liệu hệ thống cho thấy sử dụng CPU và bộ nhớ bình thường. Các tiến trình vẫn hoạt động. Điều này không hợp lý, cho đến khi chúng tôi kiểm tra lỗi này trong stderr:

 

RuntimeError: reentrant call inside <_io.BufferedWriter name=''>
Worker with pid 12345 was terminated due to signal 9

 

 

Gỡ lỗi sự cố

 

Lỗi này rất khó theo dõi. Dưới đây là những gì chúng tôi đã tìm hiểu được thông qua quá trình điều tra:

 

  • Lỗi liên quan đến cơ chế ghi nhật ký của Gunicorn, đặc biệt là khi nhiều tiến trình worker cố gắng ghi vào stderr cùng một lúc.
     

  • Đây là một vấn đề đã biết trong các phiên bản cũ của Gunicorn, trong đó ghi nhật ký lặp lại hoặc đệ quy có thể gây ra sự cố.
     

  • Tín hiệu 9 (SIGKILL) có nghĩa là tiến trình worker đã bị hệ thống buộc phải kết thúc — có thể là do bế tắc ghi nhật ký hoặc bộ nhớ bị cạn kiệt.

 

Chúng tôi đã kiểm tra:

 

 

 

Bản vá lỗi: Nâng cấp từng giai đoạn

 

Chúng tôi không chuyển sang phiên bản mới nhất ngay lập tức. Thay vào đó, chúng tôi đã thực hiện một quá trình nâng cấp an toàn:

 

  1. Nâng cấp Gunicorn lên 21.2.0 — vì cộng đồng đã xác nhận phiên bản này đã giải quyết nhiều vấn đề về ghi nhật ký.
     

  2. Giám sát hệ thống trong vài ngày. Lỗi đã biến mất và hệ thống trở nên ổn định trở lại.
     

  3. Sau khi xác nhận sự ổn định, chúng tôi đã chuyển sang Gunicorn 23.0.0, phiên bản ổn định mới nhất.
     

  4. Cũng đã cập nhật Python lên 3.10 để cải thiện hiệu suất và khả năng tương thích.

 

Không có vấn đề nào kể từ đó.

 

 

Bản vá lỗi bổ sung (Tùy chọn nhưng được khuyến nghị)

 

  • Chúng tôi đã thay thế việc ghi nhật ký stderr trực tiếp bằng bộ xử lý ghi nhật ký thích hợp trong Python bằng cách sử dụng logging.StreamHandler(sys.stdout).
     

  • Giảm nhẹ số lượng worker của Gunicorn để hạn chế đồng thời trong giờ cao điểm.
     

  • Thêm cài đặt max_requests trong Gunicorn để tái chế worker sau N yêu cầu.

 

gunicorn app:app --workers=4 --max-requests=1000 --max-requests-jitter=100

 

 

Những điểm mấu chốt

 

  • Gunicorn < 20.1 không còn an toàn cho sản xuất nữa — hãy nâng cấp càng sớm càng tốt.
     

  • Ghi nhật ký có thể lặng lẽ làm hỏng ứng dụng của bạn nếu không được cấu hình đúng cách.
     

  • Luôn giám sát stderr và tín hiệu worker, ngay cả khi nhật ký ứng dụng trông ổn.
     

  • Thực hiện theo một con đường nâng cấp an toàn và đăng ký theo dõi các vấn đề trên GitHub hoặc nhật ký thay đổi của các phụ thuộc quan trọng.

 

Suy nghĩ cuối cùng

 

Vấn đề này nhắc nhở chúng tôi rằng tại sao ngay cả các thư viện trưởng thành như Gunicorn cũng cần được bảo trì và giám sát tích cực. Tại Glinteco, chúng tôi giúp khách hàng không chỉ xây dựng ứng dụng mà còn chạy và mở rộng chúng một cách an toàn.

 

Nếu bạn đang gặp phải hành vi lạ trong ứng dụng Flask/Django của mình, hoặc cần ý kiến thứ hai về đường dẫn triển khai của mình, hãy liên hệ với chúng tôi. Chúng tôi đã từng trải qua điều đó.

 

Tag list:
- reentrant call inside BufferedWriter
- Gunicorn RuntimeError
- Python logging issue
- Gunicorn production best practices
- Gunicorn SIGKILL
- Gunicorn upgrade fix
- Gunicorn logging bug
- Flask app crash

Liên quan

Python Web Application

Đọc thêm
Python Flask

Đọc thêm

Theo dõi

Theo dõi bản tin của chúng tôi và không bao giờ bỏ lỡ những tin tức mới nhất.