Cách Chúng Tôi Khắc Phục Lỗi Gunicorn Worker trong Ứng Dụng Flask: Hành Trình Khắc Phục Sự Cố Thực Tế

By hientd, at: 22:20 Ngày 03 tháng 11 năm 2024

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

How We Fixed Gunicorn Worker Errors in Our Flask App: A Real Troubleshooting Journey
How We Fixed Gunicorn Worker Errors in Our Flask App: A Real Troubleshooting Journey

Cách Chúng Tôi Khắc Phục Lỗi Worker Gunicorn trong Ứng Dụng Flask của Chúng Tôi: Một Hành Trình Khắc Phục Sự Cố Thực Sự

 

Khi bạn quản lý các máy chủ sản xuất, luôn có lúc mọi thứ không diễn ra như ý muốn ngay cả khi bạn nghĩ rằng mọi thứ đang hoạt động trơn tru. Gần đây, chúng tôi đã gặp phải chính xác điều đó - một vấn đề thực sự trong ứng dụng Python/Flask của chúng tôi chạy trên Gunicorn. Khách hàng của chúng tôi báo cáo sự cố gián đoạn định kỳ với ứng dụng, và chúng tôi nhanh chóng nhận ra đã đến lúc cần tìm hiểu kỹ vấn đề này. Đây là câu chuyện về cách chúng tôi giải quyết nó, những gì chúng tôi đã học được và các bước đơn giản mà chúng tôi sẽ thực hiện trong tương lai để tránh gặp phải vấn đề tương tự.

 

Cấu Hình Ban Đầu

Cấu hình của chúng tôi có một bộ cân bằng tải với hai máy chủ xử lý các yêu cầu của khách hàng. Trong điều kiện bình thường, bộ cân bằng tải giữ cho lưu lượng truy cập hoạt động trơn tru, nhưng khách hàng của chúng tôi bắt đầu gặp phải sự cố khả dụng bật/tắt này.

[2024-11-03 13:25:42 +0000] [26747] [INFO] Booting worker with pid: 26747
--- Logging error ---
Traceback (most recent call last):
  File "/usr/lib/python3.6/logging/__init__.py", line 998, in emit
    self.flush()
  File "/usr/lib/python3.6/logging/__init__.py", line 978, in flush
    self.stream.flush()
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stderr>'>
Call stack:
  File "/home/ubuntu/sample-app/venv/bin/gunicorn", line 8, in <module>
    sys.exit(run())
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 67, in run
    WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/app/base.py", line 231, in run
    super().run()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/app/base.py", line 72, in run
    Arbiter(self).run()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 211, in run
    self.manage_workers()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 551, in manage_workers
    self.spawn_workers()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 623, in spawn_workers
    time.sleep(0.1 * random.random())
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 242, in handle_chld
    self.reap_workers()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 533, in reap_workers
    os.WTERMSIG(status)
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/glogging.py", line 261, in warning
    self.error_log.warning(msg, *args, **kwargs)
  File "/usr/lib/python3.6/logging/__init__.py", line 1320, in warning
    self._log(WARNING, msg, args, **kwargs)
  File "/usr/lib/python3.6/logging/__init__.py", line 1444, in _log
    self.handle(record)
  File "/usr/lib/python3.6/logging/__init__.py", line 1454, in handle
    self.callHandlers(record)
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/newrelic/hooks/logger_logging.py", line 87, in wrap_callHandlers
    return wrapped(*args, **kwargs)
  File "/usr/lib/python3.6/logging/__init__.py", line 1516, in callHandlers
    hdlr.handle(record)
  File "/usr/lib/python3.6/logging/__init__.py", line 865, in handle
    self.emit(record)
  File "/usr/lib/python3.6/logging/__init__.py", line 998, in emit
    self.flush()
  File "/usr/lib/python3.6/logging/__init__.py", line 978, in flush
    self.stream.flush()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 242, in handle_chld
    self.reap_workers()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 533, in reap_workers
    os.WTERMSIG(status)
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/glogging.py", line 261, in warning
    self.error_log.warning(msg, *args, **kwargs)
  File "/usr/lib/python3.6/logging/__init__.py", line 1320, in warning
    self._log(WARNING, msg, args, **kwargs)
  File "/usr/lib/python3.6/logging/__init__.py", line 1444, in _log
    self.handle(record)
  File "/usr/lib/python3.6/logging/__init__.py", line 1454, in handle
    self.callHandlers(record)
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/newrelic/hooks/logger_logging.py", line 87, in wrap_callHandlers
    return wrapped(*args, **kwargs)
Message: 'Worker with pid %s was terminated due to signal %s'
Arguments: (26469, 9)
[2024-11-03 13:25:42 +0000] [26748] [INFO] Booting worker with pid: 26748
--- Logging error ---
Traceback (most recent call last):
  File "/usr/lib/python3.6/logging/__init__.py", line 998, in emit
    self.flush()
  File "/usr/lib/python3.6/logging/__init__.py", line 978, in flush
    self.stream.flush()
RuntimeError: reentrant call inside <_io.BufferedWriter name='<stderr>'>
Call stack:
  File "/home/ubuntu/sample-app/venv/bin/gunicorn", line 8, in <module>
    sys.exit(run())
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 67, in run
    WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/app/base.py", line 231, in run
    super().run()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/app/base.py", line 72, in run
    Arbiter(self).run()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 211, in run
    self.manage_workers()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 551, in manage_workers
    self.spawn_workers()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 623, in spawn_workers
    time.sleep(0.1 * random.random())
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 242, in handle_chld
    self.reap_workers()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 533, in reap_workers
    os.WTERMSIG(status)
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/glogging.py", line 261, in warning
    self.error_log.warning(msg, *args, **kwargs)
  File "/usr/lib/python3.6/logging/__init__.py", line 1320, in warning
    self._log(WARNING, msg, args, **kwargs)
  File "/usr/lib/python3.6/logging/__init__.py", line 1444, in _log
    self.handle(record)
  File "/usr/lib/python3.6/logging/__init__.py", line 1454, in handle
    self.callHandlers(record)
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/newrelic/hooks/logger_logging.py", line 87, in wrap_callHandlers
    return wrapped(*args, **kwargs)
  File "/usr/lib/python3.6/logging/__init__.py", line 1516, in callHandlers
    hdlr.handle(record)
  File "/usr/lib/python3.6/logging/__init__.py", line 865, in handle
    self.emit(record)
  File "/usr/lib/python3.6/logging/__init__.py", line 998, in emit
    self.flush()
  File "/usr/lib/python3.6/logging/__init__.py", line 978, in flush
    self.stream.flush()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 242, in handle_chld
    self.reap_workers()
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/arbiter.py", line 533, in reap_workers
    os.WTERMSIG(status)
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/gunicorn/glogging.py", line 261, in warning
    self.error_log.warning(msg, *args, **kwargs)
  File "/usr/lib/python3.6/logging/__init__.py", line 1320, in warning
    self._log(WARNING, msg, args, **kwargs)
  File "/usr/lib/python3.6/logging/__init__.py", line 1444, in _log
    self.handle(record)
  File "/usr/lib/python3.6/logging/__init__.py", line 1454, in handle
    self.callHandlers(record)
  File "/home/ubuntu/sample-app/venv/lib/python3.6/site-packages/newrelic/hooks/logger_logging.py", line 87, in wrap_callHandlers
    return wrapped(*args, **kwargs)
Message: 'Worker with pid %s was terminated due to signal %s'
Arguments: (26469, 9)</module></stderr></module></stderr>


Dưới đây là cách chúng tôi bắt đầu khắc phục sự cố:

  1. Xác minh các tiến trình: Đầu tiên, chúng tôi kiểm tra tất cả các tiến trình máy chủ để xác nhận rằng chúng đang chạy. Mọi thứ dường như ổn ở cấp độ này - không có sự cố hoặc tiến trình treo rõ ràng nào.
     

  2. Kiểm tra nhật ký: Vì tất cả các tiến trình dường như đang chạy trơn tru, chúng tôi chuyển sang các nhật ký được quản lý bởi Supervisord. Đó là nơi chúng tôi thấy một mô hình lặp lại: ứng dụng bị chấm dứt một cách ngẫu nhiên. Và trong nhật ký lỗi của chúng tôi, chúng tôi đã tìm thấy các mục cụ thể này:

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


    Cùng với đó, chúng tôi liên tục thấy:

    Worker with pid %s was terminated due to signal %s


    Với sự kết hợp của các lỗi "reentrant" và việc chấm dứt worker này, có vẻ như chúng tôi gặp phải sự kết hợp của các vấn đề về bộ nhớ, xung đột Gunicorn và lỗi ghi nhật ký. Nhưng chúng tôi cần thêm thông tin.

 

Tìm hiểu sâu hơn: Nghiên cứu lỗi

Với những manh mối này, chúng tôi bắt đầu tìm kiếm trực tuyến, tìm kiếm các thuật ngữ như "reentrant call inside <_io.BufferedWriter>" "Gunicorn RuntimeError.” May mắn thay, chúng tôi đã tìm thấy các cuộc thảo luận trên GitHub từ những người khác đã gặp phải vấn đề tương tự. Dưới đây là một vài cuộc thảo luận chính mà chúng tôi đã tham khảo:

Đọc qua những điều này, một vấn đề trở nên rõ ràng: chúng tôi đang chạy một phiên bản Gunicorn lỗi thời - 20.0.1. Phiên bản phát hành mới nhất là 23.0.0, và nó bao gồm các bản sửa lỗi cho việc ghi nhật ký và quản lý tiến trình giải quyết trực tiếp các vấn đề này. Vì vậy, chúng tôi quyết định thử nâng cấp.

Vấn đề bộ nhớ Gunicorn

 

Kiểm tra giải pháp

  1. Nâng cấp đầu tiên: Thay vì nhảy ngay vào phiên bản mới nhất, chúng tôi đã nâng cấp lên 21.2.0. Chúng tôi muốn thận trọng, vì vậy chúng tôi đã theo dõi ứng dụng một cách chặt chẽ. Sau vài giờ, chúng tôi thấy sự ổn định - không còn sự chấm dứt ngẫu nhiên nữa, và mọi thứ đều hoạt động như mong đợi.
     

  2. Sử dụng phiên bản mới nhất: Khi chúng tôi cảm thấy tự tin, chúng tôi đã nâng cấp lên 23.0.0, phiên bản Gunicorn mới nhất (yêu cầu nâng cấp phiên bản Python mới hơn - khó hơn nhưng đáng giá). Và kể từ đó, ứng dụng đã ổn định mà không có một lỗi reentrant nào. Khả năng truy cập ứng dụng của khách hàng của chúng tôi đã trở lại bình thường, và rõ ràng là việc nâng cấp đã giải quyết được vấn đề.

 

Những gì chúng tôi đã học được

Trải nghiệm này đã làm nổi bật một vài bài học:

  1. Nhật ký là manh mối đầu tiên của bạn: Luôn bắt đầu bằng cách xác nhận các tiến trình đang chạy và kiểm tra kỹ lưỡng các nhật ký. Nhật ký thường chứa các gợi ý quan trọng.
     

  2. Tìm kiếm các vấn đề tương tự: Khi bạn thấy một lỗi lạ, những người khác có thể đã gặp phải nó. Tìm kiếm trên GitHub với các thuật ngữ cụ thể có thể chỉ cho bạn các cuộc thảo luận hữu ích và đôi khi thậm chí là các giải pháp chính xác.
     

  3. Thực hiện nâng cấp chậm rãi: Thay vì nhảy vào phiên bản mới nhất, nên nâng cấp và kiểm tra từng bước. Chúng tôi đã thấy sự cải thiện ngay lập tức với 21.2.0, và cách tiếp cận dần dần đó cho phép chúng tôi đảm bảo sự ổn định trước khi chuyển sang 23.0.0.
     

  4. Luôn cập nhật các bản phát hành: Đăng ký các kho lưu trữ GitHub cho các thư viện mà bạn phụ thuộc vào - như Gunicorn - giúp bạn cập nhật các bản cập nhật quan trọng. Đây là một cách đơn giản để tránh những vấn đề đột ngột này.

 

Kết luận

Khắc phục sự cố sản xuất có thể gây căng thẳng, nhưng việc áp dụng phương pháp từng bước thực sự đã được đền đáp ở đây. Trải nghiệm này đã nhắc nhở chúng tôi về tầm quan trọng của việc giám sát các phụ thuộc và giữ cho chúng được cập nhật. Hy vọng câu chuyện của chúng tôi mang lại cho bạn một vài hiểu biết để giải quyết những thách thức tương tự - hoặc tránh chúng hoàn toàn.

Tag list:
- Python Flask Gunicorn server issues
- gunicorn server down constantly
- RuntimeError: reentrant call inside <_io.BufferedWriter name=''>
- Flask Gunicorn issues
- Gunicorn reentrant logging terminate
- RuntimeError: reentrant call inside
- gunicorn flask issues
- Gunicorn RuntimeError: reentrant

Liên quan

Python AI

Đọc thêm
Experience CRM

Đọ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.