Improving Performance of Dynamic Web Pages
How the ESI Sample Application Works
Contents
|
This article describes a sample
application that uses Oracle9i Application Server, Oracle9iAS
Web Cache, and Edge Side Includes (ESI) to deliver Web pages of dynamic,
personalized content. The main part of the sample is a JSP-based portal
page. It uses Edge Side Includes for Java (JESI) to identify content fragements
(some cached, some not) and define a template so a complete Web page can
be assembled on demand at the edge of the Internet. This strategy reduces
the load on back-end servers and enables applications to make better use
of the cache, accelerating overall performance. The sample also renders
the same portal page without using JESI or a cache so you can observe the
performance difference first-hand. |
About ESI
The
ESI specification defines a way to improve
performance by reducing the back-end processing load when delivering dynamic
content and applications via the Web. The current version defines four areas:
markup language, architecture, invalidation protocol, and a Java ESI tag library.
A key concept is the notion of page fragments (text, images, forms, and
anything else that can be contained in an HTML document). The figure at right
shows a Web page built from static fragements (examples: titles and buttons)
and dynamic, personalized fragments (examples: stock quotes, news headlines,
and weather data). An ESI template defines a container for fragments
and specifies how to build a Web page from those fragments.
The ESI specification defines an XML-based mark-up
language for defining templates and identifing page fragments. WIth ESI, applications
can deliver Web pages to users faster because only truly dynamic fragments need
to be generated on demand (examples: real-time data, or transactions such as
adding items to a shopping cart or paying a bill). Static fragments and semi-dynamic
fragments (example: temperature data gathered every 30 minutes) can be served
from a cache.
In
contrast, consider how things typically happen today, without ESI. Clients issue
requests, and Web servers, application servers, and databases access expensive
hardware to generate the content, assemble the pages, and then return them to
the clients. The back-end infrastructure has to handle every request, and as
requests increase, performance can degrade. Static pages can be prebuilt and
cached to ease some of the burden, but any page with truly dynamic content must
be completely rebuilt each time it is requested.
ESI provides features that improve the performance of dynamic
Web pages. You can break a page into fragments, and each fragment can have a
cacheability profile: you can specify whether a fragment is cached, and if it
is cached, when it should expire. ESI tags also support conditional logic, so
pages can be assembled based on information in HTTP request headers or browser
cookies. The ESI architecture provides for intermediaries (also called reverse
proxies) that can process ESI tags and act on behalf of the Web server.
Oracle9iAS Web Cache (part of Oracle9i Application Server) includes
an ESI processor. For even faster performance, ESI lets you distribute page-building
chores throughout a content delivery network (CDN) of low-cost servers deployed
across the Internet or a private intranet.
Here's
the flow of events:
- Client browser requests dynamic content from Web site.
- Oracle9iAS Web Cache includes an ESI processor that
returns dynamically-generated HTML with embedded HREF links (for static elements)
that reference the CDN service's domain.
- Client browser requests referenced static objects from
the CDN.
- The CDN's distributed DNS mechanism chooses the optimal
cache server to respond to requests for static content.
ESI and JESI
Conceptually similar to SSI (Server-Side Includes), ESI is
an in-markup scripting language that is interpreted before the page is served
to the client. The core ESI language is based on XML and defines tags that define
templates and identify page fragments, typically in HTML documents.
The following table summarizes the ESI tags.
| Tag |
Description |
<esi:include>
|
Include a cacheable fragment. |
<esi:choose>
|
Conditional execution based on, for example, cookie value
or user agent. |
<esi:try>
|
Specify alternative processing when a request fails. |
<esi:vars>
|
Permit variable substitution (for environment variables). |
<esi:remove>
|
Specify alternative content to be stripped by ESI but
displayed by the browser if ESI processing is not done. |
<!--esi ... -->
|
Specify content to be processed by ESI but hidden from
the browser. |
<esi:inline>
|
Include a cacheable fragment whose body is included in
the template. |
Edge Side Includes for Java (JESI) extends the Java programming
language and makes it easy to write JSPs (JavaServer Pages) using ESI. The JESI
tag library, provided with OracleJSP, can simplify common tasks such as:
- Specifying meta-data information, such as expiry time of
page fragments, conveniently within the JESI tags.
- Sending invalidation messages to purge URLs and expire
cached items.
- Personalizing dynamic pages using cookie information.
JESI tags translate into appropriate calls, such as generating
a HTTP request for invalidation, translating into the appropriate ESI tag in
the generated page, setting the appropriate HTTP response header, etc. For example,
the following JSP code contains JESI tags that include the results returned
by another JSP for a specified login name:
<% if (l_page == 'S' ) { l_url = "CachedStocks.jsp?loginname="+l_pageLoginname; %> <jesi:include page="<%=l_url%>" /> <% } %>
|
The following table summarizes the JESI tags.
| Tag |
Description |
<jesi:template> |
Declares a template and its attributes.
|
<jesi:include> |
Identifies a fragment in a template. This
JSP tag generates <esi:include> tag. |
<jesi:fragment> |
Identifies a fragment in a JSP page. |
<jesi:param> |
Used within a <jesi:include>
tag to specify additional parameters. |
<jesi:codeblock> |
Declares a code block to execute (examples:
authenticate a user or connect to the database) before processing fragments.
|
<jesi:control> |
Declares attributes (example: expiration) of templates and fragments.
|
Design Notes
This sample application is a portal that displays:
- Stocks
- Weather
- Headlines
- Horoscope
- To Do task items for the day
Some of the portal content is generated by providers like
quotes.nasdaq.com, weather.yahoo.com, and astrocenter.com. Other content (example:
tasks in the user's To Do list) comes from the database. The end-user can customise
portal categories, for example, by choosing which stocks to track. This application
also allows the user to change the color scheme, headings, refresh rate, and
layout. The application stores each user's profile in the database and uses
it to select content for the page.
To
demonstrate how caching fragments can improve performance, this sample application
renders the same portal content in two different frames: the upper frame uses
the cache, the lower frame does not. When you load this page the first time,
the cache is empty, so the time required to render each frame is about the same,
depending on network traffic, bandwidth, and other factor external to the application
itself. On subsequent loads, though, the upper frame can use cached data to
render the portal much faster, while load times for the lower frame don't change
much. (Note: If your browser caches pages and page elements locally, you may
see an improvement in load times for the lower frame, as well, but the upper
frame will still load faster.) Each time it loads the portlets, the application
displays a graph so you can compare performance with and without cached fragments.
The main portal page is built from a template consisting of
category fragments and sub-fragments. For example, a stock quote category fragment
includes sub-fragments for ticker symbol, price, and change. Category fragments
are cached for each user, because their content changes for every user. The
sub-fragments carry the same information for every user and they are cached
at global level and are available to all users. The expiration time of a category
fragment is customizable for every user. Expiration of sub-fragments can be
set at the application level.
When a user customizes a category of information, only that
particular category is invalidated in the cache. So, the next request for the
portal page has to fetch only the invalidated informationthe rest can
be fetched from the cache. You can observe this behavior by customizing the
layout of the page or by customizing any category information. The frame without
the cache takes longer to fetch the data because it must rebuild the page from
scratch, a process that includes aggregrating the content from all content providers.
The cached version offers additional benefits via globally
cached fragments, enabling the demo to increase performance as more people use
the application, because more fragments are cached. Example: As more people
request more stock quotes, more stock quotes are stored in the cache, increasing
the probability that, when a user requests a quote, the corresponding fragment
will be in the cache.
The rest of this article describes the cached version in more
detail.
Implementation Notes
The application is implemented using JSPs to declare HTML
page templates and identify content fragments. The JSPs invoke a JavaBean (implemented
in MyPortalBean.java) to perform tasks such as retrieving data
from providers (e.g., stock quotes from nasdaq.com) and querying the database
(e.g., to fetch a user's to-do items).
Declaring
Content Fragments
Each category of information displayed in the portal is declared
as a fragment in a JSP. The various fragments are identified using the JESI
tags and are assembled at run time. The application stores each person's profile
information including the customizable options like color, title of the page,
and refresh rate for each fragment and layout style of the content. This information
is passed to edge server as cookie/session information, which is used by the
JESI tags and then assembled on the fly at the edge server, not at the application
Web server.
The following code comes from CachedStocks.jsp.
<TR> <% // stock quote url for each of the stock quotes String l_symbol[] = (String []) l_symbols.elementAt(i); String l_url = "CachedStock
|
|
|