SQL Server encounters memory pressure and generate 701 Error due to incorrect configuration of Service Broker
Here is one of the rare scenario on SQL Server memory issue (701 error) caused due service broker misconfiguration or incorrectly used, causing memory object OBJECTSTORE_SERVICE_BROKER to grow and not releasing memory back.
Below is the memory error, we observed in SQL Server error log followed by DBCC MEMORYSTATUS output.
You will see below error messages in SQL Server error log:
2010-02-17 07:28:43.06 Server Failed allocate pages: FAIL_PAGE_ALLOCATION 1
2010-02-17 07:28:43.06 spid14s Error: 701, Severity: 17, State: 123.
2010-02-17 07:28:43.06 spid14s There is insufficient system memory to run this query.
2010-02-17 07:28:43.06 spid12s Error: 802, Severity: 17, State: 11.
2010-02-17 07:28:43.06 spid12s There is insufficient memory available in the buffer pool.
In DBCC MEMORYSTATUS we find:
Memory Manager
VM Reserved = 1650436 KB
VM Committed = 1649556 KB
AWE Allocated = 0 KB
Reserved Memory = 1024 KB
Reserved Memory In Use = 0 KB
MEMORYCLERK_SQLBUFFERPOOL (Total)
VM Reserved = 1632340 KB
VM Committed = 1632340 KB
AWE Allocated = 0 KB
SM Reserved = 0 KB
SM Committed = 0 KB
SinglePage Allocator = 0 KB
MultiPage Allocator = 400 KB
OBJECTSTORE_SERVICE_BROKER (Total)
VM Reserved = 0 KB
VM Committed = 0 KB
AWE Allocated = 0 KB
SM Reserved = 0 KB
SM Committed = 0 KB
SinglePage Allocator = 1523880 KB -->Consuming most of the memory
MultiPage Allocator = 0 KB
The Single Page allocator value for OBJECTSTORE_SERVICE_BROKER object looks interesting and uncommon causing BPOOL exhaustion consuming almost 1.5 GB.
This hints problem towards service broker. Further to go indepth in troubleshooting service broker gathered the information from the view:
select state,COUNT(*) from sys.conversation_endpoints group by state
There were millions of conversations in the view:
count
--------
20930578
“90% of the conversation was in conversing state”
Was checking the service broker configurations and observed that initiator and target was configured on the same database. The service broker was configured to temporarily save the application messages to improve application performance.
The queue was set in auto mode i.e. the procedure at the target would be called automatically to pick up the message from the target queue. Checked the profiler traces and found that there was no call to the target procedure and that seemed to be the cause of the problem.
Further dived deeper into this issue and was successful in reproducing the issue using the steps below:
Repro steps
===========
Note: Intent of the below mentioned repro is just to show that when the stored procedure at the target gets invalidated then the messages get stuck in the queue causing OBJECTSTORE_SERVICE_BROKER object to keep growing.
ALTER DATABASE DBName SET ENABLE_BROKER
create message type req1 AUTHORIZATION dbo validation= None
create message type req2 AUTHORIZATION dbo validation= None
create queue senderqueue
create queue receiverqueue
create contract testcontract (req1 sent by initiator, req2 sent by target)
create service sendreqservice on queue senderqueue(testcontract)
create service receivereqservice on queue receiverqueue(testcontract)
select name,service_broker_GUID from sys.databases where is_broker_enabled=1
create route testroute with service_Name='sendreqservice', broker_instance='CB496106-EC67-41A9-8F01-3EDFE58FB01B', address='TCP://localhost:1433'
create table temp_table (message char(10))
create procedure sp_processqueue
as
begin
Declare @message char(20)
declare @message_type_name varchar(20)
declare @conversationhandle uniqueidentifier
begin
receive top(1)
@conversationhandle =conversation_handle,
@message_type_name=message_type_name,
@message=message_body
from dbo.receiverqueue
if @message_type_name='req1'
begin
insert into temp_table values(@message);
end
--end conversation @conversationhandle with cleanup;
end
end
Alter queue receiverqueue with activation(status=ON,procedure_name = SP_processqueue,execute as owner)
Declare @message char(10);
declare @conversationhandle uniqueidentifier
set @message='hi'
begin dialog conversation @conversationhandle
from service sendreqservice
to service 'receivereqservice'
on contract testcontract
with encryption =off;
send on conversation @conversationhandle
message type req1
(@message);
--end conversation @conversationhandle
Now let’s invalidate the procedure to create the problem:
1. Change the procedure code somewhere and make it invalid:
alter procedure sp_processqueue
as
begin
Declare @message char(20)
declare @message_type_name varchar(20)
declare @conversationhandle uniqueidentifier
begin
receive top(1)
@conversationhandle =conversation_handle,
@message_type_name=message_type_name,
@message=message_body
from dbo.receiverqu --> changed the name to invalid table_name
if @message_type_name='req1'
begin
insert into temp_table values(@message);
end
--end conversation @conversationhandle with cleanup;
end
end
2. Now again run the code to queue a message.
Declare @message char(10);
declare @conversationhandle uniqueidentifier
set @message='hi'
begin dialog conversation @conversationhandle
from service sendreqservice
to service 'receivereqservice'
on contract testcontract
with encryption =off;
send on conversation @conversationhandle
message type req1
(@message);
--end conversation @conversationhandle
select * from temp_table
select * from sys.conversation_endpoints
You will see that the status in the sys.conversation_endpoints is again "CONVERSING". Which is same as the successful execution but the difference is that the message is not processed, you can also check in the profiler trace that we called the stored procedure to process the message but it failed to execute as it was invalid.
1. Now correct the stored procedure:
alter procedure sp_processqueue
as
begin
Declare @message char(20)
declare @message_type_name varchar(20)
declare @conversationhandle uniqueidentifier
begin
receive top(1)
@conversationhandle =conversation_handle,
@message_type_name=message_type_name,
@message=message_body
from dbo.receiverqueue -->changed the name to valid table_name
if @message_type_name='req1'
begin
insert into temp_table values(@message);
end
--end conversation @conversationhandle with cleanup;
end
end
2. Again run the below code to enqueue the message:
Declare @message char(10);
declare @conversationhandle uniqueidentifier
set @message='hi'
begin dialog conversation @conversationhandle
from service sendreqservice
to service 'receivereqservice'
on contract testcontract
with encryption =off;
send on conversation @conversationhandle
message type req1
(@message);
If you see in the profiler trace, there will be no call to the stored procedure at target. Hence the message don’t get processed as its still considered as invalid until we run manually at least once.
To sort out the problem, run the stored procedure manually:
exec sp_processqueue
After this you will find the messages being processed, run the below query to confirm the same.
select * from temp_table
Resolution
==========
1. You will need to run the target procedure manually.
It will deliver the messages to the target and release the space from the OBJECTSTORE_SERVICE_BROKER objectstore.
2. But to clear the messages from the service_endpoints view you will have to change the procedure code to end the conversations (with cleanup).
By:
Harsh Chawla
SE, Microsoft SQL Server
Reviewed by
Nickson Dicson
TL, Microsoft SQL Server
Mukesh Nanda
TL, Microsoft SQL Server
Amit Banerjee
SEE, Microsoft SQL Server
Comments
Anonymous
January 31, 2013
got very use ful and apt informationAnonymous
February 18, 2014
Thanks that was informative about service broker