Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Server-Side Caching in COM+ and VB : Page 4

Are there times when server-side caching is a good idea? How does server-side caching impact data access performance? Testing the various techniques seems to be the only way this can be determined. Thats what this article is all about. It examines and shows test results for COM+ techniques that are VB-friendly such as using the Shared Properties Manager, using the file system, and using global variables, a lookup table, the Global Interface Table, and commerce.dictionary, and compares these techniques to the caching performance of going to the database each time for data and the baseline when no data is read. Then the article looks at other algorithms and caching options you might want to consider. Also provided with the article is a tool you can use for your own tests.


advertisement

USING THE SHARED PROPERTIES MANAGER

When using server-side caching in MTS/COM+, the SPM might be the first solution you think of. If you use COM+, the SPM is included in the ordinary COM+ Services Type Library. If you use MTS, you must reference the Shared Property Manager Type Library.

In October 1999 I wrote an article for VB-2-The-Max about 18 common programming traps when using MTS and one of those errors was forgetting to use the SPM. Then I gave some test results from an extremely simple test as a proof of its benefits. A little later I received an e-mail from Troy Cambra at Microsoft where he said the following:



"This is potentially a very bad recommendation. The Shared Property Manager does not scale well in many circumstances. On a single processor box it is fine and in the single client test, it is great, but as you add processors and users, you will often find the scaling/performance curve to be opposite to what you expect. Under any load (concurrent users), you will typically see SPM scale inversely with the number of processors. This is because the implementation is rather simplistic and serializes all reads as well as writes. We are going to be coming out with several new best-practices documents and most of them recommend against SPM for such a purpose. SPM is OK in situations were contention will not be an issue or where scalability is not an issue, but other than that, it is usually quite detrimental.

Storing state in the database is currently the best practice and will continue to be so in the immediate future. Writing a solid, well-performing, well-scaling general purpose in-memory cache is extremely difficult. Databases have had decades to optimize and tune accordingly and as such are simply much better at managing state."

After the discussion with Troy I wrote a new article where I discussed the whole SPM matter further. (For the complete article, see The 19th common programming trap in MTS.) I also decided to reduce to a minimum the amount of SPM-related information in my MTS course. As a result, I was especially interested in seeing how the SPM would do in those tests. Figure 9 shows the code I use to do a static fetch in the class for the SPM.

Figure 9. Static fetch in the class for the SPM

Private Function StaticFetch() As Single

Dim spmMgr As SharedPropertyGroupManager

Dim spmGroup As SharedPropertyGroup

Dim spmProperty As SharedProperty

Dim bolGroupAlreadyExists As Boolean

Dim bolPropertyAlreadyExists As Boolean

Dim sngVat As Single

Set spmMgr = New SharedPropertyGroupManager

Set spmGroup = _

spmMgr.CreatePropertyGroup(PropertyGroupName, LockSetGet, _

Process, bolGroupAlreadyExists)

Set spmProperty = spmGroup.CreateProperty(PropertyVat, _
bolPropertyAlreadyExists)

If bolPropertyAlreadyExists = False Then

'Write to SPM!

sngVat = VatGet()

spmProperty.Value = sngVat

Else

sngVat = spmProperty.Value

End If

Set spmProperty = Nothing

Set spmGroup = Nothing

Set spmMgr = Nothing

StaticFetch = sngVat

End Function

Unfortunately I get an Access Violation when I stress the SPM on my SMP machine. I don’t want to draw any conclusions from this because perhaps the problem is related to my cheap, home-built SMP machine. The error 800706be is being raised back to the client and there is information in the event log about the Access Violation. I added symbols to my SMP machine and the call stack reported in the event log is shown in Figure 10:

Figure 10. Call Stack for Error

The serious nature of this error has caused the process to terminate.

Exception: C0000005

Address: 0x7310DC0F

Call Stack:

COMSVCS!CSharedPropGroupObject::CreateProperty(unsigned short *,short *,struct ISharedProperty * *) + 0x7D

COMSVCS!const ATL::CComObject<class CSharedPropGroupObject>::'vftable'{for 'ISupportErrorInfo'} + 0x0

COMSVCS!ATL::CComObject<class CInstancesCollection>::AddRef(void) + 0x0

COMSVCS![thunk]:CSharedPropObject::QueryInterface'adjustor{4}' (struct _GUID const &,void * *) + 0x0

+ 0x136CFA70

I haven’t determined the cause of the error, but after some experimentation I found a way to make the tests work. The recommendation I’ve seen is to always use Requires for the Synchronization support for STA-components. Then you get the same behavior as in MTS. However, I unchecked Enable Just In Time Activation and changed the Synchronization support to Not Supported in the Component Services snap-in and the problem disappeared. Because I had to change the Synchronization support to Not Supported for the component that uses the SPM, the results are hard to compare with all the other components that use Requires as the setting. When I tested the difference for global variables (with Requires and Not Supported) I saw an increase in the throughput between 20% and 25%. Therefore I have decreased the SPM-values by 20% to make the comparison between apples-vs.-oranges less obvious. The results are shown in Figure 11.

Figure 11. Results for using SPM

SPM

No of transactions (1 CPU)

CPU-usage (1 CPU)

No of transactions (2 CPUs)

CPU-usage (2 CPUs)

Static read

29 (see text!)

100%

39 (see text!)

60%

Semi-static read

51 (see text!)

100%

38 (see text!)

33%

I also found it interesting that when I tested with two CPUs, there was a large difference in the load between the CPUs. The first was loaded to about 95% and the second to 30%.

To support Troy’s comments above, you’ll see that the number of transactions dropped relative to the usage of global variables (discussed later) when I compared 2 client processes and 5 client processes.

After reconfiguring the Component Services snap-in, the SPM sometimes performed quite well in this test. However, the results from time to time varied considerably especially for the semi-static read with 2 CPUs. Even though I show the results of a good test, the result drops when the second CPU is added. It may be my lab environment, but I will be reluctant to use the SPM in heavy load scenarios since there are signs of instability and bad scalability.

USING THE FILE SYSTEM

Another common solution to the problem is to use the file system. For example, database triggers could write to a specific file when something changes, but a more typical solution is to recreate the file for semi-static data when the update method updates the database. The update method will be responsible for updating the file too. I don’t think that the files should be the main storage for the data. The main storage should take place in the database and then the values can be cached in files.

I have decided not to use the File System Object for the file handling here, but that is often a good idea. It often performs better than the ordinary Visual Basic file-handling code, but that wasn’t the case in my simple tests.

Something else to consider here is the multithreading aspects of the reading and writing of the files. There are specific solutions for this when it comes to files, but in this test I decided to use a mutex to protect the critical section when I read from and write to the semi-static file. (Read more about Win32-techniques for protecting critical sections on msdn.microsoft.com.)

By the way, watch out in coding critical sections. Be very sure you know what you’re doing before you go there! Figure 12 shows the code I used for the semi-static fetch in this scenario and Figure 13 shows the results.

Figure 12. Semi-static fetch in the class for Files

Private Function SemiStaticFetch() As String

Dim lngHandle As Long

Dim lngResult As Long

Dim intFile As Integer

Dim strBuffer As String

intFile = FreeFile

lngHandle = CreateMutexAndWait(MutexName)

Open App.Path & FileNameProducts For Input As intFile

Input #intFile, strBuffer

Close intFile

ReleaseMutexAndCloseHandle lngHandle

SemiStaticFetch = strBuffer

End Function

Figure 13 Results for Using the File System

Files

No of transactions (1 CPU)

CPU-usage (1 CPU)

No of transactions (2 CPUs)

CPU-usage (2 CPUs)

Static read

6

100%

7

100%

Semi-static read

9

100%

10

69%

I haven’t optimized this code so much better performance is no doubt possible. Even so, I don’t like this solution because the added CPU didn’t help very much at all. The only scenario I can think of for using files are when I don’t want to disturb the database server and I have a scarce amount of memory on the COM+ server or something large to cache. It can also be good for large XML files.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date