Cache Data and HTML on the Web Server's Disks
Sometimes, you may have too much data to cache in memory. "Too much" is a judgment call; it depends on how much memory you want to consume, as well as the number of items to cache and the frequency of which these items will be retrieved. In any case, if you have too much data for in-memory caching, consider caching data in text or XML files on the Web servers' hard disks. You can combine caching data on disks and in memory to build the optimum caching strategy for your site.
Note that when measuring the performance of a single ASP page, retrieving data on disk may not always be faster than retrieving the data from a database. But caching reduces load on the database and on the network. Under high loads, this will greatly improve overall throughput. Caching can be very effective when caching the results of an expensive query, such as a multitable join or a complex stored procedure, or caching large result sets. As always, test competing schemes.
ASP and COM provide several tools for building disk-based caching schemes. The ADO recordset Save() and Open() functions save and load recordsets from disk. You could use these methods to rewrite the sample code from the Application data caching tip, above, substituting a Save() to file for the code that writes to the Application object.
There are a few other components that work with files:
- Scripting.FileSystemObject allows you to create, read, and write files.
- MSXML, the Microsoft® XML parser that comes with Internet Explorer, supports saving and loading XML documents.
- The LookupTable object (sample, used on MSN) is a great choice for loading simple lists from disk.
Avoid Caching Non-Agile Components in the Application or Session Objects
While caching data in the Application or Session object can be a good idea, caching COM objects can have serious pitfalls. It is often tempting to stuff frequently-used COM objects into the Application or Session objects. Unfortunately, many COM objects, including all of those written in Visual Basic 6.0 or earlier, can cause serious bottlenecks when stored in the Application or Session objects.Specifically, any component that is not agile will cause performance bottlenecks when cached in the Session or Application objects. An agile component is a component marked
ThreadingModel=Both
that aggregates the Free-threaded marshaler (FTM), or is a component that is marked ThreadingModel=Neutral
. (The Neutral model is new to Windows® 2000 and COM+.) The following components are not agile: - Free-threaded components (unless they aggregate the FTM).
- Apartment-threaded components.
- Single-threaded component.
In IIS 4.0, a component marked
ThreadingModel=Both
was considered agile. In IIS 5.0, that is no longer sufficient. The component must not only be marked Both, it must also aggregate the FTM. Agility in Server Components describes how to make C++ components written with the Active Template Library aggregate the FTM. Be aware that if your component caches interface pointers, those pointers must themselves be agile, or must be stored in the COM Global Interface Table (GIT). If you can't recompile a Both-threaded component to aggregate the FTM, you can mark the component as ThreadingModel=Neutral
. Alternatively, if you don't want IIS performing the agility check (thus, you want to allow non-agile components to be stored at Application or Session scope), you can set AspTrackThreadingModel
to True
in the metabase. Changing AspTrackThreadingModel
is not recommended.IIS 5.0 will throw an error if you attempt to store a non-agile component created with
Server.CreateObject
in the Application object. You can work around this by using <object runat=server scope=application ...>
in Global.asa, but this is not recommended, as it leads to marshaling and serialization, as explained below.What goes wrong if you cache non-agile components? A non-agile component cached in the Session object will "lock down" the Session to an ASP worker thread. ASP maintains a pool of worker threads that services requests. Normally, a new request is handled by the first-available worker thread. If a Session is locked down to a thread, then the request has to wait for its associated thread to become available. Here's an analogy that might help: you go to a supermarket, select some groceries, and pay for them at checkout stand #3. Thereafter, whenever you pay for groceries at that supermarket, you always have to pay for them at stand #3, even though other checkout stands might have shorter or even empty lines.
Storing non-agile components at Application scope has an even worse effect on performance. ASP has to create a special thread to run non-agile, Application-scoped components. This has two consequences: all calls have to be marshaled to this thread and all calls are serialized. Marshaling means that the parameters have to be stored in a shared area of memory; an expensive context switch is made to the special thread; the component's method is executed; the results are marshaled into a shared area; and another expensive context switch reverts control to the original thread. Serialization means that all methods are run one at a time. It is not possible for two different ASP worker threads to be executing methods on the shared component simultaneously. This kills concurrency, especially on multiprocessor machines. Worse still, all non-agile Application-scoped components share one thread (the "Host STA"), so the effects of serialization are even more marked.
Confused? Here are some general rules. If you are writing objects in Visual Basic (6.0) or earlier, do not cache them in the Application or Session objects. If you don't know an object's threading model, don't cache it. Instead of caching non-agile objects, you should create and release them on each page. The objects will run directly on the ASP worker thread, so there will be no marshaling or serialization. Performance will be adequate if the COM objects are running on the IIS box, and if they don't take a long time to initialize and destroy. Note that Single-threaded objects should not be used this way. Be careful—VB can create Single-threaded objects! If you have to use Single-threaded objects this way (such as a Microsoft Excel spreadsheet) don't expect high throughput.
ADO recordsets can be safely cached when ADO is marked as Free-threaded. To mark ADO as Free-threaded, use the Makfre15.bat file, which is typically located in the directory \\Program Files\Common\System\ADO.
Warning:
ADO should not be marked as Free-threaded if you are using Microsoft Access as your database. The ADO recordset must also be disconnected In general, if you cannot control the ADO configuration on your site (for example, you are an independent software vendor [ISV] who sells a Web application to customers who will manage their own configurations), you are probably better off not caching recordsets.
Dictionary components are also agile objects. The LookupTable loads its data from a data file and is useful for combo-box data as well as configuration information. The PageCache object from Duwamish Books provides dictionary semantics, as does the Caprock Dictionary. These objects, or derivatives thereof, can form the basis of an effective caching strategy. Note that the Scripting.Dictionary object is NOT agile, and should not be stored at Application or Session scope.Invite your mail contacts to join your friends list with Windows Live Spaces. It's easy! Try it!
ليست هناك تعليقات:
إرسال تعليق