Performance tuning your Grails apps
whoami > Colin Harrington
- Grails team at OCI
- @ColinHarrington
- harringtonc@objectcomputing.com
If a tree falls in a forest ...
does it make a sound?
and no one is around to hear it,
https://en.wikipedia.org/wiki/If_a_tree_falls_in_a_forest
Metaphysics & Quantum Mechanics
- George Berkeley asked the question
- Albert Einstein & Neils Bohr
- Bohr: "The moon does not exist if nobody is looking at it."
- How do you prove it? Prove me wrong
If your user hits a perf issue ...
does it matter to you?
and nobody reports it,
Measure
&
Monitor
Measure first philosophy
- Ask questions later
- Data > no data
User
This app is slow.
Perception burn!
May or may not report the issue (probably not)
Measurement
User X loaded the results page in 1870ms today at 4:30pm
475 records were pulled from the DB
if (user.cares()) {
if(user.canLocateSupport() && user.hasTime()) {
reportSlowness()
}
}
Perceived Performance
How your users feel is the reality that you are working with
- https://blog.marvelapp.com/a-designers-guide-to-perceived-performance/
Design & Code for your user
- https://www.fastcompany.com/1825005/how-one-second-could-cost-amazon-16-billion-sales
How One Second Could Cost Amazon $1.6 Billion In Sales
Front End
Web
Mobile
API
Javascript
Client Heavy
Webapp Performance basics:
- Originating HTTP request
- Web Page (HTML)
- Assets, js, css, images, etc.
- Javscript app loading times
- XHR (ajax) requests
- SSE, websockets etc.
Bundling & Minification
Asset Pipeline Plugin
- Asset Bundling
- Extensible Modules (Supports LESS,Handlebars,Coffeescript, Ember-Handlebars, SASS) via other modules.
- Cache Digest Names (Creates cache digested names and stores aliases in a manifest.properties)
- Js Minification
- Js SourceMap Generation
- Css Minification / Relative Path assertion
- File Encoding Support
- GZIP File Generation
- Last-Modified Header
http://plugins.grails.org/plugin/grails/asset-pipeline
Separate Client & Server
Gradle Multi-module build
- Standalone Client
- javascript project
- grunt, gulp, npm tooling, dependencies, bundling etc.
- Server Backend
- APIs
- Rich data sources
- Security measures
- Testable & flexible
Content Delivery Network
- Distributed & Built to be 'close' to clients
- Caching mechanisms
- Static assets
- Maybe root html documents?
- layered / uptime / DDOS protection
Preloading Data?
- HTTP request
- HTML Response
- Browser
- Parse HTML Document
- Load referenced resources
- Paint the page
- Load Javascript app
- Load Js dependencies
- Initialize the app
- API calls to fetch data.
Front-end analytics
- Analytics platforms
- Google Analytics
- Pingdom
- New Relic
- many, many others
Error handling
- Javascript testing!
- Unit testing style
- Browser testing
- Error tolerant UX
- Visually Responsive vs blocking
Log client side Javascript errors!
- Use a lib for your framework?
- Roll your own?
- Use a 3rd party
- Track.js
- Sentry.io
- Rollbar
- Raygun
- Web analytics platforms
Latency : Time scale
Cost
- Code Performance
- Reading from Drive
- SSD
- Rotational
- Network latency
- Same rack
- Same building
- Across the internet
Logging
Logs or it didn't happen
Quantify results
Human memory is 'lossy'
Removal of opinion
What happened surrounding
Grails uses logback
https://logback.qos.ch
-
grails-app/conf/logback.groovy or...
-
grails-app/conf/logback.xml
(can also be configured externally)
Heisenberg effect
- Observing influences performance
- log.info("Something happened")
- log.info("Something happened ${expensiveEvaluation()}")
https://en.wikipedia.org/wiki/Observer_effect_(physics)
Async Appenders
- Appenders blocking by default
- AsyncAppender delegates
- Any appender can be wrapped
- Durability vs performance
- Appenders
- File
- DB
- SMTP
- Syslog
- ...
Log Aggregation
Log Aggregation
- Centralized
- Debugging purposes
- Analyzing
- Usage/trends
- spot & diagnose errors quickly
- Handle Many types of logs
- System Logs
- Application Logs
- Load balancer logs
- Network device logs
- front-end error logs
Centralized
One place to rule them all!
Metrics
Visual representation
Proxy/Load Balancer timing Logs are a great place to start
monitor traffic, analyze outliars
1 picture == 1000 words
Add context to log statements
- Which Server
- Which thread
- CorrelationIDs
- User/client identifier
Mapped Diagnostic Context (MDC)
- https://logback.qos.ch/manual/mdc.html
- User/client identifier
- Early in the chain: Filter or Interceptor:
-
MDC.put("user", user.name)
-
Easy to search and filter
-
CorrelationID from the entry point
-
(also works if included in reactive flows)
-
Starting Point
- Access Logs
- Load balancer
- Nginx
- Tomcat access valve
Access logs
- Request timing (duration, when)
- HTTP status
- Size of the response
- Remote IP address
- Thread that processed the request
- Session ID (tomcat)
- Custom headers
Look at min/max/average response times
Historical Performance
Did the performance change over time?
Growing? at what rate?
Interceptors
- Can be used as a simple Performance monitoring tool
class MyInterceptor {
int order = HIGHEST_PRECEDENCE
boolean before() { true }
boolean after() { true }
void afterView() {
// no-op
}
}
Interceptors
- Before the controller action
- after the controller action
- after the view layer is done
class MyInterceptor {
int order = HIGHEST_PRECEDENCE
boolean before() { true }
boolean after() { true }
void afterView() {
// no-op
}
}
Profiling Tools
- New Relic
- Datadog
- Solar Winds
- YourKit Java Profiler (works great!)
- JProfiler
YourKit Java Profiler
JProfiler
Databases
SQL?
- Connection Pooling usage and settings
- SQL Logging
- Shim (wraps the client driver)
- Enable Hibernate SQL logging
- Query Logging on the actual server
* warning this can be chatty!
Enable SQL logging
logger("org.hibernate.SQL", DEBUG, ["STDOUT"], false)
logger("org.hibernate.type.descriptor.sql.BasicBinder", TRACE, ["STDOUT"], false)
environments:
local:
dataSource:
logSql: true
formatSql: true
grails-app/conf/logback.groovy
Application configuration
grails-app/conf/application.yml
Profiling in other data sources
- Mongo Profiling Level
- Redis monitoring or Slow log
- MySQL Slow Log
- Postgres logging slow queries
Slow Query
One expensive query
Usually a Complex query
1 * (Query Time + network overhead)
Many Queries
Many smaller less expensive queries
Overhead becomes important
n * (Query Time + network overhead)
GORM & Hibernate
ORMs are tough
Hibernate Session
- https://www.slideshare.net/JonasWitt1/understanding-database-transactions-and-hibernate-sessions-in-grails
Transactions
- https://www.slideshare.net/JonasWitt1/understanding-database-transactions-and-hibernate-sessions-in-grails
Hibernate Second Level Cache
- premature optimization?
- Optimize frequently used objects
Hibernate Query Cache
hasMany
Considered
Harmful
(@See Burt's talk!)
Author Example
class Author {
String name
static hasMany = [books: Book]
}
RxGORM
http://gorm.grails.org/
new Book(title:"The Stand")
.save()
.subscribe { Book it ->
println "Title = ${it.title}"
}
Book.get(id)
.subscribe { Book it ->
println "Title = ${it.title}"
}
Breaking
out of
procedural Jail
Asnyc
Promises
import static grails.async.Promises.*
def p1 = task { 2 * 2 }
def p2 = task { 4 * 4 }
def p3 = task { 8 * 8 }
assert [4,16,64] == waitAll(p1, p2, p3)
import static java.util.concurrent.TimeUnit.*
import static grails.async.Promises.*
Promise p = task {
// Long running task
}
p.onError { Throwable err ->
println "An error occured ${err.message}"
}
p.onComplete { result ->
println "Promise returned $result"
}
// block until result is called
def result = p.get()
// block for the specified time
def result = p.get(1,MINUTES)
class BookService {
List<Book> findBooks(String title) {
// implementation
}
}
import grails.async.*
class AsyncBookService {
@DelegateAsync BookService bookService
}
3rd Party API calls
- Network overhead 100ms?
- Orders of magnitude slower than code
- Beware of mixing with Long running Transactions
JVM Performance
Garbage Collection
- What type of GC?
- GC logs
- JVM monitoring tools
Visual VM
View layer
Grails Views
- http://views.grails.org/
- Statically Compiled Json Views!
@CompileStatic
Load Testing
- Jmeter (older but flexible)
- Gatling
- etc.
Connect with Us
grails.org
groovy-community.grails.org
grailsblog.objectcomputing.com
objectcomputing.com/grails
@grailsframework
@objectcomputing
Thank you for attending!
Please visit our table for giveaways
and to meet the team!
ociweb.com/grails
info@ociweb.com
Performance tuning your Grails apps
By Colin Harrington
Performance tuning your Grails apps
Gr8conf US 2017: You built it, they came - success!! What happens months or years later if your app grows and starts to slow down, grow too large or starts to be unreliable? We'll take a look at common pitfalls and their solutions, as well as take a more in-depth approach on how to address performance concerns. Whether Grails 2 or Grails 3, we'll dive into some real-world stories and cover some of the tricks and tools.
- 3,437