I've seen lots of examples of using things like Netflix's #HystrixCommand on service methods, but is it possible to enable a circuit breaker when using one or more CacheManager instances? In other words, bypass the Spring cache if the underlying service is unavailable or unstable over time.
Specifically, in our usage of Spring Cache, we simply have a method annotated with #Cacheable. Typically with a circuit breaker you specify a fallback, but our fallback is "Dont' use the cache, just execute our method normally". How would we implement that with annotations? Do we need to refactor our code to separate the CacheManager calls?
I think you should write a custom cache manager and write the circuit breaker logic there.
#Component
public CacheManager CustomCacheManager implements CacheManager {
#Override
public Cache getCache(String s) {
return null;
}
#Override
public Collection<String> getCacheNames() {
return null;
}
}
Related
Is it possible to perform an action before a jms message is received in spring boot? I know I could put it at the very top of my #JmsListener, but I have several listeners and I'd prefer avoiding adding a call to all of them.
I'm trying to use the logging MDC (a threadlocal, if you're not familiar with the MDC,) to track various things and I'd like to set some properties before beginning to process the message. I can do this on my controllers with a Filter, but does spring jms have the same concept?
I would try to start with an Before or Around (in case there should be some logic implemented after handling message as well) aspect:
#Before("#annotation(JmsListener)")
public void handle(ProceedingJoinPoint joinPoint) { ... }
#Around("#annotation(JmsListener)")
public void handle(ProceedingJoinPoint joinPoint) { ... }
Couple of links: enabling aspectj support, before advice, around advice.
In our Spring Boot application (2.0.4.RELEASE), we use Zipkin to integrate distributed tracing.
When creating the integration manually with a 10% sampling rate, meaning with a #Configuration like this:
#Configuration
public class ZipkinConfiguration {
#Value("${grpc.zipkin.endpoint:}")
private String zipkinEndpoint;
#Bean
public SpanCustomizer currentSpanCustomizer(Tracing tracing) {
return CurrentSpanCustomizer.create(tracing);
}
#Bean
public Tracing tracing(#Value("${spring.application.name}") String serviceName) {
return Tracing.newBuilder().localServiceName(serviceName).spanReporter(spanReporter()).build();
}
private Reporter<Span> spanReporter() {
return AsyncReporter.create(sender());
}
private Sender sender() {
return OkHttpSender.create(zipkinEndpoint);
}
}
our application has a 50 percentile performance of about 19ms and a 99.9 percentile of about 90ms at around 10 requests per second.
When integrating Sleuth 2.0.2.RELEASE instead like this in gradle:
compile "org.springframework.cloud:spring-cloud-starter-sleuth:2.0.2.RELEASE"
compile "org.springframework.cloud:spring-cloud-sleuth-zipkin:2.0.2.RELEASE"
the performance drops massively to a p50 of 49ms and a p999 of 120ms.
I tried disabling the different parts of the Sleuth integration (spring.sleuth.async.enabled, spring.sleuth.reactor.enabled, etc.).
Disabling all these integrations brings the performance to p50: 25ms, p999: 103 ms. Just having Sleuth adds about 15-25% of overhead.
It turns out that the one thing with the significant impact is setting spring.sleuth.log.slf4j.enabled to false. If all other integrations are enabled, but this is disabled, the performance stays within the Sleuth overhead mentioned above, although nothing is logged.
So my question is:
Is there a way to avoid the overhead by Sleuth (compared to "manual" tracing) and especially the one done by the SLF4J integration?
The option is to disable Slf4j integration as you mentioned. When a new span / scope is created, we go through Slf4j to put data in MDC and it takes time unfortunately. Disabling that will save it.
This might be a repeat but i couldn't find suitable post myself.
My question is, how does it really work (how the spring/hibernate support) to manage a single transaction with multiple DAO classes?
Does it really mean that same JDBC connection is used across multiple DAOs that are participating in a transaction? I would like to understand the fundamentals here.
Thanks in advance
Harinath
Using a simple example:
#Controller
#Transactional
#RequestMapping("/")
public class HomeController {
#Inject
private UserRepository userRepository;
#Inject
private TagRepository tagRepository;
...
#RequestMapping(value = "/user/{user_id}", method = RequestMethod.POST)
public #ResponseBody void operationX(#PathVariable("user_id") long userId) {
User user = userRepository.findById(userId);
List<Tags> tags = tagRepository.findTagsByUser(user);
...
}
...
}
In this example your controller has the overarching transaction, thus the entity manager will keep track of all operations in this operationX method and commit the transaction at the end of the method. Spring's #Transactional annotation creates a proxy for the annotated class which wraps it's methods in a transaction when called. It achieves this through the use of AOP.
Regarding the connection to the database - it is generally obtained from a connection pool and uses the connection for the duration of the transaction, whereafter it returns it to the connection pool. Similar question answered here: Does the Spring transaction manager bind a connection to a thread?
EDIT:
Furthermore, for the duration of the transaction, the connection is bound to the thread. In subsequent database operations, the connection is obtained every time by getting the connection mapped to the thread in question. I believe the TransactionSynchronizationManager is responsible for doing this. The docs of which you can find here: TransactionSynchronizationManager
I am looking to retrofit our existing transaction API to use Spring’s PlatformTransactionManager, such that Spring will manage our transactions. I chained my DataSources as follows:
DataSourceTransactionManager - > LazyConnectionDataSourceProxy - > dbcp.PoolingDataSource - > OracleDataSource
In experimenting with the DataSourceTransactionManager , I have found that where PROPAGATION_REQUIRES_NEW is used, it seems that Spring’s transaction management requires that the transactions be committed/rolled back in LIFO fashion, i.e. you must commit/rollback the most recently created transactions first.
Example:
#Test
public void testSpringTxns() {
// start a new txn
TransactionStatus txnAStatus = dataSourceTxnManager.getTransaction(propagationRequiresNewDefinition); // specifies PROPAGATION_REQUIRES_NEW
Connection connectionA = DataSourceUtils.getConnection(dataSourceTxnManager.getDataSource());
// start another new txn
TransactionStatus txnBStatus = dataSourceTxnManager.getTransaction(propagationRequiresNewDefinition);
Connection connectionB = DataSourceUtils.getConnection(dataSourceTxnManager.getDataSource());
assertNotSame(connectionA, connectionB);
try {
//... do stuff using connectionA
//... do other stuff using connectionB
} finally {
dataSourceTxnManager.commit(txnAStatus);
dataSourceTxnManager.commit(txnBStatus); // results in java.lang.IllegalStateException: Cannot deactivate transaction synchronization - not active
}
}
Sadly, this doesn’t fit at all well with our current transaction API which allows you to create transactions, represented by Java objects, and commit them in any order.
My question:
Am I right in thinking that this LIFO behaviour is fundamental to Spring’s transaction management (even for completely separate transactions)? Or is there a way to tweak its behaviour such that the above test will pass?
I know the proper way would be to use annotations, AOP, etc. but at present our code is not Spring-managed, so it is not really an option for us.
Thanks!
yes,I have met the same problems below when using spring:
java.lang.IllegalStateException: Cannot deactivate transaction synchronization - not active.
According above,Spring’s transaction management requires that the transactions be committed/rolled back in LIFO fashion(stack behavior).The problem disappear.
thanks.
Yes, I found this same behavior in my own application. Only one transaction is "active" at a time, and when you commit/rollback the current transaction, the next active transaction is the next most recently started transaction (LIFO/stack behavior). I wasn't able to find any way to control this, it seems to be built into the Spring Framework.
I have a spring MVC rest service that returns data in XML. I would like to cache this xml response. How can I achieve this? Is it possible to do this using mvc:interceptors?
You could make this work, but I think there are better solutions.
First, if you want to use Spring MVC interceptors, you'll use the postHandle method to store something in your cache and the preHandle to check the cache and possible circumvent processing. The question is, what do you store in the cache. You would need to store the complete response. This means that you would have to easily get the full response from your ModelAndView in postHandle. This may or may not be easy, depending on how you're doing things.
You're most likely better off using a different caching mechanism all together. I recommend caching at the web server level. This is especially true if you're looking to cache in the interceptor level as that is right "next" to the web server and I don't see any benefit in re-inventing the wheel there. Apache has a cache module. So does nginx. Varnish is pretty awesome too.
I should also mention that you should not cache until you've determined that you need to (don't prematurely optimize). This is a waste of your time and effort. Secondly, when you've determined that you do have performance issues that need to be fixed (and caching is the correct solution), you should cache the right data in the right place.
Now, say you've determined that you do have a performance problem and some sort of caching is a good solution. The next thing to determine is what can be cached. If, for every URL, you return the same data, then caching at the web server (Apache, nginx, Varnish, etc.) level will be your best bet.
Often, you will have cases where two clients will hit the same URL and get different data. This is most easily seen on a site like Facebook. I see different data when I'm logged in than my friend sees. In this case, you will not be able to cache at the web server level. You will need to cache inside your application. Usually this means caching at the database level.
I couldn't disagree with the optimization part of the solution more.
Web requests are inherently slow as you're loading data from a remote location, possibly a few thousand miles away. Each call must suffer a full TCP round-trip time for at least the packets themselves, possibly the connect and fin for each request, which for connect is a three packet synchronous exchange before you start to transfer data.
US coast-to-coast latency is about 50ms on a good day, so every connection suffers a 150ms penalty, which for most implementations is incurred for every request.
Caching the response on the client-side removes this latency entirely, and if the service has correct headers on their response, is trivial. If they don't, you'll have to define a caching policy, which for the most part isn't particularly difficult. Most API calls are either real-time or not.
In my opinion, caching REST responses isn't premature optimization, it's common sense.
Don't use spring cache it is not what you need. You need to reduce load to your Server, not speed up your inner spring application execution.
Try use som HTTP-related caching strategies.
You can add one of HTTP-headers to your requests
#cache expires in 3600 seconds
cache-control: private, max-age=3600
#hash of your content
ETag: "e6811cdbcedf972c5e8105a89f637d39-gzip"
# redirect caching to any HTTP header
vary: User-Agent
Detailed description of caching techniques
Spring example
#RequestMapping (value = "/resource/1.pdf", produces = "application/octet-stream")
public ResponseEntity<InputStreamResource> getAttachement (#RequestParam (value = "id") Long fileId)
{
InputStreamResource isr = new InputStreamResource(javaInputStream);
HttpHeaders headers = new HttpHeaders();
//other headers
headers.setCacheControl("private, max-age=3600");
return new ResponseEntity<>(irs, headers, HttpStatus.OK);
}
I use this and it works with awesome speed.
Really easy to use spring + ehcache:
1)Controller:
#Cacheable("my.json")
#RequestMapping("/rest/list.json")
public ResponseEntity list(#RequestParam(value = "page", defaultValue = "0", required = false)
int pageNum,
#RequestParam(value = "search", required = false)
String search) throws IOException {
...
}
2) At ehcache.xml some like this:
<cache name="my.json" maxElementsInMemory="10000" eternal="true" overflowToDisk="false"/>
3) Configure spring. I'm using spring javaconf style:
#Configuration
#EnableCaching
public class ApplicationConfiguration {
#Bean
public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() throws MalformedURLException {
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("ehcache.xml"));
return ehCacheManagerFactoryBean;
}
#Bean
#Autowired
public EhCacheCacheManager cacheManager(EhCacheManagerFactoryBean ehcache) {
EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager();
ehCacheCacheManager.setCacheManager(ehcache.getObject());
return ehCacheCacheManager;
}
}
At the application level, I would go with a plain Java cache as EHCache. EHCache is pretty easy to integrate with methods on Spring beans. You could annotate your service methods as #Cacheable and it's done. Check it out at EHCache Spring Annotations.
At the HTTP level, Spring MVC provides a useful ETag filter. But I think it would be better if you could configure this kind of caching at the server level more than at app level.
As of Spring 3.1, you can use the #Cachable annotation. There is also support for conditional caching, and some sibling annotations like #CachePut, #CacheEvict and #Caching for more fine grained control.
Spring currently supports two different cache managers, one that is backed by a ConcurrentHashMap and one that is backed by Ehcache.
Lastly, don't forget to read the details about how to enable the annotations.