Application & Session Cache Performance Problem

R

roadrunner

Hi,

Our website has recently been experiencing some problems under load. We have
pinpointed a particular function which slows dramatically when we have these
problems. Normally it should execute in under a second but it rises to about
one minute under duress.

The code is fairly straight forward with no calls to databases or any other
servers. The only dubious thing I can see is that it retrieves several arrays
from the Application cache and a few variables from Session Cache. From
reading around I get the impression that storing arrays in Application cache
can cause thread queuing problems that are only noticeable under heavy loads.
However, some of the documents I have read apply to different versions of
IIS, etc., so I am not sure if the info I have read applies to our
configuration. We are using classic ASP running on IIS6 running on Win2K
Server SP4.

Please can someone confirm whether we may be expeiencing thread queuing on
the Application cache or offer any other explanations.

Thanks,
roadrunner
 
A

Anthony Jones

roadrunner said:
Hi,

Our website has recently been experiencing some problems under load. We have
pinpointed a particular function which slows dramatically when we have these
problems. Normally it should execute in under a second but it rises to about
one minute under duress.

The code is fairly straight forward with no calls to databases or any other
servers. The only dubious thing I can see is that it retrieves several arrays
from the Application cache and a few variables from Session Cache. From
reading around I get the impression that storing arrays in Application cache
can cause thread queuing problems that are only noticeable under heavy loads.
However, some of the documents I have read apply to different versions of
IIS, etc., so I am not sure if the info I have read applies to our
configuration. We are using classic ASP running on IIS6 running on Win2K
Server SP4.

Please can someone confirm whether we may be expeiencing thread queuing on
the Application cache or offer any other explanations.

Storing anything in the application object requires the application to lock
while it's being accessed. If another page attempts to anything with the
application it will block. Heavy use of the application object will result
in threads queing up for access (I'm not sure the queue will be orderly).

Do any of your pages use the .Lock and .Unlock methods. Is it possible that
a few of them are holding on the application object for longer than
necessary?

Are there many different arrays that have different uses?
 
R

roadrunner

Hi Anthony,

We are not using Application.Lock & Unlock on the section of code that is
misbehaving as we are only reading data. The main array we are accessing has
dimensions of 200*20. It stores small (<256 chars) string values.

Thanks,
roadrunner
 
A

Anthony Jones

roadrunner said:
Hi Anthony,

We are not using Application.Lock & Unlock on the section of code that is
misbehaving as we are only reading data. The main array we are accessing has
dimensions of 200*20. It stores small (<256 chars) string values.

An empty array of those dimensions will be 64K to start with. If we
estimate a conservative 20 characters per entry you can add 160K to that.

Each time you access this array it needs to be serialised into the local
memory used by the thread and each time you write it back to the application
object it needs to be serialised.

If you are doing this a lot it is going to impact performance. Whilst this
array is being moved into or out of the application object no other thread
can access the application object.

How are you managing the concurrency of multiple requests trying to modify
this array at the same time?

Without a lock the state of this array is going to get into a real mess
isn't it?
 
E

Evertjan.

Anthony Jones wrote on 15 mei 2006 in
microsoft.public.inetserver.asp.general:
An empty array of those dimensions will be 64K to start with. If we
estimate a conservative 20 characters per entry you can add 160K to
that.

Each time you access this array it needs to be serialised into the
local memory used by the thread and each time you write it back to the
application object it needs to be serialised.

If you are doing this a lot it is going to impact performance. Whilst
this array is being moved into or out of the application object no
other thread can access the application object.

How are you managing the concurrency of multiple requests trying to
modify this array at the same time?

Without a lock the state of this array is going to get into a real
mess isn't it?

You should not do an unlocked write.

If the applicatin variable is read once every page access, and say 500
users get one page every quarter minute, this will give 33 reads per
second. Would that amount to your "real mess"?

I think the question is if the problem is worse than withother methods.

Worse than Jet engine access of a database containing the same?

Worse than the same with SQL-server?

=================

I read once and somewhere that:

<%
application("mine")=application("mine")+1
%>

has an imlpied lock mechanism in ASP. Is this true?
 
R

roadrunner

To repeat, no writes are being made in the problematic function, nor in any
others that are being executed at the same time. The 'large' array is loaded
when the application first starts and not modified after that. Also, we are
not experiencing high memory usage or cpu on the servers.

Anthony you say "whilst this array is being moved into or out of the
application object no other thread can access the application object". If
there are no application.locks and we are not updating the array anywhere why
is there this restriction?
 
A

Anthony Jones

roadrunner said:
To repeat, no writes are being made in the problematic function, nor in any
others that are being executed at the same time. The 'large' array is loaded
when the application first starts and not modified after that. Also, we are
not experiencing high memory usage or cpu on the servers.

Anthony you say "whilst this array is being moved into or out of the
application object no other thread can access the application object". If
there are no application.locks and we are not updating the array anywhere why
is there this restriction?

Yes it still needs to be serialised into the threads local memory before
vbscript can access it's contents. Hence every page that uses it represents
at least one movement of 160K+ of memory. That's quite a lot of memory to
be allocating and deallocating frequently. This is a bad enough situation
as it is.

One would hope that the application object understands the difference
between mutliple read attempts and a write attempt thus allowing multiple
concurrent reads of the array but I wouldn't count on it. If it doesn't
then threads would queue up to read the array.

An alternative perhaps would be to use a FreeThreaded XML DOM. Accessing
this doesn't require the entire set of data to be moved into the thread's
local memory. It depends on usage but it may be worth a try.


Anthony.
 
B

Bob Barrows [MVP]

roadrunner said:
Hi,

Our website has recently been experiencing some problems under load.
We have pinpointed a particular function which slows dramatically
when we have these problems. Normally it should execute in under a
second but it rises to about one minute under duress.

The code is fairly straight forward with no calls to databases or any
other servers. The only dubious thing I can see is that it retrieves
several arrays from the Application cache and a few variables from
Session Cache. From reading around I get the impression that storing
arrays in Application cache can cause thread queuing problems that
are only noticeable under heavy loads. However, some of the documents
I have read apply to different versions of IIS, etc., so I am not
sure if the info I have read applies to our configuration. We are
using classic ASP running on IIS6 running on Win2K Server SP4.

Please can someone confirm whether we may be expeiencing thread
queuing on the Application cache or offer any other explanations.
Does your page pull the data from Application once, storing it in a local
variable? Or did the author make the mistake of repeatedly reading the data
from Application in the same page?
 
A

Anthony Jones

Evertjan. said:
Anthony Jones wrote on 15 mei 2006 in
microsoft.public.inetserver.asp.general:


You should not do an unlocked write.

If the applicatin variable is read once every page access, and say 500
users get one page every quarter minute, this will give 33 reads per
second. Would that amount to your "real mess"?

No. At the time of asking I was concerned that without the benefit of
lock/unlock the array would become corrupt due to concurrent
read-modify-write cycles on the array.
I think the question is if the problem is worse than withother methods.

Worse than Jet engine access of a database containing the same?

Depends on how much of the array content is needed per request.
Worse than the same with SQL-server?
Ditto


=================

I read once and somewhere that:

<%
application("mine")=application("mine")+1
%>

has an imlpied lock mechanism in ASP. Is this true?

At the end of the day it's just COM copying the content of a variant from
one apartment to another. Certainly you can't have two requests writing the
same application value at the same time so some locking has to be inplace.
I doubt the locking is as granular as per named item. It's probably a
single lock on the application object after all it isn't designed to store
rapidly changing data.

 
M

Michael D. Kersey

Rather than asking us to speculate based on your (possibly incorrect)
description and diagnosis of the problem, please post the code. Include
the entire section of code that you are _certain_ contains the problem.
I'm assuming that you know roughly where the problem is but are
unfamiliar with the exact nature of the problem.
 
R

roadrunner

Thanks Anthony, You mean store the array in an xml file instead of the
application object? I guess this would slow down a single request? For
multiple requests, wouldn't there be contention to access it by the threads
still?
 
R

roadrunner

Hi Bob, The application object is referenced each time a different element of
the array is required. I know this is a bit bad from a speed point of view
due to object references but from what Anthony says it sounds like the
Application object should be avoided for arrays completely. I am posting a
simplfied version of the sub under Michael Kersey's post to give a better
idea of what it does.
 
R

roadrunner

Hi Michael,

Here is a simplifed (for readability/legal reasons) version of the code.

Sub WithContentionProblems (byref intNumItems)

Dim intItemIndex, intSubItemIndex

intNumItems = 0

For intItemIndex = 1 To UBound(Application("Items"),2)
For intSubItemIndex = 2 To 0 Step -1
If InStr(1, "," & Request.ServerVariables("HTTP_TYPES") & ",",
",""WIDGETS"",", vbTextCompare) > 0 ) Then
parrItemData(0, intNumItems) = intItemIndex
parrItemData(1, intNumItems) = 1
parrItemData(2, intNumItems) = Application("Items")(2, intItemIndex)
parrItemData(3, intNumItems) = Application("Items")(3, intItemIndex)
parrItemData(4, intNumItems) = Application("Items")(4, intItemIndex)
parrItemData(5, intNumItems) = Application("Items")(5, intItemIndex)
parrItemData(6, intNumItems) = intSubItemIndex
parrItemData(7, intNumItems) = Application("Items")(7, intItemIndex)
parrItemData(8, intNumItems) = Application("Items")(8, intItemIndex)
parrItemData(9, intNumItems) = Application("Items")(9, intItemIndex)
intNumItems = intNumItems + 1
Exit For
End If
Next
Next

End Sub
 
B

Bob Barrows [MVP]

It's more than a "bit" bad. It is probably what is exacerbating what
Anthony is talking about. Frankly, I've never had an issue with using an
array in Application, as long as I minimize references to it.
 
B

Bob Barrows [MVP]

This is horrible, but it looks real easy to fix. Do a search/replace,
replacing Application("Items") with "arItems" (no quotes of course). Then
add
dim arItems
arItems=Application("Items")
at the appropriate scope: put it outside the sub if used in multiple
procedures, inside the sub if used only within the sub.
 
R

roadrunner

Thanks Bob, I am going to run this in loadrunner to simulate multi-user
conditions over the next few days and then try making the changes you suggest
and comparing the times. I will let you know how it goes but it may be a few
days before I can do this.
 
A

Anthony Jones

roadrunner said:
Thanks Anthony, You mean store the array in an xml file instead of the
application object?

I mean store your data in an XML file then on application start load that
file into a Free Threaded DOM :-

"MSXML2.FreeThreadedDOMDocument.3.0"

Store this DOM object in the application object.

If you store your array as a series of 200 elements each with a 20 child
elements then access it like:-

Dim oDOM : Set oDOM = Application("xmlDom")

x = oDOM.childNodes(123).childNodes(15).text

Not as fast as accessing an array but the only data that needs to marshalled
into the local thread is the string going into x not the entire array.
I guess this would slow down a single request? For
multiple requests, wouldn't there be contention to access it by the threads
still?

Not when all those accesses are reads.

While your at it you might consider using an include to abstract this. If
this approach doesn't work out you can change the implementation behind the
abstract without changing lots of pages again.

IOW:-

'ArrayAccessor.asp
<%

Class ArrayAccessor

Private moDOM

Public Property Get Item(x,y)
Item = moDOM.childNodes(x).childNodes(y).Text
End Property

Private Sub Class_Initialize()
Set moDOM = Application("xmlDOM")
End Sub

End Class
%>

'YourPage.asp
<!-- #include virtual="/utils/ArrayAccessor.asp" -->
<%

Dim oArr: Set oArr = New ArrayAccessor

x = oArr.Item(123,15)

%>

If the FreeThreaded DOM stuff doesn't work out for you, you need only change
the ArrayAccessor.asp page.
 
A

Anthony Jones

roadrunner said:
Hi Michael,

Here is a simplifed (for readability/legal reasons) version of the code.

Sub WithContentionProblems (byref intNumItems)

Dim intItemIndex, intSubItemIndex

intNumItems = 0

For intItemIndex = 1 To UBound(Application("Items"),2)
For intSubItemIndex = 2 To 0 Step -1
If InStr(1, "," & Request.ServerVariables("HTTP_TYPES") & ",",
",""WIDGETS"",", vbTextCompare) > 0 ) Then
parrItemData(0, intNumItems) = intItemIndex
parrItemData(1, intNumItems) = 1
parrItemData(2, intNumItems) = Application("Items")(2, intItemIndex)
parrItemData(3, intNumItems) = Application("Items")(3, intItemIndex)
parrItemData(4, intNumItems) = Application("Items")(4, intItemIndex)
parrItemData(5, intNumItems) = Application("Items")(5, intItemIndex)
parrItemData(6, intNumItems) = intSubItemIndex
parrItemData(7, intNumItems) = Application("Items")(7, intItemIndex)
parrItemData(8, intNumItems) = Application("Items")(8, intItemIndex)
parrItemData(9, intNumItems) = Application("Items")(9, intItemIndex)
intNumItems = intNumItems + 1
Exit For
End If
Next
Next

End Sub

Yikes!!!

Having made my ealier post before reading this I would definitely say you
should try Bob's suggestion first before complicating things with DOMs etc.
 
R

roadrunner

Ok, will do.

Anthony Jones said:
Yikes!!!

Having made my ealier post before reading this I would definitely say you
should try Bob's suggestion first before complicating things with DOMs etc.
 
M

Michael D. Kersey

roadrunner said:
Hi Michael,
Here is a simplifed (for readability/legal reasons) version of the code.

Sub WithContentionProblems (byref intNumItems)
Dim intItemIndex, intSubItemIndex
intNumItems = 0

For intItemIndex = 1 To UBound(Application("Items"),2)
For intSubItemIndex = 2 To 0 Step -1
If InStr(1, "," & Request.ServerVariables("HTTP_TYPES") & ",",
",""WIDGETS"",", vbTextCompare) > 0 ) Then
parrItemData(0, intNumItems) = intItemIndex
parrItemData(1, intNumItems) = 1
parrItemData(2, intNumItems) = Application("Items")(2, intItemIndex)
parrItemData(3, intNumItems) = Application("Items")(3, intItemIndex)
parrItemData(4, intNumItems) = Application("Items")(4, intItemIndex)
parrItemData(5, intNumItems) = Application("Items")(5, intItemIndex)
parrItemData(6, intNumItems) = intSubItemIndex
parrItemData(7, intNumItems) = Application("Items")(7, intItemIndex)
parrItemData(8, intNumItems) = Application("Items")(8, intItemIndex)
parrItemData(9, intNumItems) = Application("Items")(9, intItemIndex)
intNumItems = intNumItems + 1
Exit For
End If
Next
Next

End Sub

The expression in the statement:
If InStr(1, "," & Request.ServerVariables("HTTP_TYPES") & ",",
",""WIDGETS"",", vbTextCompare) > 0 ) Then

always has the same value (is a "loop invariant") - it's being
unnecessarily recomputed with each iteration. Another thing is that
Request.ServerVariables is rumoured to be a costly request and anyway it
is necessary to call it only once. Taking the entire invariant
expression out of the two loops yields something like (untested code):
strSearch = "," & Request.ServerVariables("HTTP_TYPES") & ","
strFind = ",""WIDGETS"","
IntWidget = InStr(1, strSearch, strFind , vbTextCompare)
For intItemIndex = 1 To UBound(Application("Items"),2)
For intSubItemIndex = 2 To 0 Step -1
If ( intWidget > 0 ) Then
...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top