We are building a Spring-MVC web application for 80 000 users.
I see a lot of controllers in the petclinic example using :
#SessionAttribute annotation and
SessionStatus status ... status.setComplete() to store and remove the beans from the HTTP Session. Very useful indeed.
Is it the best way to go if you plan to build an application for 80 000 users ?
Could you still use session load balancing and session failover if you plan to store all your form data like this ?
It will probably not meet your needs, no. There are two principle problems with the built in implementation:
It doesn't really support tabbed browsing. If a user loads the same screen in multiple browser tabs, the two tabs accessing one controller are going to clobber each other's session attribute data.
If users don't follow your "planned" navigation path that setComplete() call will get missed and the object hang around indefinitely until the session expires and is cleaned up.
Number 1 may or may not be a concern depending on how your app is designed and what it does. (some things, e.g., Banks, deliberately thwart mult-tabbed usage anyway) But most users I think would expect to be able to edit User A's profile in one tab and User B's profile in another tab and not have submitting one form break the other screen.
Number 2 you could work around by always submitting a screen into its own controller then redirecting after cleanup, but that's a lot of work if you aren't already building that way.
The good news is org.springframework.web.bind.support.SessionAttributeStore is a recognized extension point! You can provide any implementation of that you like and inject it in your dispatcher servlet. You don't even need to use the Web Session to store information if you want to avoid bloating it up with business objects. You could put that actual storage in a backend terracotta cluster for example, and not worry about it being compatible with your clustering strategy.
--
And then there's always option Gamma if you really need true scalability: rework it into a RESTful strategy that doesn't rely serverside state in the first place :)
Related
We have 13 years old monolithic java application using
Struts 2 for handling UI calls
JDBC/Spring JDBC Template for db calls
Spring DI
Tiles/JSP/Jquery for UI
Two deployables are created out of this single source code.
WAR for online application
JAR for running back-end jobs
The current UI is pretty old. Our goal is to redesign the application using microservices. We have identified modules which can run as separate microservice.
We have following questions in our mind
Which UI framework should we go for (Angular/React or a home grown one). Angular seems to be very slow and we need better performance as far as page loading is concerned.
Should UI/Javascript make call to backend web services directly or should there be a spring controller proxy in deployed WAR which kind of forwards UI calls to APIs. This will also help if a single UI calls requires getting/updating data from different microservice.
How should we cover microservice security aspect
Which load balancer should we go for if we want to have multiple instance of same microservice.
Since its a banking application, our organization does not allow using Elastic Search/Lucene for searching. So need suggestion for reporting using Oracle alone.
How should we run backend jobs?
There will also be a main payment microservice which will create payments. Since payments volume is huge hence it will require multiple instances. How will we manage user logged-in session. Should we go for in-memory distributed session store (may be memcache)
This is a very broad question. You need to get a consultant architect to understand your application in depth, because it is unlikely you will get meaningful in-depth answers here.
However as a rough guideline here are some brief answers:
Which UI framework should we go for (Angular/React or a home grown one). Angular seems to be very slow and we need better performance as far as page loading is concerned.
That depends on what the application actually needs to do. Angular is one of the leading frameworks, and is usually not slow at all. You might be doing something wrong (are you doing too many granular calls? is your backend slow?). React is also a strong contender, but seems to be losing popularity, although that is just a subjective opinion and could be wrong. Angular is a more feature complete framework, while React is more of a combination of tools. You would be just crazy if you think you can do a home grown one and bring it to the same maturity of these ready made tools.
Should UI/Javascript make call to backend web services directly or
should there be a spring controller proxy in deployed WAR which kind
of forwards UI calls to APIs. This will also help if a single UI calls
requires getting/updating data from different microservice.
A lot of larger microservice architectures often involve an API gateway. Then again it depends on your use case. You might also have an issue with CORS, so centralising calls through a proxy / API gateway, even if it is a simple reverse proxy (you don't need to develop it) might be a good idea.
How should we cover microservice security aspect.
Again no idea what your setup looks like. JWT is a common approach. I presume the authentication process itself uses some centralised LDAP / Exchange or similar process. Once you authenticate you can sign a token which you give to the client, which is then passed to the respective micro services in the HTTP authorization headers.
Which load balancer should we go for if we want to have multiple
instance of same microservice.
Depends on what you want. Are you deploying on a cloud based solution like AWS (in which case load balancing is provided by the infrastructure)? Are you going to deploy on a Kubernetes setup where load balancing and scaling is handled as part of its deployment fabric? Do you want client-side load balancing (comes part of Spring Cloud)?
Since its a banking application, our organization does not allow using
Elastic Search/Lucene for searching. So need suggestion for reporting
using Oracle alone.
Without knowledge of how the data on Oracle looks like and what the reporting requirements are, all solutions are possible.
How should we run backend jobs?
Depends on the infrastructure you choose. Everything is possible, from simple cron jobs, to cloud scheduling services, or integrated Java scheduling mechanisms like Quartz.
There will also be a main payment microservice which will create
payments. Since payments volume is huge hence it will require
multiple instances. How will we manage user logged-in session. Should
we go for in-memory distributed session store (may be memcache)
Not really. It will defeat the whole purpose of microservices. JWT tokens will be managed by the client's browser and expire automatically. You don't need to manage user logged-in session in such architectures.
As you have mentioned it's a banking site so security will be first priory. Here I have few suggestions for FE and BE.
FE : You better go with preactjs it's a react like library but much lighter and fast as compare to react. For ui you can go with styled components instead of using some heavy third party lib. This will also enhance performance and obviously CDNs for images and big files.
BE : As per your need you better go with hybrid solution node could be a good option.e.g. for sessions.
Setup an auth server and get you services validate user from there and it will be used in future for any kinda service .e.g. you will expose some kinda client API's.
User case for Auth : you can use redis for session info get user validated from auth server and add info to redis later check if user is logged in from redis this will reduce load from auth server. (I have used same strategy for a crypto exchange and went pretty well)
Load balancer : Don't have good familiarity with java but for node JS PM2 will do that for you not a big deal just one command and it will start multiple instances and will balance on it's own.
In case you have enormous traffic then you better go with some messaging service like rabbitmq this will reduce cost of servers by preventing you from scaling your servers.
BE Jobs : I have done that with node for extensive tasks and went quite well there you can use forking or spanning this will start a new instance for particular job and will be killed after completing it and you can easily generate logs along with that.
For further clarification I'm here :)
I have been trying to implement an "ahead-of-time" caching scheme. Essentially, I have a web app that users interact with to retrieve resources–from a cache if the resource has been requested before, and from elsewhere on a cache miss.
I would like to populate the cache ahead of time. This would look like the user providing specific parameters in the request that will kick the web app off and get it requesting resources and caching them.
The wrinkle in the problem is that if a user requests a specific resource while my web app is requesting resources and caching them, priority needs to be given to the user's request. Once the user has received the resource, the "ahead-of-time" caching should kick back in.
I'm new to servlets, and I have no idea how to make two requests talk like that. How could I "postpone" the operation of some function based off of a separate request to my web app?
I'd be happy to provide any relevant code that you all would find useful. My caching class is almost identical to the one on the JCS website.
Thanks,
Kevin
I've been tasked with making an enterprise application multi-tenant. It has a Java/Glassfish BLL using SOAP web services and a PostgreSQL backend. Each tenant has its own database, so (in my case at least) "multi-tenant" means supporting multiple databases per application server.
The current single-tenant appserver initializes a C3P0 connection pool with a connection string that it gets from a config file. My thinking is that now there will need to be one connection pool per client/database serviced by the appserver.
Once a user is logged in, I can map it to the right connection pool by looking up its tenant. My main issue is how to get this far - when a user is first logged in, the backend's User table is queried and the corresponding User object is served up. It seems I will need to know which database to use with only a username to work with.
My only decent idea is that there will need to be a "config" database - a centralized database for managing tenant information such as connection strings. The BLL can query this database for enough information to initialize the necessary connection pools. But since I only have a username to work with, it seems I would need a centralized username lookup as well, in other words a UserName table with a foreign key to the Tenant table.
This is where my design plan starts to smell, giving me doubts. Now I would have user information in two separate databases, which would need to be maintained synchronously (user additions, updates, and deletions). Additionally, usernames would now have to be globally unique, whereas before they only needed to be unique per tenant.
I strongly suspect I'm reinventing the wheel, or that there is at least a better architecture possible. I have never done this kind of thing before, nor has anyone on my team, hence our ignorance. Unfortunately the application makes little use of existing technologies (the ORM was home-rolled for example), so our path may be a hard one.
I'm asking for the following:
Criticism of my existing design plan, and suggestions for improving or reworking the architecture.
Recommendations of existing technologies that provide a solution to this issue. I'm hoping for something that can be easily plugged in late in the game, though this may be unrealistic. I've read about jspirit, but have found little information on it - any feedback on it or other frameworks will be helpful.
UPDATE: The solution has been successfully implemented and deployed, and has passed initial testing. Thanks to #mikera for his helpful and reassuring answer!
Some quick thoughts:
You will definitely need some form of shared user management index (otherwise you can't associate a client login with the right target database instance). However I would suggest making this very lightweight, and only using it for initial login. Your User object can still be pulled from the client-specific database once you have determined which database this is.
You can make the primary key [clientID, username] so that usernames don't need to be unique across clients.
Apart from this thin user index layer, I would keep the majority of the user information where it is in the client-specific databases. Refactoring this right now will probably be too disruptive, you should get the basic multi-tenant capability working first.
You will need to keep the shared index in sync with the individual client databases. But I don't think that should be too difficult. You can also "test" the synchronisation and correct any errors with an batch job, which can be run overnight or by your DBA on demand if anything ever gets out of sync. I'd treat the client databases as the master, and use this to rebuild the shared user index on demand.
Over time you can refactor towards a fully shared user management layer (and even in the end fully shared client databases if you like. But save this for a future iteration.....
In a web application based on propraietery MVC and authorization model, we have recently migrated to Spring MVC.
As part of that move, we are also looking at moving away from a locally created GUID that is passed with each request to a cookie based Session ID.
On the face of it, it looks as if in our case, doing so will be a big disadvantage as the standard JSESSION/HttpSession seems to be the root of all security evils:
Session Fixation (In existing code session is only created after succesful login, so we need never invalidate() a sessions.
CSRF - Session is never passed as a cookie so this is never a risk (and god, it's a problematic one to handle since there is no real framework or generic solution out therem checked HDIV and CSRFGuard).
Testing Useability - QA can easily have multiple users with multiple roles connecting to the same Server, not possible with JSESSION.
In consistent HTTPSession creation and invalidation in various Containers (Weblogic, JBOSS and Websphere)
Inconsistent JSession handling when moving between HTTP to HTTPS.
So, other than the obvious advantage of "being standard", Any clues as to why would I want to go the JSESSION route?
Not really a categoric answer about why you should or should not use jsession, but stil some remarks regarding your concerns:
Your application should not rely on the fact that a session exist or not. It should rely on the fact that the session is valid according to certain rules you put on it (user authenticated, roles assigned to this user, etc...)
CSRF is not really a big deal as long as you take care to not use GET for sensible actions, and as you mention Spring MVC, it is quite easy to achieve with it.
True, if you only rely on one browser. And as a side note, while manual testing remains a must for some situations, many use cases can benefit from automation, and thus reduce the impact of having to switch from a role to another.
Never encounter a problem with that. But I tried to kept the content of the session as small as possible.
And that's a good thing. It can prevent you from moving away from your secure connection without noticing it.
Now, whatever the option you'll choose, there will always be some drawbacks. Having a UUID in each request (and thus potentially in each GET URL) does not allow your users to use bookmarks easily. Nor to keep their session alive.
After much discussion analysis and testing, it seems that tleast in my case, a non RESTfull application, with a desktop like RIA UI, and extensive security considration, JSESSION is not the way to go (CSRF mainly) and a better option is a BODY based internally generated key.
This does mean though, that the application will be forced to handle timeouts and session invalidation.
Here's a scenario:
I have a java front end (RCP/SWT) app which currently has no authentication support.
I have to however, add security to this application so that it gets deployed in different enterprise envinronments. I have a few approaches which I thought I would share with you all here and take your inputs. Please note that there are no strict requirements yet, so.. I would like you to consider typical and non-typical enterprise network security models.
Approach 1
Create a 'Security' webservice that
the thick client would invoke, on startup.
The client queries the security for the current authentication mode and receives the implementation class of the authentication as a soap attachment. The class received, will not have the logic for authencation, rather it would just describe the UI and the events on the UI. (The client could make use of a GUI toolkit such as Thinlet?)
Once the class is loaded, a UI relating to the currently set authentication method is displayed to the end user.
Advantages:
This approach lets me handle different authentication schemes. For instance, if the app has to authenticate against user names and passwords stored in a database, a screen with UserName and password fields would suffice. However, say the user were to do a network logon that would involved typing in the network name, the UI would contain three fields. If the security model at the client network dictates ntlm/SSO based authentications, the user won't see a UI. This will also leave scope for future authentication methods - for instance, supporting a captcha specific logon screen/ biometric stuff / whatever.
Approach 2
KISS (Keepin in yea.., Simple)
User name and password are usually the only two credentials required by all of the known authenticating mechanisms?
Have the thick client query the webservice and let the webservice handle the entire authentication process.
I am not sure how realistic/feasible/commonly used the above mentioned approaches are. Appreciate your help.
I'd certainly not recommend transmitting class definitions as SOAP attachments. A network classloader would make more sense, but is still not needed in your situation.
Put in the client what belongs there - the UI. Have the multiple screen types ready (i.e. defined as classes) on the client and activate each of them depending on a single value passed by the server. For example if AuthenticationType.CREDENTIALS is passed, go for username/password. If Authentication.SMART_CARD is - go for smart card.
If you want to distribute the application and later implement different auth screens, then use Java Web Start. Thus all clients will be guaranteed to be running the latest version.
After knowing that your requirements impose some limitations, take a look at this network classloaders article.