Java Performance Tuning
Java(TM) - see bottom of page
Our valued sponsors who help make this site possible
JProfiler: Get rid of your performance problems and memory leaks!
Training online: Concurrency, Threading, GC, Advanced Java and more ...
Tips November 2014
JProfiler
|
Get rid of your performance problems and memory leaks!
|
JProfiler
|
Get rid of your performance problems and memory leaks!
|
|
|
Back to newsletter 168 contents
https://weblogs.java.net/blog/jacksjpt/archive/2014/11/13/googles-big-question-whats-different-now
Google's Big Question: What's Different Now? (Page last updated November 2014, Added 2014-11-30, Author Jack Shirazi, Publisher java.net). Tips:
- Bandwidth limitations on mobile devices are the limiting factor in using remote storage.
- Low latency doesn't mix well with the cloud whereas high throughput works brilliantly.
- If your resource requirements are relatively constant then dedicated servers are more cost-effective than cloud provision; so consider carefully which services you run in the cloud.
- When provisioning in the cloud, you need to choose the optimal mix of multi-tenancy vs JVM isolation
- Monitor elastic cloud resources consistently, be aware of time drift across virtual machines and aim to handle instance spin-up and initialization without impacting other services or request latencies.
- The cloud is a new environment with it's own very specific challenges that need independent consideration for testing, monitoring and analysis - you can't just take the techniques you use on a server or browser or client application or mobile app and transfer those to cloud services, you actually have to use different techniques, it's a completely new environment class to add to those four: it has a server-like environment, but resource competition similar to a browser and mobile app type unpredictability of uptime.
- Optimizing for mobile devices is well understood, see previous extracted tips e.g. Matthew Carver's "Six Ways You're Using Responsive Design Wrong", Tim Hinds's "Beginner's Guide to Mobile Performance Testing", Caroline de Lacvivier's "FAQ: Testing mobile app performance", Steve Weisfeldt's "Best Practices for Load Testing Mobile Applications".
- Assume every type of network connection failure will happen: non-connectivity; connections that don't do anything (it's not really connected but doesn't tell your socket); connections that get enough bytes trickling in to prevent any timeout but so slow and with so many retries that your read goes on for hours; connections returning the data in an unexpected format; incorrect data (you must corroborate external data if you're relying on it to make a decision).
https://www.skillsmatter.com/skillscasts/5810-building-fault-tolerant-microservices
Building Fault-Tolerant Microservices (Page last updated November 2014, Added 2014-11-30, Author Christopher Batey, Publisher SkillsMatter). Tips:
- Problems you can see with distributed services include: split brains, dropped packets, slow networks, other JVMs hitting GC pauses.
- You need to be able to recreate faults to test for fault tolerance. Mock services at the communication layer using tools. Eg Vagrant wihh dropwizard lets you spin up a JVM for testing; Saboteur uses tc, iptables to simulate network issues (dropped packets, delays, ...); Wiremock launches a http service that let's you mocks http errors;
- You can't use network timeouts for SLAs, connections timeouts are done incorrectly in most services, they set connection timeouts and socket read timeouts for connections in a connection pool. But you need to: monitor the connection pool usage or you can block on used up pools; multiple small partial transfers can stop the socket read timing out; etc.
- Implement reliable timeouts by spawning a worker thread that executes the functionality and time that thread in the master thread - then if it times out, dump the worker thread. Hystrix (from netflix) is a framework which does this for you.
- The default pool size for executors (and many pools) is unbounded - this means your application can blow up under stress just from unbounded resources growing too large. Make sure your pools and queues are bounded - and either reject or block as appropriate for the component.
- Mock your pools and queue faults by setting the size to 1 with a high timeout and send in several requests - this mocks your component under stress when request load exceeds it's capacity.
- Communications are hugely unreliable - expect invalid codes, malformed data, data too large or too small, and connection failures.
- Use a monitoring tool that gathers and displays metrics, eg Graphite+Codahale. Make sure all boundaries logged and resources (pools, queues, etc) are externally monitorable.
- Try to include a request identifier that continues with the request across the system so you can monitor and investigate indivdual requests.
- If your "busy" resources are close to your "max" available resources, you are hitting a system limt - you should know when this happens.
- Fail quickly to your requestors rather than letting them hang and wait for too long response or a later failure.
- Monitor your external requests, and if they are responding badly have a temporary failover path that avoids the external request (presumably providing a reduced service) - circuit breaker pattern. This can be manually flipped or automatically with alerts. Have a "semi-open" state where you can trickle a subset of requests back to the external resource to find out when it starts being capable of full load again.
http://www.infoq.com/presentations/jvm-dynamic-optimizations
Priming Java for Speed at Market Open (Page last updated August 2014, Added 2014-11-30, Author Gil Tene, Publisher InfoQ). Tips:
- Java Just-in-time (JIT) compilation starts slow, profiles, warms up, optimizes and gets fast; and can identify if an optimization is wrong, will deoptimize and redo from the profiling and JIT. If that process happens at a critical time, your application is suddenly slower when you most need it to be fast - and it's not even your code that's causing that slowdown, it's because you're hitting code that you haven't hit before in this JVM instance.
- The compiler can cache a variable read eg
while (x.flag){...}
can become y = x.flag; while (y){...}
. If you don't want that to happen, you need to use a volatile variable.
- The compiler can eliminate writes to a variable with multiple writes to the same variable - just the last write can be done. If you don't want that to happen, you need to use a volatile variable.
- The JVM JIT compiler does speculative optimizations - which can become invalid when a new class is loaded or a new code pathway is executed if that violates the assumptions; at which point the code relevant to the assumptions but is now invalid has to revert to interpreted code before the classloading/code path can complete (this is deoptimization); it can then be speculatively re-optimized including the new class.
- Warming up your code (running code long enough to get it JIT compiled) is not necessarily sufficient, if the warmup doesn't execute the real code pathways that will ultimately happen; as when those are hit, the code will be deoptimized then re-optimized.
- -XX:+PrintCompilation will print out the JIT compilation steps, including deoptimisation steps. This is useful to work out when deoptimizations happen so you can execute warmups that avoid hitting deoptimizations when the real execution happens.
- JIT optimized code that is deoptimized and then re-optimized can still be faster than optimized code that includes all pathways, if the speculative optimization that gets deoptimizes is much faster and is hit a lot.
- Deoptimization will include disk access time if it includes classloading - that can be significant.
- Hitting an exception for the first time - especially NPEs - can cause costly deoptimizations.
http://jaxenter.com/high-performance-jvm-code-reactor-111964.html
High-performance JVM code with Reactor (Page last updated November 2014, Added 2014-11-30, Author Michael Nitschinger, Publisher jaxenter). Tips:
- A reactive system is scalable, responsive, resilient.
- Amdahl's law says the speedup you can obtain is limited by how much of your system you can parallelize. Every synchronization point limits parallelization, so you want to limit synchronization points.
- Asynchronous non-blocking message passing systems avoid synchronization so scale well.
- Resilient systems are able to continue overall processing when a node fails. Isolate failure points and try to make the system self-healing (retries, failovers, etc).
- To keep the system responsive under load, use bounded queues (as buffers) and backpressure (eg "please try again" responses); apply batching to bursts of traffic. Implicit batching (like the LMAX Disrupter approach) provides batching with no increase in latency.
http://www.informit.com/articles/article.aspx?p=2242814
Why Performance Engineering? Why Performance Engineers? (Page last updated September 2014, Added 2014-11-30, Author André B. Bondi, Publisher InformIT). Tips:
- Clearly specify performance requirements early in the software development cycle and create a performance test plan.
- Ask can the system handle: peak load; spikes in load; increases in users, data; additional functionality.
- Can you relax the SLAs while still providing acceptable performance? This is a cheeky but cost-effective way to achive performance.
- Performance engineering includes: Making sure there is performance engineering expertise; Specifying performance requirements; Planning performance measurements testing; Preparing performance measurement tools, load generation tools, and analysis and reporting tools.
- Performance engineering activities are: setting performance requirements; performance modelling; Making architecure and technology choices; Specifying design and implementation to achieve performance targets; Performance testing; Performance monitoring; Capacity management and planning.
http://www.developer.com/java/fundamentals-of-thread-safety-in-java.html
Fundamentals of Thread Safety in Java (Page last updated October 2014, Added 2014-11-30, Author Manoj Debnath, Publisher developer.com). Tips:
- Race conditions can lead to corrupt or inconsistent or inaccurate data. The canoncial example is multiple threads updating a shared counter; since the update is a two-operation read then write combination, it's easy for two threads to read the same value and both increment the counter then write the same value - hence losing one increment.
- The synchronized keyword ensures mutual exclusion: only the thread holding the lock can access the method or block at a time and other threads needing the lock must wait.
- java.util.concurrent structures (eg AtomicInteger) provide for thread-safe operations.
- Use thread pools (from the Executors service) if you need multiple threads, as that lets you reuse threads (thread creation is relatively expensive if the operation to execute on the thread is short).
- Thread pools should be shutdown when you no longer need them, otherwise you are holding on to resources that are unavailable to other objects.
- Stateless objects are thread safe. Stateful objects are usually not thread-safe unless specifically implemented that way.
Jack Shirazi
Back to newsletter 168 contents
Last Updated: 2024-09-29
Copyright © 2000-2024 Fasterj.com. All Rights Reserved.
All trademarks and registered trademarks appearing on JavaPerformanceTuning.com are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries. JavaPerformanceTuning.com is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
URL: http://www.JavaPerformanceTuning.com/news/newtips168.shtml
RSS Feed: http://www.JavaPerformanceTuning.com/newsletters.rss
Trouble with this page? Please contact us