建立分布式Service Broker应用程序
步骤:
I.创建基本的Service Broker对象:
在ServerA的DatabaseA里,让我们执行下面的操作:
1)创建消息类型
Create Message Type SenderMessageType validation=NONE Create Message Type ReceiverMessageType validation=NONE |
2)在上面的消息类型上创建约定
Create Contract SampleContract( SenderMessageType SENT BY INITIATOR, ReceiverMessageType SENT BY TARGET) |
3)创建一个发起队列
Create Queue InitiatorQueue WITH status = ON |
4) 在队列和约定上创建服务
Create Service SenderService ON QUEUE InitiatorQueue (SampleContract) |
在ServerB的DatabaseB里,让我们执行下面的操作:
1) 创建消息类型:
Create Message Type SenderMessageType validation=NONECreate Message Type ReceiverMessageType validation=NONE |
2)在上面的消息类型上创建约定
Create Contract SampleContract( SenderMessageType SENT BY INITIATOR, ReceiverMessageType SENT BY TARGET) |
3)创建一个目标队列
Create Queue TargetQueue WITH status= ON |
4)在队列和约定上创建服务
Create Service ReceiverService ON QUEUE TargetQueue (SampleContract) |
注意: 在上面的代码里我们已经在两个服务器上创建了同样的消息类型和约定。我们需要在参与会话的每个数据库里创建同样的消息类型和约定.
II. 创建路由:
一旦在两个服务器上创建了服务,我们就需要在每个数据库里创建路由并联合远程服务来发送消息.
在ServerA的DatabaseA里
Create Route RouteAWITH SERVICE_NAME = 'ReceiverService', BROKER_INSTANCE = '1B9C40BC-7FCF-41F7-9813-61C11A49D0DE', ADDRESS = 'TCP://157.57.100.9:4022'GO |
在上面的路由里,ReceiveService是ServerB的DatabaseB里的服务。如果不指定broker_instance,那么有相同名称的服务将被ServerB从任何数据库里随机的挑选。但如果你要明确说明需要映射到DatabaseB的ReceiveService的话,那么我们需要使用下面的查询从sys.databases里获取DatabaseB的Service_broker_guid。
select service_broker_guid from sys.databases where name = 'DatabaseB' |
Address部分告诉我们需要连接到IP地址为157.57.100.9端口号为4022的ServerB。
在ServerB的DatabaseB里
用相同的方式创建路由(在我们的例子里需要创建这个路由,因为一旦我们在ServerB里处理了ServerA发来的消息,我们要给ServerA发回消息)。
Create Route RouteBWITH SERVICE_NAME = 'SenderService', BROKER_INSTANCE='D164787D-590A-47AC-83AB-987F880E3F2A', ADDRESS = 'TCP://172.22.26.216:4022'GO |
III. 设置传输安全:
注意:所有关于传输安全的操作都将在服务器的master数据库里执行。
1) 为master数据库创建主密钥
2) 创建证书和支持基于验证的证书的终端
Server A:
Use masterGo--1. Create a master key for master database.Create Master Key Encryption BY Password = 'gs53&"f"!385'Go/*2.Create certificate and End Point that support certificate based authentication */Create Certificate EndPointCertificateAWITH Subject = 'A.Server.Local', START_DATE = '01/01/2006', EXPIRY_DATE = '01/01/2008'ACTIVE FOR BEGIN_DIALOG = ON;GOCREATE ENDPOINT ServiceBrokerEndPoint STATE=STARTED AS TCP (LISTENER_PORT = 4022) FOR SERVICE_BROKER ( AUTHENTICATION = CERTIFICATE EndPointCertificateA, ENCRYPTION = SUPPORTED ); |
Server B:
Use masterGo --1. Create a master key for master database.Create Master Key Encryption BY Password = '45Gme*3^&fwu';Go--2.Create certificate and End Point that support certificate based authentication.Create Certificate EndPointCertificateBWITH Subject = 'B.Server.Local', START_DATE = '01/01/2006', EXPIRY_DATE = '01/01/2008'ACTIVE FOR BEGIN_DIALOG = ON;GOCREATE ENDPOINT ServiceBrokerEndPoint STATE=STARTED AS TCP (LISTENER_PORT = 4022) FOR SERVICE_BROKER ( AUTHENTICATION = CERTIFICATE EndPointCertificateB, ENCRYPTION = SUPPORTED ); |
3) 做一个已创建好的证书的一个备份,并拷贝到另一个服务器上,把它安装到远程实例里。
Server A:
BACKUP CERTIFICATE EndPointCertificateA TO FILE = 'C:/Documents and Settings/Santhi/Desktop/Service Broker/Session/EndPointCertificateA.cer';GO |
把证书从上面的位置拷贝到下面的位置
目标: Server B
路径: C:/Documents and Settings/Santhi/Desktop/ServiceBroker/
Server B:
BACKUP CERTIFICATE EndPointCertificateB TO FILE= 'C:/Documents and Settings/Santhi/Desktop/ServiceBroker/EndPointCertificateB.cer';GO |
把证书从上面的位置拷贝到下面的位置
目标: Server A
路径: C:/Documents and Settings/Santhi/Desktop/ServiceBroker/Session/
4)从另一个服务器里拷贝过来的证书备份文件里创建证书。
Server A:
Create Certificate EndPointCertificateB From FILE = 'C:/Documents and Settings/Santhi/Desktop/Service Broker/Session/EndPointCertificateB.cer';GO |
Server B:
Create Certificate EndPointCertificateA From FILE = 'C:/Documents and Settings/Santhi/Desktop/ServiceBroker/EndPointCertificateA.cer';GO |
5)在目前的服务器里从证书里创建一个远程服务器的登录。
Server A:
CREATE LOGIN sbLogin FROM CERTIFICATE EndPointCertificateB;GO |
Server B:
CREATE LOGIN sbLogin FROM CERTIFICATE EndPointCertificateA;GO |
6)在终端上分配登录和连接权限。
Server A:
GRANT CONNECT ON ENDPOINT::ServiceBrokerEndPoint To sbLoginGO |
Server B:
GRANT CONNECT ON ENDPOINT::ServiceBrokerEndPoint To sbLoginGO |
IV. 设置对话安全:
注意:所有与对话安全相关的操作都是再ServerA的DatabaseA和ServerB的DatabaseB里执行的,而不是在master数据库里。
1) 在本地数据库也就是我们的应用程序将要使用的数据库里创建主密钥。
Server A:
Use DatabaseAGOCreate Master Key Encryption BYPassword = 'gs53&"f"!385'Go |
Server B:
Use DatabaseBGOCreate Master Key Encryption BYPassword = '45Gme*3^&fwu';Go |
2)创建用户证书
Server A:
Create Certificate UserCertificateA WITH Subject = 'A.Server.Local', START_DATE = '01/01/2006', EXPIRY_DATE = '01/01/2008'ACTIVE FOR BEGIN_DIALOG = ON;GO |
Server B:
Create Certificate UserCertificateB WITH Subject = 'B.Server.Local', START_DATE = '01/01/2006', EXPIRY_DATE = '01/01/2008'ACTIVE FOR BEGIN_DIALOG = ON;GO |
3)备份创建好的用户证书并在远程实例上安装。
Server A:
BACKUP CERTIFICATE UserCertificateA TO FILE='C:/Documents and Settings/Santhi/Desktop/Service Broker/Session/UserCertificateA.cer';GO |
把上面位置的证书复制到下面的位置
目标: Server B
路径: C:/Documents and Settings/Santhi/Desktop/ServiceBroker/
Server B:
BACKUP CERTIFICATE UserCertificateB TOFILE='C:/Documents and Settings/Santhi/Desktop/ServiceBroker/UserCertificateB.cer';GO |
把上面位置的证书复制到下面的位置
目标: Server A
路径: C:/Documents and Settings/Santhi/Desktop/ServiceBroker/Session/
4)创建一个和在另一个数据库里有访问权限的用户的名称相同的用户。
Server A:
Create User UserB WITHOUT LOGINGO |
Server B:
Create User UserA WITHOUT LOGINGO |
5)使用在第4步里创建的用户的验证,来从复制到另一个服务器上的证书备份文件里创建一个用户证书。
Server A:
CREATE CERTIFICATE UserCertificateB AUTHORIZATION UserB FROM FILE = 'C:/Documents and Settings/Santhi/Desktop/Service Broker/Session/UserCertificateB.cer';GO |
Server B:
CREATE CERTIFICATE UserCertificateA AUTHORIZATION UserAFROM FILE = 'C:/Documents and Settings/Santhi/Desktop/ServiceBroker/UserCertificateA.cer';GO |
6)给用户分配连接权限。
Server A:
GRANT CONNECT TO UserB; |
Server B:
GRANT CONNECT TO UserA; |
7)在本地服务上给用户分配发送权限。
Server A:
GRANT SEND ON SERVICE::SenderService To UserB;GO |
Server B:
GRANT SEND ON SERVICE::ReceiverService To UserA;GO |
8)使用创建的用户来创建一个远程服务绑定。
Server A:
CREATE REMOTE SERVICE BINDING ServiceBindingB TO SERVICE 'ReceiverService' WITH USER = UserB |
Server B:
CREATE REMOTE SERVICE BINDING ServiceBindingA TO SERVICE 'SenderService' WITH USER = UserA |
V. 从ServerA发送消息
在DatabaseA里:
/**********Begin a Dialog and Send a Message******************/Declare @ConversationHandle uniqueidentifierBegin TransactionBegin Dialog @ConversationHandle From Service SenderService To Service 'ReceiverService' On Contract SampleContract WITH Encryption=off;SEND ON CONVERSATION @ConversationHandle Message Type SenderMessageType ('<test>test</test>')Commit |
上面的代码打开一个事务并使用不加密的方式在特定的约定上开始一个对话。然后它使用创建的ConversationHandle在会话上发送一个消息,接着提交事务。在开始会话的时候,我们也指定了将用来发送和接收消息的服务。
现在在DatabaseB(serverB上)的TargetQueue里检查这条记录。
select cast(message_body as xml) from TargetQueue |
VI. 接收来自ServerA的消息:
在DatabaseB里:
/*****Receive the Message and send a message to the ender**********/Declare @ConversationHandle as uniqueidentifierDeclare @MessageBody as nvarchar(max)Declare @MessageType as sysnameBegin TransactionPrint 'Started Receiving ';RECEIVE top (1) @MessageType = message_type_name, @ConversationHandle = conversation_handle, @MessageBody = message_bodyFROM TargetQueue;if @MessageType = 'SenderMessageType' Begin SEND ON CONVERSATION @ConversationHandle Message Type ReceiverMessageType ('Message is received') END Conversation @ConversationHandle ENDCommit |
上面的代码打开一个事务并从TargetQueue里接收第一条消息。在接收消息后,我们就可以执行一些其他的逻辑了,但在我们的例子里,为了简化已收到的消息,我们仅仅把消息发回发送者。
现在在DatabaseB(ServerB上)检查一下记录。当记录被成功处理后就会被删除。现在检查一个DatabaseA(ServerA上)的InitiatorQueue的记录。当使用了终端会话时,两条新的记录将被插入,一条是相关于会话的。另一条是相关于终端对话的。
select cast(message_body as xml) from InitiatorQueue |
结论:
本文没有讨论Service Broker的基本概念。它用来处理分布式service broker应用程序的建立。