Client-side vs server-side caching

DrJohnZoidberg

Honorary Master
Joined
Jul 24, 2006
Messages
27,997
Reaction score
7,455
Location
Table View
I'm building a custom website for our business which displays all our reporting in a nice graphical way using graphs and tables.

Everything is done with PHP and Javascript/jQuery and using MySQL for the database.

The thing is the site is being hosted locally at our office but I have also made it available to the outside and a few users will be accessing it internationally. Our office internet is pretty crap (we only have 4Mbit ADSL, so upload speed is slow) and we already have a bunch of other web services competing for the bandwidth.

I've already written a client-side caching function using javascript which stores data requests in the browsers session storage. The only issue here obviously is that once the session is killed the data must be retrieved again, MySQL queries need to be called, etc. Also it is only stored for that users browser and anyone else accessing it will obviously have to generate their own cache each time.

So basically I'm trying to decide whether I should leave it as is or use server-side caching. On the one side I want to reduce the amount of calls to the database but also with limited bandwidth I would like to limit the data requests from the server.

Which option would you chose in this scenario? If you think I should go server-side do you have any tips/resources where I might start with this?

Note that I'm not using any framework, although I have looked in to using something like Phalcon or Laravel but I don't have time to rewrite the entire project right now.


Here is the code for my client-side caching, maybe it's useful to someone else and maybe you could help me optimise it too and point out any issues :)

Everytime the page needs to display data I first use getCache() to see if the data is cached and if it's not then I retrieve the data from the server and use setCache() to store it.

Code:
if(sessionStorage === null) console.log("Storage not supported by the browser");

//cached object
var temp = sessionStorage.getItem('cacheObj');
var cacheObj = $.parseJSON(temp);

if (cacheObj === null) {
    var cacheObj = new Object();
}

function setCache(postId, postData) {
    
    if (cacheObj.length > 0) {
        
        var objectExists = false;
        
        var milliseconds = new Date().getTime();
        
        //check if we already have this data stored and is current
        for (var i = 0; i < cacheObj.length; i++) {
            if (cacheObj[i].postId === postId) {
                objectExists = true;
            }
        }
        // add the data to the object if it's not there already
        if (!objectExists) {
            cacheObj.push( { postId: postId, data: postData, timestamp: milliseconds } );
            sessionStorage.setItem('cacheObj', JSON.stringify(cacheObj));
        }
    } else {        
        cacheObj =  [ { postId: postId, data: postData, timestamp: milliseconds } ];
        sessionStorage.setItem('cacheObj', JSON.stringify(cacheObj));
    }

};

function getCache(postId) {
    
    var milliseconds = new Date().getTime();
    var validityMilliseconds = 60000*60*1; // 1 hour
    //var validityMilliseconds = 30000; // 30 seconds
    
    if (cacheObj.length > 0) {
        for (var i = 0; i < cacheObj.length; i++) {
            if (cacheObj[i].postId === postId) {
                if (milliseconds < (cacheObj[i].timestamp + validityMilliseconds)) {
                    return cacheObj[i].data;
                } else {
                    console.log('Object expired, destroying.');
                    cacheObj.splice(i, 1);
                }
            }
        }
    }
    return false;
};
 
Can you not do both?

Excellent point, now why didn't I think of that :D

Do you know the best way I should approach the server-side problem? I'm guessing it would most efficient to use a MySQL table with the most recently stored cache?
 
Store recently enquired objects in a caching store like memcache or redis, we use redis as our middle layer between various data itensive tasks. We then have various jobs that will background the caches when new data becomes available, we wrote an internal push notification platform to prompt the cache to update.

If database hits are not an issue for you then you can use the table, but that is not really caching.

Also you can move the storage of items out from the session and into local storage. Not sure what browsers you guys use, but we restrict access to our platform, only chrome allowed.
 
Store recently enquired objects in a caching store like memcache or redis, we use redis as our middle layer between various data itensive tasks. We then have various jobs that will background the caches when new data becomes available, we wrote an internal push notification platform to prompt the cache to update.

If database hits are not an issue for you then you can use the table, but that is not really caching.

Also you can move the storage of items out from the session and into local storage. Not sure what browsers you guys use, but we restrict access to our platform, only chrome allowed.

Thanks, I will look into those. I guess it's a lot better to rather store items in memory, just don't want to have to rerun intensive queries on the db side though.

That is a premature way of caching items. Caches need to be invalidated and served with fresh new items if something changes.

Yes, this something I ran into. This is why I decided to just invalidate the cache after an hour, although it's not really a great solution.
 
so. As long as you're able to push updates down to the browser and store locally you can still do both. We use signalr to update the browsers cache when needed but also caching server side so all new requests get the cached data

So you resend every single item? Or do you only send items that do not appear in the browsers cache?
 
Only the items that have changed since the browser session started or last updated...

its a bit more complex because deciding when to push is tricky. if something important happens then we push regardless of the time since last update.. or it happens on a schedule or if a threshold is reached.. say x amount of changes or whatever
 
Thanks, I will look into those. I guess it's a lot better to rather store items in memory, just don't want to have to rerun intensive queries on the db side though.



Yes, this something I ran into. This is why I decided to just invalidate the cache after an hour, although it's not really a great solution.

Yeah, most of our keys in redis have a ttl of about 12 hours. Which runs in accordance with our working hours. But this key is updated constantly throughout the day. It reduced load times on our web platform from 30seconds to about 3 seconds.
 
Only the items that have changed since the browser session started or last updated...

its a bit more complex because deciding when to push is tricky. if something important happens then we push regardless of the time since last update.. or it happens on a schedule or if a threshold is reached.. say x amount of changes or whatever

Cool, i had never ending **** with signalr, so dropped it like a hot potato. Started buckling under the rate of our messaging platform.
 
It's the bomb when it works and radioactive waste when it doesn't... debugging it is a pain lol

Yep i reported a few bugs on it, took them like months to fix. Now i wasnt paying for the service so didnt expect them to reply the next day type thing. Eventually just went with what i know well, faye/socket.io and raw websocket js impl.
 
Why are you hosting these applications on your local network? Dedicated and VPS servers are so cheap now it surely doesn't make any sense to host these sites on a server sitting in your office.
 
played around a bit with websockets and localStorage.

@OP, from what I read the users do not necessarily modify data on their side, your site is more for displaying current data. So in that case:
1. As sp4ceman said, store sessionStorage in localStorage, and update by latest timestamp or some other worthwhile metric.
2. websockets are addictive. lower latency and (I may be wrong but ) less data usage than ajax. As soon as something is updated server side, you can push it to all connected clients. Socket.io is simple to understand, and provides fallback to ajax/long-polling (although caniuse says 74% supports WS). You'll probably run it on nodejs so there's a redis driver if you go with semaphore's excellent idea.
3. webrtc. highly experimental. Essentially is websockets, but instead of a central server which is necessary for websockets, its p2p in nature. So idea is send to one client, and that sends on to the next, which sends to next, etc. Fun to play with, don't know if its worth the effort for your app though. But if your app is more for educational purposes have a look.
 
Why are you hosting these applications on your local network? Dedicated and VPS servers are so cheap now it surely doesn't make any sense to host these sites on a server sitting in your office.

The majority of the usage for now will come from users on the company intranet, I will relook this at a later time though. There are also a bunch of automation systems running that take incoming mails from our mail server, extract the attachments and import these reports into the database.
 
played around a bit with websockets and localStorage.

@OP, from what I read the users do not necessarily modify data on their side, your site is more for displaying current data. So in that case:
1. As sp4ceman said, store sessionStorage in localStorage, and update by latest timestamp or some other worthwhile metric.
2. websockets are addictive. lower latency and (I may be wrong but ) less data usage than ajax. As soon as something is updated server side, you can push it to all connected clients. Socket.io is simple to understand, and provides fallback to ajax/long-polling (although caniuse says 74% supports WS). You'll probably run it on nodejs so there's a redis driver if you go with semaphore's excellent idea.
3. webrtc. highly experimental. Essentially is websockets, but instead of a central server which is necessary for websockets, its p2p in nature. So idea is send to one client, and that sends on to the next, which sends to next, etc. Fun to play with, don't know if its worth the effort for your app though. But if your app is more for educational purposes have a look.

Thanks for taking the time to reply here. I haven't had time this week to work on anything, will take a look at some of the ideas from this thread next week.
 
what is wrong with the existing solutions for this? server side caching + etags?

there is probably a memcached implementation where you can do the equivalent in php

Code:
@Cachable("somethings")
function Something getSomething() {
  return db.query(SOME_SQL, new SomethingRowMapper());
}

Then add a shallow etag filter to your request chain.
 
Last edited:
Top
Sign up to the MyBroadband newsletter
X