Chọn DB pool_size cho ứng dụng Flask-SQLAlchemy chạy trên Gunicorn


8

Tôi có ứng dụng Flask-SQLAlchmey đang chạy trong Gunicorn được kết nối với cơ sở dữ liệu PostgreQuery và tôi gặp khó khăn khi tìm hiểu pool_sizegiá trị sẽ là bao nhiêu và tôi nên mong đợi bao nhiêu kết nối cơ sở dữ liệu.

Đây là sự hiểu biết của tôi về cách mọi thứ hoạt động:

  • Các quy trình trong Python 3.7 KHÔNG chia sẻ bộ nhớ
  • Mỗi công nhân Gunicorn là quy trình riêng của nó
  • Do đó, mỗi nhân viên Gunicorn sẽ nhận được bản sao của nhóm kết nối cơ sở dữ liệu và nó sẽ không được chia sẻ với bất kỳ nhân viên nào khác
  • Chủ đề trong Python DO chia sẻ bộ nhớ
  • Do đó, mọi luồng trong công nhân Gunicorn S share chia sẻ nhóm kết nối cơ sở dữ liệu

Điều đó có đúng không? Nếu đó là chính xác, thì đối với ứng dụng Flask đồng bộ đang chạy trong Gunicorn:

  • Là số lượng kết nối cơ sở dữ liệu tối đa = (số lượng công nhân) * (số lượng luồng trên mỗi công nhân)?
  • Và trong một công nhân, nó có bao giờ sử dụng nhiều kết nối từ một hồ bơi hơn là có công nhân không?

Có một lý do tại sao pool_sizenên lớn hơn số lượng chủ đề? Vì vậy, đối với một ứng dụng gunicorn ra mắt gunicorn --workers=5 --threads=2 main:appnên pool_sizelà 2? Và nếu tôi chỉ sử dụng công nhân, và không sử dụng chủ đề, có lý do nào để có số pool_sizelớn hơn 1 không?

Câu trả lời:


3

Thêm 2 xu của tôi. Hiểu biết của bạn là chính xác nhưng một số suy nghĩ để xem xét:

  • trong trường hợp ứng dụng của bạn bị ràng buộc IO (ví dụ như nói chuyện với cơ sở dữ liệu), bạn thực sự muốn có nhiều hơn 1 luồng. Nếu không, CPU của bạn sẽ không bao giờ đạt được 100% sử dụng. Bạn cần thử nghiệm với số lượng luồng để có được sự phù hợp, thường là với công cụ kiểm tra tải và so sánh các yêu cầu mỗi giây và việc sử dụng CPU.

  • Ghi nhớ mối quan hệ giữa số lượng công nhân và kết nối, bạn có thể thấy rằng khi thay đổi số lượng công nhân, bạn sẽ cần điều chỉnh kích thước nhóm tối đa. Điều này có thể dễ quên, vì vậy có lẽ một ý tưởng tốt là đặt kích thước nhóm lớn hơn một chút so với số lượng công nhân, ví dụ hai lần số đó.

  • postgresql tạo ra một quy trình trên mỗi kết nối và có thể không mở rộng tốt, khi bạn sẽ có nhiều quy trình gunicorn. Tôi sẽ đi với một số nhóm kết nối nằm giữa ứng dụng của bạn và cơ sở dữ liệu (pgbouncer là phổ biến nhất tôi đoán).


3

Chỉ cần thêm một số kinh nghiệm gần đây của riêng tôi vào câu trả lời của @ matino . Các ứng dụng WSGI cũng có thể được hưởng lợi từ các nhân viên không đồng bộ. Tôi sẽ thêm một số điểm về async workersconnection poolsở đây.

Gần đây chúng tôi đã phải đối mặt với một số vấn đề tương tự về sản xuất của chúng tôi. Lưu lượng truy cập của chúng tôi tăng vọt trong 1-2 ngày và tất cả các yêu cầu đã bị tắc vì một số lý do. Chúng tôi đã sử dụng gunicorn với các geventnhân viên async cho djangoứng dụng của chúng tôi . Hóa ra các kết nối psql là lý do cho nhiều yêu cầu bị đình trệ (và cuối cùng đã hết thời gian).

Các gợi ý số yêu cầu đồng thời là (2*CPU)+1. Vì vậy, trong một kịch bản đồng bộ hóa, các tính toán của bạn sẽ như sau:(workers_num * threads_num) <= (2 * cores_num) + 1

Và bạn sẽ nhận được (workers_num * threads_num)kết nối tối đa đến cơ sở dữ liệu của bạn. (giả sử, tất cả các yêu cầu có truy vấn db). Do đó, bạn sẽ cần đặt cài đặt psql của mình pool_sizethành số lớn hơn số này. Nhưng khi bạn sử dụng công nhân không đồng bộ, các tính toán sẽ có một chút khác biệt. Nhìn vào lệnh gunicorn này:

gunicorn --worker-class=gevent --worker-connections=1000 --workers=3 django:app

Trong trường hợp này, số lượng yêu cầu đồng thời tối đa có thể nhận được tối đa 3000yêu cầu. Vì vậy, bạn cần phải thiết lập của bạn pool_sizeđể một cái gì đó lớn hơn 3000. Nếu ứng dụng của bạn bị ràng buộc IO, bạn sẽ có hiệu suất tốt hơn với các nhân viên không đồng bộ. Bằng cách này, bạn sẽ có thể sử dụng CPU của mình hiệu quả hơn.

Và về tổng hợp kết nối, khi bạn sử dụng một giải pháp như thế PgBouncer, bạn sẽ thoát khỏi tình trạng mở và đóng kết nối mọi lúc. Vì vậy, nó sẽ không ảnh hưởng đến quyết định của bạn về việc thiết lập của bạn pool_size. Các hiệu ứng có thể không đáng chú ý trong giao dịch thấp, nhưng nó sẽ là cần thiết để xử lý lưu lượng truy cập cao hơn.


2

Tôi muốn nói rằng sự hiểu biết của bạn là khá tốt. Các luồng trong một nhân viên WSGI thực sự sẽ chia sẻ một nhóm kết nối; vì vậy về mặt lý thuyết số lượng kết nối cơ sở dữ liệu tối đa là (number of workers) * Nở đâu N = pool_size + max_overflow. (Tôi không chắc chắn Flask-SQLAlchemy đặt max_overflow thành gì, nhưng đây là một phần quan trọng của phương trình ở đây - xem tài liệu QueuePool để biết ý nghĩa của nó.)

Trong thực tế, nếu bạn chỉ sử dụng Phiên có phạm vi luồng được cung cấp cho bạn bởi Flask-SQLAlchemy, bạn sẽ có tối đa một kết nối cho mỗi luồng; Vì vậy, nếu số lượng chủ đề của bạn ít hơn Nthì giới hạn trên của bạn thực sự sẽ được (number of workers) * (number of threads per worker).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.