I have an ecommerce website wherein as soon as a new user comes on website then a new visitorId gets generated for that user in database and that visitorId cookie gets stored in his browser and in memory session of server. In his subsequent journey over the website we use this visitorId to map and store any information associated with this user like products added by him in cart, products he has browsed etc. Having this visitorId thus becomes important.

Now I am working on improving initial website load time for user and in this process I find this database query which inserts record for a new user consumes some time. And by using different strategy I can either cut down or reduce this time consumed. Although it's not a lot of time, but still it's a overhead.

Please suggest some strategy that could be used to handle this functionality in a better fashion.

Current Setup

  • Java App based on Spring & Hibernate
  • MySQL server
  • Hosted on AWS using RDS, ELB, EC2
  • I'm voting to close, unfortunately. This question is lacking in detail: What you're doing is completely normal. You might have some inefficient queries in the mix, or you might be fetching more data than is required ... or maybe your schema is artificially fragmented or something. Maybe introducing client-side state is a solution; maybe not. How would we know!? Both the "session" and "visitor" concepts are conceptually very normal. How big of a hit from this functionality are you seeing? How/When does this session data get summoned up? What kind of infrastructure is behind this? Etc. – svidgen Oct 1 '19 at 21:06
  • I big to differ that. Yes I agree that what I am doing is normal hence I haven't divulged more details. I am not asking question, how can I optimize my existing setup. Instead, I am interesting in knowing if there is any alternate concept exists which I am not aware of – Abhishek Sharma Oct 2 '19 at 3:24
  • A notable "alternative concept" is JWT's, as BerinLoritsh suggested in his answer. But, you told him it didn't answer your question ... Hence, my VTC remains: This question is ambiguous, unclear, and open-ended. Please add details and focus it. E.g., your comment on Berin's answer implies that you have measured some DB transaction times and believe they can be improved. That's good! Maybe start by showing us your measurements, and some code, and a schema, and asking us directly if you're overlooking some obvious bottleneck. – svidgen Oct 2 '19 at 14:11
  • Have you considered (1) inserting said records asynchronously, while a response is already being served to the customer? (2) Inserting the records into something like Redis, or Memcached, or an in-process cache on the worker JVM, and streaming it to MySQL for persistence? You don't have to wait for that insert to complete, unless it's a checkout flow. – 9000 Oct 2 '19 at 16:43
  • @9000 This idea is rushing in my mind eversince I posted this question. Store new user in memory and not persist in DB unless he do some action that need to be strictly tracked. My app is not big nor huge traffic, so I believe I can be fine with JVM memory. Do you think there is some additional benefit of using Redis/memcached for this instead of my own in memory implementation? (I already have ELB with sticky session to user respective EC2 server) – Abhishek Sharma Oct 2 '19 at 17:16

If you already are using Redis or Memcahed for caching something in your app, you can use it. If you have a large number of workers, having a common cache would improve the hit rate when looking up that info. For 1-2 worker nodes, I'd just go with a ConcurrentHashMap derivative shared by worker threads.

Yet another thread could watch a local queue for same updates and persist its contents to MySQL when it has time. Please note that the queue should be limited by size (to prevent OOM exceptions), but can be quite large to handle spikes. You need to handle a situation when posting to the queue from the page handler is impossible, likely by just skipping it.

A cache miss on lookup would hit the MySQL and put the record into the cache, quite standard.

You need to think what would be a good caching key. I may be user ID or not; think about what would constitute a cache miss. The PK from MySQL is likely the right set of fields for the cache key.

Page-serving threads could just post the update to the cache and to the queue (both trivial and non-blocking) and go on with serving the page. I used such a setup quite successfully.

  • This is a lot of complexity for a problem we don't have any real information about yet ... How many applications that you have built require this two-layered approach for session data? ... How many applications have you built where the process of pulling a session object out of database (or Redis or Memcache) once per request isn't a negligible overhead? (In cases where you weren't unwittingly doing something insane like storing megs of stuff in your "session".) – svidgen Oct 3 '19 at 13:22
  • @svidgen: (1) The OP clearly states that storing the data in the one-layered approach is something known to slow down things. (2) Two-layered approach to session data is not a necessity, but an option; just doing the writes in another thread may be enough. (3) If not for session data, I've definitely built applications involving all these things (local and distributed caches, queues for eventual synchronization), and the approach changed performance figures enormously. – 9000 Oct 3 '19 at 17:29
  • I'm just a little baffled, to be honest. Most session management solutions I've used load the session from a DB up front or on-first-demand, store it back at the end of the request, and are a completely negligible portion of request processing. Well -- and you know, for requests that don't need the session, don't touch the session, lest you have a single client contending with itself over a session object. ... Other than that, What are you all doing with your sessions objects that make it so heavy!? (And if you're introducing something like memcache, why not just use memcache?) – svidgen Oct 3 '19 at 20:43

Having session information in memory is a problem for scalability. As long as you do that, you need to ensure users are routed to the same server every request, or that the session information is stored in a database.

One of the major reasons that Single Page Applications (SPA) has garnered support is that you can now keep all the application state in the user's browser. All that is required is to pass a token (commonly JWT) that encodes the user identity and roles/permissions that they have. When you do that, then you can get rid of server side state, which in turn helps the scalability of your application:

  • No server state means you don't need complex routing rules in your load balancer
  • Adding capacity is as simple as spinning up a new server and having your load balancer route traffic there.
  • Thanks Berin but it didn't answer my question about how can I cut down on time to create an entry in DB for a new user – Abhishek Sharma Oct 2 '19 at 3:32
  • Using a token for auth, you still need to track sessions, but now the invalidated tokens of logged-out sessions, if you want logout functionality at all. Unless your sessions are very short-lived (the case JWT is intended for), it may be a worse problem. – 9000 Oct 2 '19 at 16:37
  • Using a token allows you to manage the session on the client. There are several ways of managing the token. Particularly since JWT supports expiration dates. Bottom line is that server side in-memory session management is going to kill your scalability. I don't know how scalable you have to be though. – Berin Loritsch Oct 2 '19 at 16:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.