7 ms·
A Complete Guide to Rails Caching
- resca79 11y agothis is a great article > The most often-used method of all Rails cache stores is fetch It's true, but I think you should add performance tests while the app write/read because the big problem of db/cache is the write that influence also the read(fetch). Another big problem is the expiration vs garbage collection after the memory is full.
- pselbert 11y agoA request with dozens or hundreds of `fetch` calls will always be slower than a few `fetch_multi` or `read_multi` calls. All of the current ActiveSupport compliant libraries support both calls.
- resca79 11y agoSure! but I mean many reads and writes load the cache db server, and the curve is exponential not linear
- ghiculescu 11y agoWe've found https://github.com/n8/multi_fetch_fragments https://github.com/n8/multi_fetch_fragments to be quite handy for this.
- rubiquity 11y ago> Why don't we cache as much as we should? An alternative question: Why do we have to cache so damn much in Ruby and complicate the hell out of our infrastructure and code? Because Ruby is slow.
- nateberkopec 11y agoWhat about caching in Ruby is complicated to you? It seems pretty simple to me. What production website doesn't cache? You make it sound like it's a Ruby-only issue.
- rubiquity 11y agoWebsites that are still fast without caching and don't need to?
- ishansharma 11y agoI'd be interested in seeings popular sites that don't use caching. Can you provide examples?
- rubiquity 11y agobleacherreport.com is on record for generating unique content on the fly per user.
- cheald 11y agoFrom the bleacherreport.com source: <!-- "breaking_news_1" background cached 07/16/2015 at 12:44 AM --> So much for that theory.
- abritinthebay 11y agoI work at Bleacher Report. We use caching. Everywhere. As much as possible. We can probably do more. Just because we end up using that cached content to create a unique mix for each user doesn't mean that we don't cache. I think you misunderstand the process.
- rubiquity 11y agoI stand corrected. This conference talk had me believe otherwise: https://www.youtube.com/watch?v=xT8vDHIvurs https://www.youtube.com/watch?v=xT8vDHIvurs
- abritinthebay 11y agoMichael's great, one of the smartest engineers I've worked with, but I don't think even he would say he meant to imply we don't use any caching at all. He's also mostly talking about our Elixir stack which is not our primary stack (though... we're hiring!). So it's a little bit of an edge case. There IS less caching involved in our Elixir stack though - due to how it functions - so maybe that's where the confusion arose.
- pselbert 11y agoEvery high traffic site leverages caching to some extent, no matter what language they run underneath. That may be varnish reverse-proxy caching, in-memory caching, fragment caching, browser caching, or most likely a combination of all of them. Caching is by no means limited to Ruby or slow languages.
- rimantas 11y agoNo, because web resources are slow. Your server may be done in 100ms, but your browser will puff for 10 more seconds till it gets all the crap by slurping it 6 pieces at a time.
- rubiquity 11y agoCaching doesn't fix browser slowness, or any type of slowness after the data it produces leaves the server. I really have no clue where you're going with this.
- derwiki 11y agoWhy is `caches_action` not considered a best practice? Using that for popular landing pages, I'm able to serve over half of my requests in < 10ms.
- nateberkopec 11y agoOh, I hope I didn't give that impression that it's no longer a "best practice". But you can, of course, accomplish exactly the same thing as an action cache with fragment caching. The cases where you can use action caching are so limited (like you said - mostly landing pages) that I feel it's hardly even worth bothering with when you can just wrap the entire view in a cache method. That's all I was trying to get across.
- gingerlime 11y agoOr `caches_page` and then it won't even hit rack / rails and can be served directly by nginx. But I agree that the usage scope is quite limited. We still use it for pages served to not-logged-in users where it makes sense, and both the performance boost and the reduction of load on the system is noticeable.
- deleted 11y ago[deleted]
- blizkreeg 11y agoDoes anyone here use compression on all of their cached content? Our Redis cache store has ballooned up to about 8G (we store a lot of html/json fragments) and is unwieldy to ship around when we want to debug bad data bugs on our dev machines. We are experimenting with lz4 compression now and the speed-compression ratio tradeoff looks pretty good with it. What has been your experience with Rails caching + compression?
- rubiquity 11y agoMemcached is probably more suited for storing html/json fragments than Redis. The Dalli[0] memcached driver does compression for you. 0 - https://github.com/mperham/dalli https://github.com/mperham/dalli
- pselbert 11y agoRedis is perfectly well suited to storing html/json fragments. It is as fast or faster, has built in clustering as of 3.0, has customizable expiration behavior, and is probably already used by your infrastructure. Most of the ActiveSupport caching compliant libraries will support optional gzip compression., Readthis certainly does. There are benchmarks on the project that illustrate the performance edge it has over Dalli as well.
- rubiquity 11y agoThe bigger problem is that because of how awesome Redis is, it tends to get used for lots of things and RAM is finite. There's lots of configurations for Redis for how it handles running out of memory and nobody looks at these until they've run out of RAM and important things start disappearing. I can't count how many Rails apps I've encountered that use Redis for all or a mix of caching, background queues, pubsub, and list operations.
- pselbert 11y agoRAM is finite whether you're using it with Redis or Memcached. Redis provides multiple databases (0-16) for just this situation. Use one db for caching, another for Sidekiq, and another for ad-hoc tasks. Redis can also be configured to evict entries with an expiration first, which means cached data will be cycled through while the important bits linger safely.
- why-el 11y ago> but usually virtualization is a mostly unnecessary step in achieving production-like behavior. Mostly, we just need to make sure we're running the Rails server in production mode. Isn't this assuming your development mode has the same memory/cpu as your production? I can't tell you how many times I get questions from clients who ask why their 16GB dev box is running fine while their 512MB dyno is slow. The point of a docker image is to limit these resources, which `rails s production` does not do.
- nateberkopec 11y agoSorry, I should have qualified that sentence: "a mostly unnecessary step in achieving production-like behavior *when trying to determine a page's average response time". That's just been my experience with this. I haven't noticed significant differences in my Macbook vs Heroku when measuring response times. It's a fast-and-loose measurement, to be sure. Virtualization/dockerization is the only way to get a super-accurate measurement.
- why-el 11y agoYeah I have been thinking about this as well. I guess it depends on how wide the difference is (when I said 512MB, I really meant it. People are still comparing that to their dev machines). Somewhat related: How has your experience been setting up docker with Rails? I have an idea for a project that seamlessly integrate docker into one's Rails dev workflow, but so far I have found its setup (let alone working with it) to be cumbersome to say the least.
- douglasfshearer 11y agoFantastic resource. No mention of HTTP caching though, which for a whole class of applications is a great way to minimise rendering time. Rails has great support[1] for etag based content expiry. [1] http://api.rubyonrails.org/classes/ActionController/ConditionalGet.html#method-i-stale-3F http://api.rubyonrails.org/classes/ActionController/Conditio...
- varmais 11y ago> Developers, by our nature, are very different from end-users. We're used to the idea that when you interact with a computer, it takes a little while for the computer to come back with an answer. I don't agree. End users are used to shitty systems which take some time to load, but we developers should know better. We should be able to recognise performance bottlenecks during the architecture design and development, also we should be able to measure the layers where optimisation is necessary and useful. And when developing web app, caching should always be in mind as one tool to improve system performance in one way or another. Otherwise fantastic piece of information.
- dmitrig01 11y agoTaking this further, as a developer, I find I have even less patience for slow loading times than a 'regular end-user'. I don't know exactly, but I assume this is because I know what goes on behind the scenes, and 99% of the time, the website is doing way more work than it really needs to in order to deliver the experience that I'm asking for.
- driverdan 11y agoThis is a great guide but it's not complete. One of the biggest problems with all of these guides is that they focus solely on view caching. As far as I can tell the Rails ecosystem completely lacks a good model / data caching system. There are a few gems that do model caching but they all have major flaws. I'd love to see a good guide on Rails data caching and gems that eliminate the mess of calls to Rails.cache.fetch.
- mperham 11y agoThis is because caching should be done as coarsely as possible. Caching views and entire pages is the common case.
- sethherr 11y agoExactly - why did page caching get removed from rails core?
- halostatue 11y agoSo what’s the best approach for caching API responses?
- karmajunkie 11y agoAn api response isn't any different from a web page insofar as infrastructure is concerned. HTTP caching is usually my first choice when I have the wherewithal to do that. [Edit: conditional responses are probably the best way to go – save the bandwidth.]
- arohner 11y agoGreat article. You should additionally measure page speed as experienced by your users, because other pesky things like network congestion, the user's browser & hardware and the speed of light all affect website performance. If you measure from every user's browser, you'll get very detailed performance info. A chart from a recent blog post of mine: https://s3.amazonaws.com/static.rasterize.com/cljs-module-blog-map.jpeg https://s3.amazonaws.com/static.rasterize.com/cljs-module-bl... Just because the page loads quickly on your laptop doesn't mean it loads quickly for everyone. I'm working on a tool to measure this stuff: https://rasterize.io/blog/speed-objections.html https://rasterize.io/blog/speed-objections.html, contact me if you're interested in early access. Contact me if you're interested in an early preview.
- drm237 11y agoIn the example where you cache the todo list and use an array of the todo item ids plus the max updated time, why is that approach better than just updating the list updated_at time whenever a child record is changed? With your approach, each todo item needs to be pulled from the db which should be slower than just checking the parent's updated at time for a cache hit.
- beefsack 11y agoI found the animated GIF next to the article to be incredibly distracting while reading. I had to remove it using the inspector to be able to get through the article.
- chrismorgan 11y ago> First, figure about 50 milliseconds for network latency (this is on desktop, latency on mobile is a whole other discussion). And outside the USA, add on another 200ms more. I, an Australian, visited the USA last year and was surprised, although I had expected it, at how much faster the Internet was. I get the general feeling that people in the USA end up much more picky about performance than their Australian counterparts, because they’re used to a result which is quite a bit faster anyway. It’s rather a pity that we as an industry don’t care more about performance, because on average we’re utterly abysmally appallingly atrocious at it. There’s simply no good reason for things to be as slow as they are.
- mosselman 11y agoDon't forget to divide the result from `ab` by `x` where `x` is the concurrency amount (`-c x`). The 'time per request' that has 'mean, across all concurrent requests' behind it is the mean of every single request. All other ms values show you the response time per single request * concurrency. So the percentile table is only interesting when you take this into account.