My program has to go through a learning step that takes around 15 mins to complete. The result of this learning is two Models stored into two public objects which will be then used in other classes. I put this learning step in the following method:
public void init()
So as to be performed at the start of the server. The problem is, every time the server reloads, it re-does the learning step. I have to wait another 15 minutes just to see the effects of a small change. I was wondering if there is a way to retain the value of some objects throughout the running of the program and the server. Here is my code:
public static Model model1;
public static Model model2;
#Override
public void init()
{
model1= readModel(source1)
model2= readModel(source2)
}
PS. I am using Servlets with JSP pages and Tomcat Server.
Make it a session- or application-scoped bean, as appropriate, and access it as a bean rather than a normal object.
As a general solution, I would suggest for you to keep the learning part and the model out of service container. Possibly a different VM / process. This way you will be able to retain the model for as long as the process is required to run, independent of the state of client process that is your tomcat.
DETAILED
You can achieve this in few steps
First, you need to migrate model preparation and caching to a different program. This program will run as a daemon and you can use Daemon by Apache to run it as a background service
Second, Assuming your daemon is up and running, your model consumer can communicate with the model VM using standard protocols. The selection of protocol depends on your exact requirements. It can be an API exposed over TCP/HTTP or RMI or anything else.
ALTERNATIVELY
As I suggested in comments, you can also dump the model binary to file system once the model is trained. Cache the model on tomcat startup. The io will be much faster than learning phase.
You could have a look here?
The Idea is either save session somewhere and put your model objects there or just use Hazelcast (overkill probably :))
Related
I am planning to use Spring State Machine to control an execution workflow. The system is expected to receive requests from multiple users and each user may be assigned to multiple workflows. My initial idea was to have one instance of SM per workflow and every time an user perform a step in the workflow, I would use its identifier to restore the machine from a persistent storage, input the new event and store the updated SM.
I've read around that initialising a SM is an expensive operation and some people recommend having a single instance of it, but "rehydrate" that instance with some data. My understanding is that this would be more effective, but I think it would become a "blocking" operation, in other words, one workflow would need to wait for the previous one to be finished/released before-hand. Since I'm newbie on this topic, can anyone shed some light on the best alternatives for my use case and perhaps pieces of code to illustrate the differences? (PS: I'm using v2.4.0)
I was first implementing the "rehydrate" mechanism because as you said, it made sense and was also used in the "persist" example of spring-statemachine.
Howewer, running performance tests against my API showed that using a single instance fails when using the StateMachine as an #Autowired Bean with the prototype scope as it is described in that example. What happens is that simultaneous requests against my API override that Statemachine Bean and the first request fails as the statemachine changes when writing back to the DB (i used redis).
So now I actually build a fresh statemachine everytime a request comes in and rehydrate that object:
public String getStatesGuest(HttpServletRequest httpServletRequest) throws Exception {
StateMachine<States, Events> stateMachine = stateMachineConfig.stateMachine();
resetStateMachineFromStore(httpServletRequest.getSession().getId(), stateMachine);
return convertToJson(buildGetStateResponse(stateMachine));
}
It still is very performant, I was testing with around 30 reqs/s and still got a median of 12ms. (Docker with 2 Cores for spring boot, 1 Core for redis).
I have a Spring application that is controlled with an API that we need to be single threaded, but I can not figure out how to accomplish this. The application is a re-factoring of an app that is single threaded. They want the same basic design for the new version, while using our new programming methods (i.e. Java, Spring, etc.) and adding extra functionality.
There is an API resource to start the application:
#RequestMapping("/start")
public String startProcess(){...}
If this gets called twice then the application will start another thread. We want to stop this from happening. But, we still want the stop API resource to work:
#RequestMapping("/stop")
public String stopProcess(){...}
The app has a typical Spring structure:
#SpringBootApplication
public class MyApplication{...}
#RestController
public class MyController{
#Autowired
private MyService myService;
...}
#Service
#Transactional
public class CarolService{
#Autowired
private MyDAO myDAO;
...}
#Repository
public class myDAO{...}
How do I make sure that there is only one instance of this application running at a time? Please Help! And, thanks in advance!
You have actually two different problems: making your API single-threaded and making sure that there is only one instance of this application running at a time.
The solution is conceptually the same: you have to synchronize on some mutex. But it's much easier to do in the first case than in the second.
To make your API single-threaded you'll need to synchronize on something. If you have just one controller, just make API methods synchronized. If you have more than one controller, you'll need to create some application scope bean, inject it in every controller and synchronize on it. In old times there was also something like SingleThreadModel, but I think it was deprecated. Haven't seen it around for a few years but I won't be surprized if Spring would have a way of setting it somehow.
Making sure that there is only one instance of this application running at a time is much harder. You basically want to prevent anybody to start several copies of the application in parallel. One of the way to achieve this is to have some central shared resource like a database. On start-up the application will try to "acquire" the mutex by creating a record in some table (which would allow at most one record). If the record was created successfully, the application starts normally, if not then fails. You'll need some mechanism to detect stale mutex record - probably as simple as saving the timestamp in the mutex record and constantly updating it via scheduled task (heartbeat).
We recently had a similar task in an application running many instances of many microservices. We needed exactly one microservice to regularly execute certain maintenance task. We solved it by synchronising over a central MongoDB database. Microservices try to acquire the mutex by creating a document in a database collection. By design, at most one document may exist in that collection and the microservice which created the document performs the regular task and removes the document at the end. The collection is configured with an automatic clean-up so if the microservice failed to remove the document for whatever reason, it will be removed automatically by the database.
I am working on a existing web based application which uses static map to store data specific to the Application .
This is my code below which is responsible to store Data inside a ConcurrentHashMap as shown below .
public class MyClass
// Class variable
private static Map<String, UserThread> usermap = new ConcurrentHashMap<String, UserThread>();
// Inside a Method
public void userData()
{
UserThread userThread= usermap.get(getLoginId());
if (userThread == null) {
userThread = new UserThread();
userThread.start();
usermap.put(getLoginId(), userThread);
}
}
The application is working fine , here my question is that , is this a valid code because can we store Data inside a static variable ?? (Here the Static ConcurrentHashMap contains data specific to the Application )
Static variables and caches of any kind should be avoided, especially in multi-threaded environments such as web-applications. There are several problems with your code:
Do you remove UserThreads from the map? How do you know when they should be removed? What if client's browser crashes? If you don't remove them you are asking for out-of-memory errors after the application is running for some time.
Using ConcurrentHashMap in the way you use it is not thread-safe, because it's possible that another thread adds a UserThread between if (userThread == null) and usermap.put(getLoginId(), userThread); . Concurent version of HashMap doesn't magically solve all problems with thread-safety as it may seem.
Spawning your own threads in a servlet container is not a good idea. There are better ways to do background tasks, but first you need to say what the thread is trying to do.
Generally using any kind of such static caches is bad idea, in any kind of application. In your case it would be much better to keep application-specific data in user's session.
With static map, you would run into the risk of memory leak unless you are sure of the life cycle of each entry added to the map, i.e. who would be adding them, how long will the entries stay there and when will they be removed so that they can be claimed during GC. Otherwise, your application will use up the memory and will start throwing OOME.
In this case, user which will log in on one machine will have the same session as on the second machine. I bet it's not a good way to do.
I had asked some time ago about Semi static field in Java application and Alessandro Santini gave me very nice solution with ThreadLocal. Check this out.
AFAIK it is according to the specification not ok to start your own thread inside a container. You are supposed to use a WorkManager for this. But the only server I know of that actually is enforcing that rule is Websphere Application server.
a static variable in principle is ok, of course if you run in an clustered environment each server will have its own instance of the static variable. This might or might not be a problem.
So technically you might be fine.
On the other hand I am really curious what you are trying to achieve with all these threads. If you start one thread per user this is an excellent attack vector for DOS attacks. I also have no idea why you would want to do something like this.
After my research and discussion here I decided I need to set the same name for threads on different JVMs which belong to the same control flow in the distributed system. Threads are created e.g. by RMI. Is it possible to set name when thread is created in that way?
There's no automatic means to transfer this info from client-to-server.
It sounds like you want/need some sort of Context object set up on the client (per-thread?) and passed as a method argument to your RMI servers. That Context object could contain not just the thread-name, but perhaps also other info like the calling process pid etc.
You'd then have to use that Context object to set thread-names etc. accordingly via Thread.setName() once it's been passed across the wire. Going forwards, you could set up context-specific info in your logging framework using this (e.g. using Log4j nested diagnostic contexts)
The use of aspects to automate this further is left as a further exercise for the reader :-)
The Thread class has a static method to setName(String). If you can have your threads, wherever they come from, running that method, you should be good to go. These guys had similar issues with Tomcat related threads.
I have a servlet, and that servlet uses a .net web service to perform some function. To do this, I created the webservice client in Netbeans using the "jax-rpc" style client.
Let's say that my service name is "Tester". Then two of the generated classes are called "Tester", and "TesterSoap".
To get a reference to the web service, I need to do this:
Tester t = new Tester_Impl();
TesterSoap tsoap = t.getTesterSoap();
To use the webservice, I can then do this:
tsoap.runTest();
My question is, since this is a servlet which gets executed many times, should I store the first two lines in static variables (so they only ever get executed once), or store them locally so that they execute everytime the servlet is executed?
Another way of asking the same question: is there a performance hit everytime the first two lines are called? (I'm testing everything locally so it's hard to measure).
Thanks...
If the default constructor and any of the initialization blocks of the Tester_Impl() class and the method getTesterSoap() doesn't do anything expensive (e.g. reading file from disk, loading data from DB, connecting a socket, etc, I however suppose it doesn't) then you don't need to worry about it.
You can consider declaring them as an instance variable of the class extending from HttpServlet. But, a big but, it is going to be shared among all HTTP requests, because there will be only one instance of the particular servlet class during whole application's lifetime. So if the Tester_Impl class is supposed to have a state, then it is a very bad idea to declare it as an instance variable. It would then be shared among all requests. With other words, it's not threadsafe. If you want to ensure threadsafety in servlets, then declare everything in the very same method block.
I would not optimize prematurely here. Test this out in as close to a production environment as you can (i. e. not on your local box) and see what the performance hit is. What I've done in the past is write a small shell script that hits my server with wget n times with a delay of k milliseconds and then measured the latency, possibly instrumenting the code with some timing or profiling myself (or with jvisualvm or some other profiling tool).
If you want to protect your design from a possible performance hit without doing the testing, you could use a factory to provide instances of the service client and then you could swap out singleton service clients for many of them whenever you feel like it.