SQL 用于会话卡在会话状态的分布式应用程序的服务器服务代理

SQL Server Service Broker For Distributed App With Conversations Stucking in State of Conversing

我已经对 SSB 有了一点经验,但我只是在同一台服务器上的数据库中进行了此操作。我从来没有这样做过,在不同的机器上使用两个不同的服务器。因此,经过一些研究,我找到了一些 youtube 教程,以及 nice tutorial 正是我想要的,安全性。

但是我无法将消息从服​​务器 A 传递到服务器 B。问题是;如何找到我丢失的东西?

我知道你们都有工作,不是来审查任何代码的。但是我坚持了几天,我只是想要一些帮助,或者一些敏锐的眼睛指出我看不到的东西。

我正在阅读这本名为 "Pro SQL Server 2008 Service Broke" 的书,试图找到我的答案。

我在 youtube 上收集了一个 few videos

我尝试了 this 故障排除,但无法使用 ssbdiagnose。我不知道在哪里可以找到它。


现在,我要澄清 post 我的环境以及我到目前为止所做的事情。

发起者是 SQL Server 2016 Express

目标是 SQL Server 2016 Express

192.168.20.44 启动器服务器的脚本

--###
--All actions related to Basic Service Broker Objects and Dialog Security 
--will be performed in MarketPlace database of 192.168.20.44
--###
--1 Create the Basic Service Broker Objects
--###
USE MarketPlace
GO

ALTER DATABASE MarketPlace
SET Enable_broker;
GO

--1.1 Create Message Types
CREATE Message Type SenderMessageType validation = NONE;
GO

CREATE Message Type ReceiverMessageType validation = NONE;
GO

--1.2 Create Contract on the above message types
CREATE Contract PointOfSaleContract (
    SenderMessageType SENT BY INITIATOR
    ,ReceiverMessageType SENT BY TARGET
    );
GO

--1.3 Create an Initiator queue
CREATE QUEUE InitiatorQueue
    WITH STATUS = ON;
GO

--1.4  Create a Service on the queue and the contract
CREATE Service MarketPlaceService ON QUEUE InitiatorQueue (PointOfSaleContract);
GO

--###
--2 Set up Dialog Security
--###
--2.1 Create a master key in the local database i.e. the database we are going to use for our application.
CREATE Master KEY ENCRYPTION BY Password = 'gs53&"f"!385'
GO

--2.2 Create a user certificate
CREATE Certificate CertificateUserMarketPlace
    WITH Subject = 'CertificateUserMarketPlace'
        ,START_DATE = '2018-01-01'
        ,EXPIRY_DATE = '2020-12-31' ACTIVE
FOR BEGIN_DIALOG = ON;
GO

--2.3 Take a backup of the CertificateUserMarketPlace created and install it into the remote instance
--Copy the certificate to Stage Server Machine
--I Did install the certificates for current user within "automatically select the certificate store" option. Have to?
BACKUP CERTIFICATE CertificateUserMarketPlace TO FILE = 'C:\SSB\CertificateUserMarketPlace.cer';
GO

--2.4 Create a user with the same name as the user who has access rights on the other Database
--I Didn't understand this part. Should I create the very same user on Stage database?
CREATE User UserStage WITHOUT LOGIN
GO

--2.5 Create a user certificate from the user certificate backup file copied from the other server, 
--with authorization to the user created in Step 4
CREATE CERTIFICATE CertificateUserStage AUTHORIZATION UserStage
FROM FILE = 'C:\SSB\CertificateUserStage.cer';
GO

--2.6 Grant connect permissions to the user
GRANT CONNECT
    TO UserStage;
GO

--2.7 Grant send permissions to the user on the local service
GRANT SEND
    ON SERVICE::MarketPlaceService
    TO UserStage;
GO

--2.8 Create a Remote Service Binding with the user created.
CREATE REMOTE SERVICE BINDING ServiceBindingStage TO SERVICE 'StageService'
    WITH USER = UserStage
GO

--###
--3 Set up Transport Security
--All actions related to Transport Security
--will be performed in Master database of 192.168.20.44
--###
USE master
GO

--3.1 Create a master key for master database.
CREATE Master KEY ENCRYPTION BY Password = 'gs53&"f"!385'
GO

--3.2 Create certificate 
CREATE CERTIFICATE EndPointCertificateMarketPlace
    WITH Subject = 'EndPointCertificateMarketPlace'
        ,START_DATE = '2018-01-01'
        ,EXPIRY_DATE = '2020-12-31' ACTIVE
FOR BEGIN_DIALOG = ON;
GO

--3.3 Create End Point that support certificate based authentication
CREATE ENDPOINT ServiceBrokerEndPoint STATE = STARTED AS TCP (LISTENER_PORT = 4022)
FOR SERVICE_BROKER(AUTHENTICATION = CERTIFICATE EndPointCertificateMarketPlace, ENCRYPTION = SUPPORTED);
GO

--3.4 Take a backup of the certificate created and install it into the remote instance
--Copy the certificate to Stage
BACKUP CERTIFICATE EndPointCertificateMarketPlace TO FILE = 'C:\SSB\EndPointCertificateMarketPlace.cer';
GO

--3.5 Create certificate from the certificate backup file copied from the Target server
CREATE CERTIFICATE EndPointCertificateStage
FROM FILE = 'C:\SSB\EndPointCertificateStage.cer';
GO

--3.6 Create login from the certificate created in Step 3.5
CREATE LOGIN SSBLogin
FROM CERTIFICATE EndPointCertificateStage;
GO

--3.7 Grant the login, connect permissions on the end point.
GRANT CONNECT
    ON ENDPOINT::ServiceBrokerEndPoint
    TO SSBLogin
GO

SELECT *
FROM sys.service_broker_endpoints
GO

--###
--4 Create a Route
--###
USE MarketPlace
GO

--4.1 Get the UID from Stage database on 192.168.20.30 to use on the Route
SELECT service_broker_guid
FROM sys.databases
WHERE NAME = 'Stage';

--4.2 Use the UID from 4.1
CREATE Route RouteToStageService
    WITH SERVICE_NAME = 'StageService'
        ,BROKER_INSTANCE = 'A88B9743-EAFF-42FA-9404-0D551D4B29DB' -- Guid From Stage
        ,ADDRESS = 'TCP://192.168.20.30:4022'
GO

192.168.20.30 目标服务器的脚本

--###
--All actions related to Basic Service Broker Objects and Dialog Security 
--will be performed in Stage database of 192.168.20.30
--###
--1 Create the basic Service Broker Objects
--###
USE Stage
GO

ALTER DATABASE Stage
SET Enable_broker;
GO

--1.1 Create Message Types
CREATE Message Type SenderMessageType validation = NONE;
GO

CREATE Message Type ReceiverMessageType validation = NONE;
GO

--1.2 Create Contract on the above message types
CREATE Contract PointOfSaleContract (
    SenderMessageType SENT BY INITIATOR
    ,ReceiverMessageType SENT BY TARGET
    );
GO

--1.3 Create an Target queue
CREATE QUEUE TargetQueue
    WITH STATUS = ON;
GO

--1.4  Create a Service on the queue and the contract
CREATE Service StageService ON QUEUE TargetQueue (PointOfSaleContract);
GO

--###
--2 Set up Dialog Security
--###
--2.1 Create a master key in the local database i.e. the database we are going to use for our application.
CREATE Master KEY ENCRYPTION BY Password = '45Gme*3^&fwu'
GO

--2.2 Create a user certificate
CREATE Certificate CertificateUserStage
    WITH SUBJECT = 'CertificateUserStage'
        ,START_DATE = '2018-01-01'
        ,EXPIRY_DATE = '2020-12-31' ACTIVE
FOR BEGIN_DIALOG = ON;
GO
--2.3 Take a backup of the user certificate created and install it into the remote instance
--Copy the certificate to MarketPlace Server Machine
BACKUP CERTIFICATE CertificateUserStage TO FILE = 'C:\SSB\CertificateUserStage.cer';
GO

--2.4 Create a user with the same name as the user who has access rights on the other Database
CREATE User UserMarketPlace WITHOUT LOGIN
GO

--2.5 Create a user certificate from the user certificate backup file copied from the other server, 
--with authorization to the user created in Step 4
CREATE CERTIFICATE CertificateUserMarketPlace AUTHORIZATION UserMarketPlace
FROM FILE = 'C:\SSB\CertificateUserMarketPlace.cer';
GO

--2.6 Grant connect permissions to the user
GRANT CONNECT
    TO UserMarketPlace;
GO

--2.7 Grant send permissions to the user on the local service
GRANT SEND
    ON SERVICE::StageService
    TO UserMarketPlace;
GO

--2.8 Create a Remote Service Binding with the user created.
CREATE REMOTE SERVICE BINDING ServiceBindingMarketPlace TO SERVICE 'MarketPlaceService'
    WITH USER = UserMarketPlace
GO

--###
--3 Set up Transport Security
--All actions related to Transport Security
--will be performed in Master database of 192.168.20.30
--###
USE master
GO

--3.1 Create a master key for master database.
CREATE Master KEY ENCRYPTION BY Password = '45Gme*3^&fwu';
GO

--3.2 Create certificate and End Point that support certificate based authentication 
CREATE Certificate EndPointCertificateStage
    WITH Subject = 'EndPointCertificateStage'
        ,START_DATE = '2018-01-01'
        ,EXPIRY_DATE = '2020-12-31' ACTIVE
FOR BEGIN_DIALOG = ON;
GO

--3.3 Create End Point that support certificate based authentication
CREATE ENDPOINT ServiceBrokerEndPoint STATE = STARTED AS TCP (LISTENER_PORT = 4022)
FOR SERVICE_BROKER(AUTHENTICATION = CERTIFICATE EndPointCertificateStage, ENCRYPTION = SUPPORTED);
GO

--3.4 Take a backup of the certificate created and install it into the remote instance.
--Copy the certificate to MarketPlace
BACKUP CERTIFICATE EndPointCertificateStage TO FILE = 'C:\SSB\EndPointCertificateStage.cer';
GO

--3.5 Create certificate from the certificate backup file copied from the other server
CREATE Certificate EndPointCertificateMarketPlace
FROM FILE = 'C:\SSB\EndPointCertificateMarketPlace.cer';
GO

--3.6 Create login from the certificate created in Step 3.5
CREATE LOGIN SSBLogin
FROM CERTIFICATE EndPointCertificateMarketPlace;
GO

--3.7 Grant the login, connect permissions on the end point.
GRANT CONNECT
    ON ENDPOINT::ServiceBrokerEndPoint
    TO SSBLogin
GO

SELECT *
FROM sys.service_broker_endpoints
GO

--###
--4 Create a Route
--###
USE Stage
GO

--4.1 Get the UID from MarketPlace database on 192.168.20.44 to use on the Route
SELECT service_broker_guid
FROM sys.databases
WHERE NAME = 'Stage';

--4.2 Use the UID from 4.1
CREATE Route RouteToMarketPlaceService
    WITH SERVICE_NAME = 'MarketPlaceService'
        ,BROKER_INSTANCE = 'A18B5078-EB73-42D4-ACF9-4AF6549921A0' -- From MarketPlace
        ,ADDRESS = 'TCP://192.168.20.44:4022'
GO

现在,当我在启动器服务器上 运行 时,消息卡住:

USE MarketPlace
GO

SELECT conversation_handle, to_service_name, enqueue_time, cast(message_body AS XML)
FROM sys.transmission_queue;

DECLARE @ConversationHandle uniqueidentifier;
BEGIN TRANSACTION
  BEGIN DIALOG @ConversationHandle
  FROM SERVICE MarketPlaceService
  TO SERVICE 'StageService'
  ON CONTRACT PointOfSaleContract
  WITH ENCRYPTION = OFF;
  SEND
  ON CONVERSATION @ConversationHandle
  MESSAGE TYPE SenderMessageType
  ('<test>Test 001</test>')
COMMIT

SELECT conversation_handle, to_service_name, enqueue_time, cast(message_body AS XML)
FROM sys.transmission_queue;

SELECT conversation_handle, is_initiator, state_desc, far_service
FROM MarketPlace.sys.conversation_endpoints;

我在我的目标服务器上看不到我的消息:

--###
--6 Sent Messages from MarketPlace
--###
USE Stage
GO

SELECT cast(message_body AS XML)
FROM TargetQueue;
GO

如果你读到这里。感谢您的关注。

来自"SQL Server 2005 Express Edition Overview"

SQL Server Express can use Service Broker only in combination with other SQL Server 2005 editions. If SQL Server Express receives a Broker message from another Express instance, and if another SQL Server 2005 edition has not processed the message, then the message is dropped. So the message can originate from an Express instance and end up at one, but it must be routed through a non-Express instance if that is the case. You can check a Message Drop trace event that is accessible from the Profiler or use tracing stored procedures to track this type of occurrence. The error message associated with the dropped message includes verbiage to this effect: "This message has been dropped due to licensing restrictions."

我知道这是针对旧版本的方式,但我找不到 2016 年同样冗长的声明。但是,由于 "Editions and supported features of SQL Server 2016" 仍然列出了有关 Service Broker ("No (Client only)") 的限制,所以我这样做相信这对 2016 年仍然有效。

不久前我自己尝试过一个非常相似的设置(也是 2016 Express),但没有找到让它直接工作的方法。

我发现的解决方法是使用 linked 服务器。我通过 link 将 BEGIN DIALOG CONVERSATION ... SEND ON CONVERSATION ... 代码发送到远程服务器并使用 sp_executesql 在那里执行它(在内部,Message Broker 在 Express Edition 中运行良好,它只是不能与其他 Express 交换消息版服务器)。这样做我 运行 进入 bug (显然)与 DTC,这阻止了远程调用最初的工作。相反,它告诉我 DTC 在远程服务器上不可用。然而,这可以通过将 remote proc transaction promotion 选项设置为 false.

来解决
EXEC master.dbo.sp_serveroption @server = N'<the server link>', @optname = N'remote proc transaction promotion', @optvalue = N'true';

在很长一段时间内一切正常。但是 SQL 服务器的一些最新更新可能有问题。至少我的 Service Broker 设置遇到了一些与您类似的问题 运行ge 问题,这些问题似乎是在 SQL 服务器更新的那一天开始的。但由于这不是一件太重要的事情,我还没有时间更详细地研究它并找到解决方案。所以我现在不能给你提示。 (有问题的更新好像是今年5月左右的,不好意思,我现在手头没有KB号。)

另一种选择,如果您仅将其用于开发,则可能是 "upgrade" 开发人员版。这声称功能齐全(相当于企业版 AFAIK)。 Here 是 2017 版的 link。不过我相信也有2016年左右,你要不要坚持2016年呢