Trong bài viết cuối cùng của tôi, tôi đã nói về lợi ích của việc triển khai xử lý không đồng bộ bằng Service Broker trong SQL Server so với các phương pháp khác tồn tại để xử lý tách rời các tác vụ dài. Trong bài viết này, chúng ta sẽ đi qua tất cả các thành phần cần được định cấu hình cho cấu hình Service Broker cơ bản trong một cơ sở dữ liệu duy nhất và những lưu ý quan trọng đối với việc quản lý hội thoại giữa các dịch vụ broker. Để bắt đầu, chúng tôi sẽ cần tạo cơ sở dữ liệu và kích hoạt cơ sở dữ liệu để sử dụng Service Broker:
TẠO CƠ SỞ DỮ LIỆU AsyncProcessingDemo; ĐI NẾU (CHỌN is_broker_enabled TỪ sys.databases WHERE name =N'AsyncProcessingDemo ') =0BEGIN THAY THẾ CƠ SỞ DỮ LIỆU AsyncProcessingDemo SET ENABLE_BROKER; ENDGO SỬ DỤNG AsyncProcessingDemo;Định cấu hình các thành phần môi giới
Các đối tượng cơ bản cần được tạo trong cơ sở dữ liệu là các kiểu thông báo cho các thông báo, một hợp đồng xác định cách các thông báo sẽ được gửi giữa các dịch vụ, một hàng đợi và dịch vụ khởi tạo cũng như một hàng đợi và dịch vụ đích. Nhiều ví dụ trực tuyến cho nhà môi giới dịch vụ hiển thị cách đặt tên đối tượng phức tạp cho các loại thông báo, hợp đồng và dịch vụ cho Nhà môi giới dịch vụ. Tuy nhiên, không có yêu cầu đối với tên phải phức tạp và tên đối tượng đơn giản có thể được sử dụng cho bất kỳ đối tượng nào.
Đối với thông báo, chúng tôi sẽ cần tạo một loại thông báo cho yêu cầu, loại thông báo này sẽ được gọi là
AsyncRequest
và một loại thông báo cho kết quả, sẽ được gọi làAsyncResult
. Cả hai sẽ sử dụng XML sẽ được xác thực là được các dịch vụ môi giới định dạng chính xác để gửi và nhận dữ liệu theo yêu cầu của các dịch vụ.- Tạo loại tin nhắnCREATE MESSAGE TYPE [AsyncRequest] VALIDATION =WELL_FORMED_XML; TẠO LOẠI TIN NHẮN [AsyncResult] VALIDATION =WELL_FORMED_XML;Hợp đồng chỉ định rằng
AsyncRequest
sẽ được dịch vụ khởi tạo gửi đến dịch vụ đích và dịch vụ đích sẽ trả vềAsyncResult
nhắn lại cho dịch vụ khởi tạo. Hợp đồng cũng có thể chỉ định nhiều loại thông báo cho trình khởi tạo và đích hoặc rằng một loại thông báo cụ thể có thể được gửi bởi bất kỳ dịch vụ nào, nếu quá trình xử lý cụ thể yêu cầu nó.- Tạo hợp đồng HỢP ĐỒNG HỢP ĐỒNG [AsyncContract] ([AsyncRequest] GỬI BỞI NHÀ ĐẦU TƯ, [AsyncResult] GỬI THEO MỤC TIÊU);Đối với mỗi dịch vụ, một hàng đợi phải được tạo để cung cấp lưu trữ các thông báo mà dịch vụ nhận được. Dịch vụ đích nơi yêu cầu sẽ được gửi đi cần được tạo bằng cách chỉ định
AsyncContract
để cho phép gửi tin nhắn đến dịch vụ. Trong trường hợp này, dịch vụ được đặt tên làProcessingService
và sẽ được tạo trênProcessingQueue
trong cơ sở dữ liệu. Dịch vụ khởi tạo không yêu cầu phải chỉ định hợp đồng, điều này khiến nó chỉ có thể nhận tin nhắn để phản hồi cuộc trò chuyện được bắt đầu từ nó.- Tạo hàng đợi xử lý và dịch vụ - chỉ định hợp đồng để cho phép gửi tới dịch vụ - Tạo hàng đợi yêu cầu và dịch vụ TẠO QUEUE RequestQueue; TẠO DỊCH VỤ [RequestService] TRÊN QUEUE RequestQueue;Gửi tin nhắn để xử lý
Như tôi đã giải thích trong bài viết trước, tôi thích triển khai một thủ tục được lưu trữ trong trình bao bọc để gửi một thông báo mới tới dịch vụ môi giới, để nó có thể được sửa đổi một lần để mở rộng hiệu suất nếu cần. Quy trình này là một trình bao bọc đơn giản xung quanh việc tạo một cuộc hội thoại mới và gửi tin nhắn đến
ProcessingService
.- Tạo quy trình trình bao bọc để gửi thư DECLARE @conversation_handle UNIQUEIDENTIFIER; BẮT ĐẦU GIAO DỊCH; BẮT ĐẦU CHUYỂN ĐỔI DIALOG @conversation_handle TỪ DỊCH VỤ @FromService ĐẾN DỊCH VỤ @ToService TRÊN HỢP ĐỒNG @Contract WITH ENCRYPTION =OFF; GỬI TRÊN CONVERSATION @conversation_handle LOẠI TIN NHẮN @MessageType (@MessageBody); GIAO DỊCH CAM KẾT; ENDGOSử dụng thủ tục được lưu trữ trong trình bao bọc, giờ đây, chúng tôi có thể gửi thông báo thử nghiệm đến
ProcessingService
để xác nhận rằng chúng tôi đã thiết lập các dịch vụ môi giới một cách chính xác.- Gửi yêu cầuEXECUTE dbo.SendBrokerMessage @FromService =N'RequestService ', @ToService =N'ProcessingService', @Contract =N'AsyncContract ', @MessageType =N'AsyncRequest', @MessageBody =Nequest '<>12345 '; - Kiểm tra thông báo trên hàng đợi xử lýSELECT CAST (message_body AS XML) FROM ProcessingQueue; ĐIXử lý tin nhắn
Mặc dù chúng tôi có thể xử lý thủ công các thư từ
ProcessingQueue
, chúng tôi có thể muốn các thư được xử lý tự động khi chúng được gửi đếnProcessingService
. Để thực hiện việc này, một quy trình được lưu trữ kích hoạt cần được tạo mà chúng tôi sẽ kiểm tra và sau đó liên kết với hàng đợi để tự động xử lý khi kích hoạt hàng đợi. Để xử lý một tin nhắn, chúng ta cầnRECEIVE
tin nhắn từ hàng đợi trong một giao dịch, cùng với loại tin nhắn và xử lý hội thoại cho tin nhắn. Loại thông báo đảm bảo rằng logic thích hợp được áp dụng cho thông báo đang được xử lý và trình xử lý hội thoại cho phép phản hồi được gửi trở lại dịch vụ khởi tạo khi thông báo đã được xử lý.
RECEIVE
lệnh cho phép một tin nhắn hoặc nhiều tin nhắn trong cùng một nhóm hoặc bộ xử lý hội thoại được xử lý trong một giao dịch duy nhất. Để xử lý nhiều thông báo, một biến bảng phải được sử dụng hoặc để xử lý một thông báo, có thể sử dụng một biến cục bộ. Quy trình kích hoạt bên dưới lấy một tin nhắn từ hàng đợi, kiểm tra loại tin nhắn để xác định xem nó có phải làAsyncRequest
không tin nhắn, và sau đó thực hiện quá trình chạy dài dựa trên thông tin tin nhắn nhận được. Nếu nó không nhận được thông báo trong vòng lặp, nó sẽ đợi tối đa 5000 mili giây hoặc 5 giây để một thông báo khác vào hàng đợi trước khi thoát khỏi vòng lặp và chấm dứt thực thi. Sau khi xử lý một tin nhắn, nó sẽ xây dựng mộtAsyncResult
và gửi lại cho người khởi tạo trên cùng một tay cầm cuộc trò chuyện mà tin nhắn đã được nhận. Quy trình cũng kiểm tra loại thông báo để xác định xem mộtEndDialog
hoặcError
đã nhận được tin nhắn để xóa cuộc trò chuyện bằng cách kết thúc cuộc trò chuyện.- Tạo quy trình xử lý để xử lý hàng đợiCREATE PROCEDURE dbo.ProcessingQueueActivationASBEGIN SET NOCOUNT ON; DECLARE @conversation_handle UNIQUEIDENTIFIER; DECLARE @message_body XML; DECLARE @message_type_name sysname; WHILE (1 =1) BẮT ĐẦU GIAO DỊCH; WAITFOR (NHẬN HÀNG ĐẦU (1) @conversation_handle =talk_handle, @message_body =CAST (message_body AS XML), @message_type_name =message_type_name FROM ProcessingQueue), TIMEOUT 5000; NẾU (@@ ROWCOUNT =0) BẮT ĐẦU GIAO DỊCH QUAY LẠI; PHÁ VỠ; KẾT THÚC NẾU @message_type_name =N'AsyncRequest 'BEGIN - Xử lý quá trình xử lý dài phức tạp ở đây - Để trình diễn, chúng tôi sẽ lấy số tài khoản và chỉ gửi trả lời DECLARE @AccountNumber INT =@ message_body.value (' (AsyncRequest / AccountNumber) [1] ',' INT '); - Xây dựng thông báo trả lời và gửi lại DECLARE @reply_message_body XML =N '' + CAST (@AccountNumber AS NVARCHAR (11)) + ''; GỬI TRÊN CONVERSATION @conversation_handle LOẠI TIN NHẮN [AsyncResult] (@reply_message_body); KẾT THÚC - Nếu kết thúc thông báo hộp thoại, hãy kết thúc hộp thoại ELSE IF @message_type_name =N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog 'BEGIN END CONVERSATION @conversation_handle; HẾT - Nếu thông báo lỗi, hãy ghi nhật ký và kết thúc cuộc hội thoại ELSE IF @message_type_name =N'http://schemas.microsoft.com/SQL/ServiceBroker/Error 'BEGIN - Ghi mã lỗi và thực hiện bất kỳ xử lý bắt buộc nào tại đây - Kết thúc cuộc hội thoại gặp lỗi END CONVERSATION @conversation_handle; CAM KẾT KẾT THÚC GIAO DỊCH; HẾT HẾT
RequestQueue
cũng sẽ cần xử lý các thông báo được gửi đến nó, do đó, một quy trình bổ sung để xử lýAsyncResult
thông báo do thủ tục ProcessingQueueActivation trả về cần được tạo. Vì chúng tôi biết rằng thông báo AsnycResult có nghĩa là tất cả công việc xử lý đã hoàn thành, cuộc trò chuyện có thể kết thúc sau khi chúng tôi xử lý thông báo đó, thông báo này sẽ gửi một thông báo EndDialog đến ProcessingService, sau đó sẽ được xử lý bằng thủ tục kích hoạt để kết thúc cuộc trò chuyện dọn dẹp mọi thứ và tránh hỏa hoạn và quên các vấn đề xảy ra khi cuộc trò chuyện được kết thúc đúng cách.- Tạo thủ tục để xử lý phản hồi cho hàng đợi yêu cầuCREATE PROCEDURE dbo.RequestQueueActivationASBEGIN SET NOCOUNT ON; DECLARE @conversation_handle UNIQUEIDENTIFIER; DECLARE @message_body XML; DECLARE @message_type_name sysname; WHILE (1 =1) BẮT ĐẦU GIAO DỊCH; WAITFOR (NHẬN HÀNG ĐẦU (1) @conversation_handle =talk_handle, @message_body =CAST (message_body AS XML), @message_type_name =message_type_name FROM RequestQueue), TIMEOUT 5000; NẾU (@@ ROWCOUNT =0) BẮT ĐẦU GIAO DỊCH QUAY LẠI; PHÁ VỠ; KẾT THÚC NẾU @message_type_name =N'AsyncResult 'BEGIN - Nếu cần, hãy xử lý thông báo trả lời tại đây DECLARE @AccountNumber INT =@ message_body.value (' (AsyncResult / AccountNumber) [1] ',' INT '); - Vì đây là tất cả công việc đang được thực hiện, hãy kết thúc cuộc trò chuyện để gửi thông báo EndDialog END CONVERSATION @conversation_handle; KẾT THÚC - Nếu kết thúc thông báo hộp thoại, hãy kết thúc hộp thoại ELSE IF @message_type_name =N'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog 'BEGIN END CONVERSATION @conversation_handle; KẾT THÚC - Nếu thông báo lỗi, hãy ghi nhật ký và kết thúc cuộc hội thoại ELSE IF @message_type_name =N'http://schemas.microsoft.com/SQL/ServiceBroker/Error 'BEGIN END CONVERSATION @conversation_handle; CAM KẾT KẾT THÚC GIAO DỊCH; HẾT HẾTKiểm tra các thủ tục
Trước khi tự động hóa việc xử lý hàng đợi cho các dịch vụ của chúng tôi, điều quan trọng là phải kiểm tra các thủ tục kích hoạt để đảm bảo rằng chúng xử lý các thông báo một cách thích hợp và để ngăn hàng đợi bị vô hiệu hóa nếu xảy ra lỗi không được xử lý đúng cách. Vì đã có thông báo trên
ProcessingQueue
ProcessingQueueActivation
thủ tục có thể được thực hiện để xử lý thông báo đó. Hãy nhớ rằngWAITFOR
sẽ khiến thủ tục mất 5 giây để kết thúc, mặc dù thông báo được xử lý ngay lập tức từ hàng đợi. Sau khi xử lý thông báo, chúng tôi có thể xác minh quy trình hoạt động chính xác bằng cách truy vấnRequestQueue
để xem liệu mộtAsyncResult
thông báo tồn tại và sau đó chúng tôi có thể xác minh rằngRequestQueueActivation
thủ tục hoạt động chính xác bằng cách thực thi nó.- Xử lý tin nhắn từ hàng đợi xử lýEXECUTE dbo.ProcessingQueueActivation; GO - Kiểm tra tin nhắn trả lời trên hàng đợi yêu cầuSELECT CAST (message_body AS XML) FROM RequestQueue; GO - Xử lý tin nhắn từ hàng đợi yêu cầuEXECUTE dbo.RequestQueueActivation; GOTự động hóa quá trình
Tại thời điểm này, tất cả các thành phần đã hoàn tất để tự động hóa hoàn toàn quá trình xử lý của chúng tôi. Điều duy nhất còn lại là ràng buộc các thủ tục kích hoạt với hàng đợi thích hợp của chúng, sau đó gửi một thông báo thử nghiệm khác để xác nhận rằng nó được xử lý và không có gì còn lại trong hàng đợi sau đó.
- Thay đổi hàng đợi xử lý để chỉ định kích hoạt bên trong CÓ KÍCH HOẠT (STATUS =ON, PROCEDURE_NAME =dbo.RequestQueueActivation, MAX_QUEUE_READERS =10, EXECUTE AS SELF); ĐI - Kiểm tra kích hoạt tự động - Gửi yêu cầu THỰC HIỆN dbo.SendBrokerMessage @FromService =N'RequestService ', @ToService', @ToService ProcessingService ', @Contract =N'AsyncContract', @MessageType =N'AsyncRequest ', @MessageBody =N''; - Kiểm tra tin nhắn trên hàng đợi xử lý - không có gì ở đó vì nó đã được xử lý tự động AS XML) TỪ RequestQueue; ĐI 12345 Tóm tắt
Các thành phần cơ bản để xử lý không đồng bộ tự động trong SQL Server Service Broker có thể được định cấu hình trong một thiết lập cơ sở dữ liệu duy nhất để cho phép xử lý tách rời các tác vụ đang chạy dài. Đây có thể là một công cụ mạnh mẽ để cải thiện hiệu suất ứng dụng, từ trải nghiệm của người dùng cuối, bằng cách tách quá trình xử lý khỏi các tương tác của người dùng cuối với ứng dụng.