What happens too soon - AMIS Technology Blog

advertisement
Improve Your ADF Fusion Application's
Response Time by as Much as 70 Percent
Frank Houweling (AMIS, The Netherlands) ODTUG Kscope13
1
Agenda
•
•
•
•
•
•
•
•
•
•
Why is performance so important ?
Overview typical ADF bottlenecks
What happens too slowly
What happens too often
What happens too soon
Too little
Too big
Demo (examples)
AMIS ADF Performance Monitor
Summary performance tips
Customers do not accept slow
applications anymore
Overview typical bottlenecks (1)
What happens too slowly:
• ViewObject queries
• PL-SQL calls from ApplicationModules
• EntityObject DML operations
• ApplicationModule passivation & activation
• ApplicationModule transactions
What happens too often:
• ViewObject queries (more than 1 of the same VO during a request)
• ViewObject queries caused by unintentionally left iterator bindings in pageDefs
• Database roundtrips
• HTTP requests
• Loading too much database rows in ADF BC memory
• ApplicationModule passivation / activation
• Logging that could have been turned off (or less)
Overview typical bottlenecks (2)
What happens too soon:
• Taskflow executions
• Loading (immediate versus lazy)
Too little:
• Caching
• JVM heap space
Too big:
• Too big scope for managed beans
• Too much HTML sent to browser
Agenda
• Why is performance so important ?
• Overview typical ADF bottlenecks
• What happens too slowly
Slow database executions
• Many bottlenecks are simply caused by slow ViewObject queries, PL-SQL
calls or EntityObject DML operations
• Often hard to track which queries are slow
• Some queries are only slow for certain bind parameters
• Some queries are not slow during a development phase but are slow in a
production environment (that has much more data)
RDBMS
Measure execution time of
ViewObject queries
Override executeQueryForCollection() in project base class during
development
Output in JDeveloper server log:
Other ways to detect slow
database executions (1)
• Oracle ADF Logger diagnostic tool in JDeveloper
Other ways to detect slow
database executions (2)
• Set up a database trace
-Queries from database perspective
-Disadvantage: database executions not from ADF application’s
perspective, often not easy to relate database trace to ADF executions
• AppDynamics (general JEE performance monitor)
-Could be useful to monitor slow requests and see slow database
executions
-Problem: looks at the request URL to distinguish http request and
business transactions. ADF uses often the same URL for many http
requests
Agenda
•
•
•
•
Why is performance so important ?
Overview typical ADF bottlenecks
What happens too slowly
What happens too often
Too often executed ViewObject
queries
• More than 1 execution of the same VO during a single http request (!)
• (Unintentionally) programmed by developer
•
•
•
•
•
•
Often caused by:
Inefficient set refresh property of iterator binding in pageDef
ViewAccessor’s queries that are used for lookup items in af:table,
af:treeTable or af:tree components
Default implementation of a <af:treetable> or <af:tree> with associations
and viewlinks executes each detail VO node in a mini query
Custom ADFBC overrides and programmatically executed iterators
Nested <af:iterators> in <af:iterators> on iterator bindings that bind to
ViewObjects with associations and viewlinks
Master-detail-detail behavior with ADFBC with associations and viewlinks
PageDef iterator binding
refresh property
• Refreshing an iterator binding reconnects it with its underlying
•
•
•
•
•
RowSetIterator object (=ViewObject)
Default value is deferred. This means ‘on demand’: the binding will not be
executed unless its value is accessed
In most cases: leave it at default (=deferred)
Be very careful with refresh=“IfNeeded” - is the root cause of many
unnecessary queries. It means: refresh and re-execute the query when
any of the bind parameter values have changed
Use RefreshCondition if you want to refresh query conditionally
Don’t use refresh=“Always” - the underlying ViewObject will re-execute
multiple times during a http request
Too often executed ViewObject
mini-queries (1)
• Default implementation of <af:treetable>
or <af:tree> with associations and
viewlinks executes each detail VO node
query and is a potential bottleneck
• Solution: create a custom managed bean
responsible for building the hierarchical
structure in Java - it retrieves
the data from the BindingContainer and
manages the page
• Replace the multiple queries with one
single query with
nodeId’s and parentNodeId’s
Too often executed ViewObject
mini-queries (2)
• Nested <af:iterators> in <af:iterators> on iterator bindings that bind to
ViewObjects with associations and viewlinks cause multiple mini-queries
• Solution: create a custom managed bean responsible for building the
hierarchical structure in Java en that retrieves the data from the
BindingContainer and manages the page
Too often executed ViewObject
mini-queries (3)
• Custom ADFBC overrides and programmatically execute iterators can
have unexpected behavior – many mini queries
• Every getter method in a ViewRowImpl can be called multiple times
during a request
Fetching the data of the Pension
fund for the web application
<
>
select *
from
employers
where id = < 324>
1
record
100s
records
select *
from
participants
where employer_id = < 324>
10s records
select *
from
benefits
where participant_id = <#>
Reporting on many employers
select *
from
employers
100s
records
1 query
10k records
select *
100s
from
participants
queries
where employer_id = <#>
100k
select *
records
from
benefits
10k queries
where participant_id = <#>
Single bulk retrieve replacing
multiple queries
• Have the database bulk up the data retrieval
• Return Ref Cursor, Types and Collections or JSON/XML
Benefits Package
select *
from
employers
where id in <some set> select *
from
participants
where employer_id in <some set>
select b.*
from
benefits b join participants p
on (p.id = b.participant_id)
where p.employer_id in <some set>
Unintentionally left iterators in
pageDefs
• ViewObject queries caused by unintentionally left iterators in pageDefs
• Iterator bindings can still be refreshed and the ViewObject unnecessary
executed - for example when you have Refresh=“ifNeeded”)
Too many database roundtrips (1)
• The ViewObject fetch mode and fetch size properties
(ViewObject General Tab - Tuning section) controls how many
rows will be returned in each round-trip to and from the database
Too many database roundtrips (2)
• ViewObject fetchMode and fetchSize are underestimated
•
•
•
•
•
properties and have big performance impact
The default value is 1 - will give poor performance (unless only
one row will be fetched)
Set the in Batches of value to gain performance efficiencies.
Rule of thumb: If you are displaying n rows at a time in the user
interface, set the fetch size to at least n + 1, so that each page
of results can be retrieved in a single round-trip to and from the
database
For selection lists where you need all the records set
fetchMode to All at once
As you increase this value, however, you also increase the
client-side buffer requirements, so you shouldn't just set this
number arbitrarily high
Too many HTTP Requests (1)
• The iterator binding rangesize property represents the current set
of objects to be displayed on the page
• Rule of thumb: for af:tables, af:treetable and af:tree components
set the rangesize to the max number of records that you can
display in the browser, not more (usually not more than 50)
• If you display 30 records and your rangesize=25 (default), than 2
http request from the client are needed to show the 30 records (!)
• For selection lists where you need all records set rangesize to -1
Too many HTTP Requests (2)
• Make use of the powerful ADF AJAX capabilities
• Set where possible on all af:command<xxx> components (buttons, links,
menu-items, etc) partialSubmit="true“ and immediate="true"
(check the 18 lessons of ADF and JSF interaction of Steven Davelaar)
• If you don’t use partialSubmit="true“ than the whole page is refreshed
• More http requests could be sent to the server than needed
HTTP Requests
Demo
• World’s most inefficient HR application !
Too much data in ADFBC
memory (1)
• Try to avoid loading more database rows than you need
• Be careful if you really do need to load a proportional number of database
rows
Too much data in ADFBC
memory (2)
• Database rows are cached in the ViewRowStorage and EntityCache
• If you query a proportional number of database rows
•
•
•
•
many database rows memory consumption can be high
Use accessmode=Range Paging if you have to display +- more than 250
records in an af:table, af:treeTable or af:tree
Query resource intensive data only on demand (BLOBS, CLOBS, etc.)
Limit the ViewObject query result rows by bind parameters where possible
Use read-only ViewObjects where update is not needed (if EO based:
deselect the updatable checkbox
Demo ViewObject Range Paging
Too frequent ApplicationModule
passivation & activation (1)
• Application module (AM) pooling enables multiple users to share
several application module instances. It may involve saving and
retrieving session state data from the database. This mechanism is
provided to make the application scalable and becomes very
important under high load with many concurrent users
Too frequent ApplicationModule
passivation & activation (2)
• Often during development the AM
pooling settings are not considered
important and left at their default.
• On a production environment, not setting
these parameters correct (and leaving
them at the default values) can be very
inefficient and may cause many
unneeded passivations and activations
• Carefully read the documentation in the
ADF Fusion developers Guide (Ch. 44 of
the 11gR2 Fusion Developer Guide)
ApplicationModule pooling
guidelines (1)
Recommended by Oracle Fusion Guide:
Oracle’s rule of thumb for setting the AM pool size is to set the
maxavailablesize and the recyclethreshold parameters to the expected
number of peak concurrent users that perform multiple operations with
short think times:
• jbo.ampool.maxavailablesize = jbo.recyclethreshold
• jbo.ampool.minavailablesize = 80 % of jbo.ampool.maxavailablesize
• jbo.ampool.doampooling=true (default)
• jbo.doconnectionpooling=false (default)
This avoids application module instantiation time when load increases the hit is taken at server startup. This also avoids recycling (passivation
cycle) of AM under normal load.
Be careful: setting the maxavailablesize and recyclethreshold too high can
result in a (too) big memory consumption (Java heap space) and can
cause out-of-memory-exceptions.
ApplicationModule pooling
guidelines (2)
Recommended by Duncan Mills:
• Increase jbo.ampool.maxinactiveage
• Set jbo.ampool.timetolive = -1
Results in more available AMs and avoid passivation/ activation costs
More recommended by Oracle Fusion Guide:
• If your highest concern and priority is to limit the number of database
connections, set jbo.doconnectionpooling=true (in combination with
jbo.txn.disconnect_level=1), otherwise leave it at false (default)
• Option for ADF applications with proportionally many root AMs, many
users and many database connections for each user
Too many database connections
• Monitor the number of database connections in the Weblogic
Console
• set jbo.doconnectionpooling=true and
jbo.txn.disconnect_level=1
Too much logging on
• Switch to SEVERE at the WLS / EM level
Agenda
•
•
•
•
•
Why is performance so important ?
Overview typical ADF bottlenecks
What happens too slowly
What happens too often
What happens too soon
Executed too soon (1)
• Example: af:panelTabbed component with in each af:
showDetailItem an af:region that starts a taskflow execution
Executed too soon (2)
.jsff page:
PageDefinition:
Executed too soon (3)
• Use childCreation="lazyUncached“ or childCreation="lazy“ to defer
taskflow execution of all tabs until the tab is opened
• For popups, use childCreation="deferred”
• For tasklows in regions, use activation="conditional" and a
RefreshCondition on the taskflow executable
Instantiated too soon
• Defer the runtime instantiation of ViewObject and nested
ApplicationModule instances until the time they are used
Loaded too soon
Immediate versus lazy
Important to consider for the following components:
•
•
•
•
af:table, af:treeTable, af:tree
af:popup
af:menu
dvt<xxx> (graphs)
• Lazy delivery should be used for tables, or other stamped components,
which are known to have a slow fetch time (when they show many
records, or the query is slow)
Design your pages smart
• Do not display too much data on a page, keep your page design simple if
possible
• Some organizations do still have old browsers (IE7) that can handle
limited amounts of HTML and JavaScript
• Do not unnecessarily query data that is not immediately needed
(unopened tree nodes, inactive tabs, invisible popups, unopened
dropdown lists, etc.)
Example bad practice
ADF10g app
30%
15%
5%
35%
?
15%
Agenda
•
•
•
•
•
•
Why is performance so important ?
Overview typical ADF bottlenecks
What happens too slowly
What happens too often
What happens too soon
Too little
Too little Caching
•
Use a shared application module to group view instances when you want to reuse lists of static data across the application
•
Use application scope for application scope managed beans
Too little JVM Heap size
Recommended by Duncan Mills:
• Set (–Xms–Xmx) as large as possible within available physical memory
• Generational parallel garbage collection strategy is recommended to
maximize throughput: -Xgc:genpar (JRockit)
Agenda
•
•
•
•
•
•
•
Why is performance so important ?
Overview typical ADF bottlenecks
What happens too slowly
What happens too often
What happens too soon
Too little
Too big
Too big scope for managed beans
• Use as small memory scopes as possible
Too much table rows to browser
• fetchsize on af:table, af:treeTable and af:tree
components defines the number of rows
sent to the browser
• Should be (and is default) the same as
the iterator rangesize in the pageDef
• Bad practice: setting a high fetchsize
on af:table, af:treeTable or af:tree component.
As a result, the browser gets a big http response and
has to build up a very big DOM tree
(example: 3,9 MB http response (!) )
Too much HTML to the browser (1)
Make IDs of the following ADF faces container components as
small as possible (max 2 characters):
•
•
•
•
•
•
•
af:pageTemplate
af:region
af:panelCollection
af:table
af:treetable
af:tree
af:iterator
Too much HTML to the browser (2)
• Monitor HTTP traffic in browser (for example firebug)
• Look for big files
HTML
Too much HTML to the browser (3)
• Make the container component IDs as small as possible, for example:
<af:pageTemplate id="t“ >
<af:panelCollection id="c“ >
<af:treeTable id=”utt” >
<af:region id="r4“ >
HTML
Summary ADF Performance Tips
1. Smart application design - do not unnecessarily query data that is not
immediately needed (unopened tree nodes, inactive tabs, invisible popups,
unopened dropdown lists, etc.)
2. Query resource intensive data only on demand (BLOBS, CLOBS, etc.)
3. Detect and avoid multiple unnecessary ViewObject query executions
4. Detect and tune ViewObject slow queries
5. Set efficient ViewObject fetchsizes
6. Set efficient PageDefinition Iterator rangesizes
7. Use partialSubmit=true and immediate = true where possible on:
af:commandButton, af:commandImageLink, af:commandLink,
af:commandMenuItem, af:commandNavigationItem,
af:commandToolbarButton.
8. If you are working with more than 500 records in tables, set the ViewObject
property accessmode to ‘Range paging’
9. Make IDs of ADF faces container components (af:pageTemplate, af:region,
af:panelCollection, af:table, af:treetable, af:tree) as small as possible
10. Learn about (and try out) the most efficient Application Module pooling
settings for your specific situation
ADF Performance Monitor
Resources
•
•
•
•
Fusion Middleware Performance and tuning guide
AMIS technology blog
Blogs by Duncan Mills
Blogs by Andrejus Baranovskis
Download