2010-08-08 23 views
6

Tôi làm việc trên lệnh manage.py tạo ra khoảng 200 luồng để kiểm tra máy chủ từ xa. Thiết lập cơ sở dữ liệu của tôi cho phép tôi sử dụng 120 kết nối, vì vậy tôi cần phải sử dụng một số loại tổng hợp. Tôi đã cố gắng sử dụng chủ đề tách ra, như thế nàySử dụng Django ORM trong chủ đề và tránh "quá nhiều khách hàng" ngoại lệ bằng cách sử dụng BoundedSemaphore

class Pool(Thread): 
    def __init__(self): 
     Thread.__init__(self)   
     self.semaphore = threading.BoundedSemaphore(10) 

    def give(self, trackers): 
     self.semaphore.acquire() 
     data = ... some ORM (not lazy, query triggered here) ... 
     self.semaphore.release() 
     return data 

tôi vượt qua thể hiện của đối tượng này để mỗi thread check-nhưng vẫn nhận được "OperationalError: Fatal: xin lỗi, quá nhiều khách hàng đã" bên trong đối tượng Pool sau init-ing 120 chủ đề. Tôi đã dự kiến ​​rằng chỉ có 10 kết nối cơ sở dữ liệu sẽ được mở và các chuỗi sẽ chờ khe semaphore miễn phí. Tôi có thể kiểm tra semaphore hoạt động bằng cách bình luận "phát hành()", trong trường hợp đó chỉ có 10 chủ đề sẽ làm việc và khác sẽ chờ cho đến khi chấm dứt ứng dụng.

Nhiều như tôi hiểu, mỗi chuỗi đang mở kết nối mới với cơ sở dữ liệu ngay cả khi cuộc gọi thực sự nằm trong chuỗi khác nhau, nhưng tại sao? Có cách nào để thực hiện tất cả các truy vấn cơ sở dữ liệu bên trong chỉ có một luồng không?

+0

Để tìm sự cố DB thực tế, tôi đoán chúng tôi cần thêm mã sql. Nhưng, tại sao bạn không chỉ bơi toàn bộ chủ đề để bạn chỉ chạy khoảng 20-30 vào thời điểm đó? – KillianDS

+0

Xin chào, vấn đề của tôi là django tạo kết nối cho mọi chuỗi liên lạc bất kỳ mã ORM nào, ngay cả khi thao tác ORM thực sự xảy ra trong chuỗi khác nhau. (Tôi đã kiểm tra nó bằng cách loại bỏ tất cả các mã từ các chủ đề khác, ngoại trừ các cuộc gọi đến trường hợp của hồ bơi cho). Vì vậy, trong trường hợp của tôi không có SQL ngoại trừ việc nhận dữ liệu trong cung cấp. Miễn là tôi có trình kiểm tra lớp (Chủ đề): def def (tự): self.getter.give (self.trackers) kết nối đang được tạo (trackers là danh sách chuỗi ở đây). Và sau khi đạt đến giới hạn 120 kết nối, cơ sở dữ liệu của tôi bắt đầu đưa ra ngoại lệ. – Riz

+0

btw, tôi đã có thể giải quyết vấn đề này theo cách - bằng cách đóng kết nối theo cách thủ công sau mỗi yêu cầu db, hiệu suất là chấp nhận được, nhưng tôi vẫn tò mò về gốc của vấn đề này. – Riz

Trả lời

13

ORM của Django quản lý các kết nối cơ sở dữ liệu trong các biến chuỗi địa phương. Vì vậy, mỗi luồng khác nhau truy cập vào ORM sẽ tạo ra kết nối riêng của nó. Bạn có thể thấy rằng trong một vài dòng đầu tiên của django/db/backends/__init__.py.

Nếu bạn muốn giới hạn số lượng kết nối cơ sở dữ liệu được thực hiện, bạn phải giới hạn số chuỗi khác nhau thực sự truy cập ORM. Một giải pháp có thể là triển khai một dịch vụ ủy nhiệm các yêu cầu ORM tới một nhóm các luồng ORM chuyên dụng. Để truyền tải các yêu cầu và kết quả của chúng từ và tới các luồng khác, bạn sẽ phải thực hiện một số loại cơ chế truyền thông điệp. Vì đây là một vấn đề điển hình của nhà sản xuất/người tiêu dùng, nên các tài liệu Python về luồng nên đưa ra một số gợi ý làm thế nào để đạt được điều này.

Chỉnh sửa: Tôi vừa googled cho "kết nối django tổng hợp". Có rất nhiều người phàn nàn rằng Django không cung cấp một hồ bơi kết nối thích hợp. Một số người trong số họ đã quản lý để tích hợp một gói gộp riêng biệt. Đối với PostgreSQL, tôi sẽ xem xét phần mềm trung gian pgpool.

+0

Tôi đã có thể giải quyết vấn đề này theo hai cách, bằng cách sử dụng pgpool2 hoặc semaphore với cuộc gọi connection.close() thủ công trong cả hai trường hợp. Hồ bơi của ORM chủ đề là những gì tôi đã cố gắng đầu tiên, nhưng đối với một số lý do Django tạo ra một kết nối mới cho mỗi thread ngay cả khi không có ORM thực tế, ngay sau khi bạn cố gắng truy cập bất kỳ thread khác với ORM - ở đây có kết nối mới. P.S. pgpool trông giống như một giải pháp tốt, nhưng tôi không thể giải quyết vấn đề này chỉ bằng cách sử dụng nó, vì tôi có một ứng dụng dài (không nhiều ứng dụng nhỏ) và pgpool không thể cung cấp kết nối gộp mới vì tất cả đều được ứng dụng của tôi sử dụng – Riz

+0

câu hỏi là: trong đó bối cảnh thread nào bạn gọi Pool.give()? Nếu bạn gọi một phương thức của một đối tượng thừa hưởng từ Thread thì phương thức đó vẫn được thực hiện bởi luồng gọi, không nhất thiết phải bởi luồng được liên kết với đối tượng.Nếu tôi giải thích bình luận trước đó của bạn ở trên một cách chính xác, các chủ đề gọi là chủ đề kiểm tra của bạn. Điều này có nghĩa rằng tất cả 200 chủ đề kiểm tra cố gắng tạo một kết nối DB riêng (vì kết nối được lưu trữ luồng cục bộ). Các semaphores của bạn chỉ giới hạn số lượng truy cập ORM song song, không phải số lượng kết nối được tạo ra. –

+0

Kể từ 1.6 hoặc lâu hơn, chúng tôi có thể có kết nối liên tục ở Django, hãy xem https://docs.djangoproject.com/en/1.8/ref/settings/#conn-max-age – dotz

Các vấn đề liên quan