Cách tốt nhất để thực hiện hàng đợi dựa trên bảng đồng thời


10

Tôi có một bảng trong MySQL đại diện cho một hàng các liên kết sẽ được xử lý. Các liên kết được xử lý bởi một ứng dụng bên ngoài, từng cái một và bị xóa cuối cùng. Đây là một hàng đợi khối lượng lớn và tôi có nhiều phiên bản của ứng dụng xử lý, trải rộng trên một số máy chủ.

Làm cách nào tôi có thể đảm bảo rằng mỗi bản ghi chỉ được chọn bởi một ứng dụng? Có cách nào để gắn cờ / khóa hồ sơ không?

Ngay bây giờ, để tránh hai hoặc nhiều hơn chọn cùng một liên kết, tôi chỉ cho phép mỗi trường hợp nhận một bộ hồ sơ nhất định (dựa trên MOD của ID của họ), nhưng đây không phải là cách minh bạch để tăng xử lý hàng đợi tốc độ chỉ bằng cách thêm các trường hợp mới.


Câu thần chú của tôi: "Đừng xếp hàng, cứ làm đi". Đó là, thay vì ném một nhiệm vụ vào hàng đợi, hãy khởi chạy một quy trình để thực hiện nhiệm vụ.
Rick James

Câu trả lời:


7

Thứ nhất: MySQL là một trong những phần mềm tồi tệ nhất có thể để thực hiện điều này, đặc biệt nếu nó rất năng động. Lý do là các công cụ như MEMORY và MyISAM chỉ có khóa toàn bảng trong khi các công cụ phù hợp hơn như InnoDB có mức phạt ghi cao hơn (để cung cấp các thuộc tính ACID) và được tối ưu hóa để truy cập các bản ghi gần đúng về mặt không gian và thời gian (được đặt trên bộ nhớ ). Cũng không có một hệ thống thông báo thay đổi tốt cho MySQL - nó phải được thực hiện như một cuộc bỏ phiếu. Có hàng tá phần mềm được tối ưu hóa hơn cho nhiệm vụ đó .

Phải nói rằng, tôi đã thấy thực hiện thành công loại truy cập này nếu các yêu cầu về hiệu suất / hiệu quả không cao lắm. Nhiều người không thể đủ khả năng để giới thiệu và duy trì một phần công nghệ hoàn toàn riêng biệt chỉ cho một phần nhỏ của logic kinh doanh.

SELECT FOR UPDATElà những gì bạn đang tìm kiếm - đọc serialization. Mặc dù CẬP NHẬT / XÓA sẽ luôn khóa hàng trong khi giao dịch MYSQL đang chạy, bạn có thể muốn tránh một giao dịch lớn trong khi quá trình đang diễn ra, vì vậy:

START TRANSACTION;
SELECT * FROM your_table WHERE state != 'PROCESSING' 
  ORDER BY date_added ASC LIMIT 1 FOR UPDATE;
if (rows_selected = 0) { //finished processing the queue, abort}
else {
UPDATE your_table WHERE id = $row.id SET state = 'PROCESSING'
COMMIT;

// row is processed here, outside of the transaction, and it can take as much time as we want

// once we finish:
DELETE FROM your_table WHERE id = $row.id and state = 'PROCESSING' LIMIT 1;
}

MySQL sẽ đảm nhiệm việc khóa tất cả các lựa chọn đồng thời trừ một khi chọn hàng. Vì điều này có thể dẫn đến nhiều kết nối bị khóa cùng một lúc, giữ cho giao dịch ban đầu càng nhỏ càng tốt và cố gắng xử lý nhiều hơn 1 hàng đó cùng một lúc.


Cảm ơn. Bạn có nghĩ rằng hiệu suất có thể được hưởng lợi từ một khóa lớn hơn (bằng cách thay đổi GIỚI HẠN thành 10)?
Miguel E

@MiguelE Nói chung, vâng, bạn càng dành nhiều thời gian để xử lý và bạn càng ít có khả năng va chạm với các giao dịch khác thì càng tốt. Nhưng nó có thể phụ thuộc trong một số trường hợp - nó cũng có thể gây ra hiệu ứng ngược lại (nhiều giao dịch bị khóa hơn). Luôn luôn kiểm tra nó đầu tiên. Nó cũng quan trọng để lập chỉ mục đầy đủ cho bảng, hoặc bạn có thể kết thúc với một khóa bảng đầy đủ trong một số chế độ cách ly.
jynus

1
Và có lẽ sẽ là một ý tưởng tốt để theo dõi ngày bạn bắt đầu xử lý hàng chỉ trong trường hợp quy trình bị treo và bạn muốn thực hiện cơ chế hết thời gian chờ.
Julian

2

Như tôi đã giải thích trong bài viết này , MySQL 8 đã giới thiệu hỗ trợ cho cả SKIP LOCKED và NO WAIT.

SKIP LOCKED rất hữu ích để triển khai hàng đợi công việc (còn gọi là hàng đợi theo đợt) để bạn có thể bỏ qua các khóa đã bị khóa bởi các giao dịch đồng thời khác.

KHÔNG WAIT là hữu ích để tránh chờ đợi cho đến khi một giao dịch đồng thời giải phóng các khóa mà chúng tôi cũng quan tâm đến việc khóa. Nếu không có WAIT, chúng tôi sẽ phải đợi cho đến khi các khóa được phát hành (tại thời điểm cam kết hoặc thời gian phát hành bởi giao dịch hiện đang giữ khóa) hoặc hết thời gian mua lại khóa. Do đó, NO WAIT hoạt động giống như thời gian chờ khóa với giá trị là 0.

Để biết thêm chi tiết về SKIP LOCK và KHÔNG WAIT, hãy xem bài viết này .


0

Tôi đã thực hiện một số thứ tương tự với kiểm tra DBCC ngoại tuyến (hai máy chủ thực hiện khôi phục sao lưu và sau đó là kiểm tra DBCC). Một máy chủ tập hợp tất cả các bản sao lưu của 31 máy chủ vào ngày hôm qua và đặt chúng vào một hàng đợi và sau đó máy chủ đó và một lần kéo khác từ hàng đợi đó. Mặc dù không có nhiều máy chủ, phương thức vẫn giữ nguyên: Máy chủ ứng dụng chạy truy vấn cập nhật đối với hàng đợi cập nhật trường ngày / giờ và trường "máy chủ ứng dụng" với tên máy chủ ứng dụng đó hoặc ID số tốt hơn. Điều này sẽ gây ra khóa hoặc nếu đã có khóa từ một máy chủ khác có được hàng tiếp theo, nó sẽ bị chặn và đợi ứng dụng khác hoàn tất việc nhận hàng tiếp theo. Sau đó, bạn sẽ muốn ứng dụng lấy lại bản ghi gần đây nhất từ ​​hàng đợi cho trường ứng dụng và nhận bất kỳ thông tin nào bạn muốn từ nó. Sử dụng MySQL '

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.