2012-11-16 32 views
9

Tôi có một dự án theo dõi thông tin trạng thái trong hơn 500 nghìn đối tượng, chương trình nhận được 10k cập nhật/giây về các đối tượng này, các bản cập nhật bao gồm các hoạt động mới, cập nhật hoặc xóa.DelayQueue với tốc độ cao hơn remove()?

Là một phần của chương trình giữ nhà phải được thực hiện trên các đối tượng này khoảng mỗi năm phút, cho mục đích này tôi đã đặt chúng trong một DelayQueue thực hiện giao diện Delayed, cho phép các chức năng chặn của DelayQueue để kiểm soát giữ nhà những vật thể này.

  • Khi mới, một đối tượng được đặt trên DelayQueue.

  • Khi cập nhật, đối tượng là remove() 'd từ DelayQueue, được cập nhật và sau đó được đặt lại ở vị trí mới được quyết định bởi thông tin được cập nhật.

  • Khi xóa, đối tượng là remove() 'd từ DelayQueue.

Vấn đề tôi đang gặp phải là phương thức remove() sẽ trở thành hoạt động lâu dài khi hàng đợi vượt qua các đối tượng 450k.

Chương trình đa luồng, một chủ đề xử lý các cập nhật và một luồng khác được giữ lại. Do sự chậm trễ remove(), chúng tôi gặp phải các vấn đề về hiệu suất khóa khó chịu và cuối cùng bộ đệm của chủ đề cập nhật sẽ tiêu thụ tất cả không gian lưu trữ.

Tôi đã cố gắng giải quyết vấn đề này bằng cách tạo một DelayedWeakReference (extends WeakReference implements Delayed), cho phép tôi để các đối tượng "bóng" trong hàng đợi cho đến khi chúng hết hạn bình thường.

Điều này sẽ giải quyết vấn đề hiệu suất, nhưng làm tăng đáng kể yêu cầu bộ nhớ. Thực hiện kết quả này trong khoảng 5 DelayedWeakReference cho mọi đối tượng thực sự cần phải nằm trong hàng đợi.

Có ai biết về số DelayQueue có theo dõi bổ sung cho phép hoạt động nhanh chóng remove() không? Hoặc có bất kỳ đề xuất nào về cách xử lý tốt hơn mà không tốn nhiều bộ nhớ hơn?

+0

Chỉ cần tò mò ... nhưng điều này là gì (ngoài vấn đề kỹ thuật)? –

+0

Nó là một công cụ để xử lý nội dung của các bảng trạng thái tường lửa, nó lấy một đầu ra văn bản từ một tường lửa và xây dựng lại bảng trạng thái trong bộ nhớ. Điều này cho phép bạn thực hiện nhiều thao tác và phân tích, và quan trọng hơn là xuất thông tin ở định dạng khác thường xuyên, xuất khẩu sự khác biệt kể từ lần cập nhật cuối cùng, như được sử dụng trong NetFlow. – CuddlyDragon

Trả lời

2


đưa tôi một chút thời gian để suy nghĩ về điều này,
nhưng sau khi đọc câu hỏi thú vị của bạn trong vài phút, sau đây là ý tưởng của tôi:
A. nếu bạn đối tượng có một số loại ID, sử dụng nó để băm, và thực sự không có một hàng đợi chậm trễ, nhưng có hàng đợi chậm trễ N.
Điều này sẽ giảm hệ số khóa theo N.
Sẽ có cấu trúc dữ liệu trung tâm,
giữ các hàng đợi N này.Vì N được định cấu hình sẵn,
bạn có thể tạo tất cả N hàng đợi khi hệ thống khởi động.

+0

Đây là một cách tiếp cận thú vị mà tôi đã không xem xét, sharding 'DelayQueue' của. Nó sẽ được dễ dàng, đủ để phân bổ các đối tượng để những người khác nhau bằng cách sử dụng modulus, như họ làm tất cả đều có một ID duy nhất. Đây có thể là một cách để mở rộng quy mô. – CuddlyDragon

+0

Thật vậy, đây chính là điều tôi muốn nói. Tôi sẽ đánh giá cao nếu bạn có thể kiểm tra điều này, và nếu nó giúp, upvote :) –

+0

Đây là đặt cược tốt nhất của tôi trong ngắn hạn, và có lẽ sẽ mở rộng đủ tốt để đáp ứng nhu cầu của tôi trong ngắn và trung hạn. Tôi có thể cố gắng thiết kế một Hàng đợi chuyên biệt hơn cho các nhu cầu của riêng tôi, cung cấp chức năng cần thiết. -- Cảm ơn! – CuddlyDragon

1

Nếu bạn chỉ cần thực hiện một vệ sinh "khoảng năm phút một lần", đây là việc phải làm để duy trì điều đó.

Những gì tôi sẽ làm là có một nhiệm vụ chạy mỗi phút (hoặc ít hơn theo yêu cầu) để xem nếu nó đã được năm phút kể từ lần cập nhật cuối cùng. Nếu bạn sử dụng phương pháp này, sẽ không có bộ sưu tập bổ sung nào để duy trì và không có cấu trúc dữ liệu nào bị thay đổi trong bản cập nhật. Chi phí của việc quét các thành phần được tăng lên, nhưng là hằng số. Các chi phí cập nhật biểu diễn trở nên tầm thường (thiết lập một trường với thời gian cập nhật lần cuối)

+0

Cảm ơn lời khuyên, tôi đã cân nhắc thực hiện "quét toàn bộ" thường xuyên của một 'HashMap' thay vì sử dụng' DelayQueue'. Tuy nhiên những gì tôi nhanh chóng nhận ra là nó cần phải là một kỷ niệm cho đối tượng cụ thể đó, tức là họ không chia sẻ cùng một hạn chế. Tôi sẽ chạy một số bài kiểm tra về sự khác biệt về hiệu suất quét mỗi năm phút, thay vì sau đó là một phương pháp trì hoãn. – CuddlyDragon

0

Nếu tôi hiểu vấn đề của bạn một cách chính xác, bạn muốn làm điều gì đó với một đối tượng, nếu nó chưa được chạm trong 5 phút.

Bạn có thể có danh sách được liên kết tùy chỉnh; cái đuôi là cái chạm gần đây nhất. Xóa nút nhanh.

Quy trình lưu giữ sách có thể chỉ đơn giản là khởi động sau mỗi 1 giây và xóa các đầu đã được 5 phút. Tuy nhiên, nếu không thể chấp nhận độ trễ 1 giây, hãy tính thời gian tạm dừng chính xác

// book keeping thread 

void run() 

    synchronized(list) 

    while(true) 

     if(head==null) 
      wait(); 
     else if( head.time + 5_min > now) 
      wait(head.time + 5_min - now); 
     else 
      remove head 
      process it 


// update thread 

void add(node) 
    synchronized(list) 
    append node 
    if size==1 
     notify() 

void remove(node) 
    synchronized(list) 
    remove node  
+0

Vấn đề tôi nghi ngờ là tìm kiếm đối tượng cần xóa trong 'DelayQueue', trong đó sử dụng' PriorityQueue', trong đó sử dụng 'Object []' để lưu trữ. Tôi tự hỏi nếu một LL sẽ được tìm kiếm nhanh hơn, hoặc là sự khác biệt mà nó có thể được thực hiện mà không cần khóa toàn bộ cấu trúc? – CuddlyDragon

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