92

I'm using memcached for some caching in my Rails 3 app through the simple Rails.cache interface and now I'd like to do some background job processing with redis and resque.

I think they're different enough to warrant using both. On heroku though, there are separate fees to use both memcached and redis. Does it make sense to use both or should I migrate to just using redis?

I like using memcached for caching because least recently used keys automatically get pushed out of the cache and I don't need the cache data to persist. Redis is mostly new to me, but I understand that it's persistent by default and that keys do not expire out of the cache automatically.

EDIT: Just wanted to be more clear with my question. I know it's feasible to use only Redis instead of both. I guess I just want to know if there are any specific disadvantages in doing so? Considering both implementation and infrastructure, are there any reasons why I shouldn't just use Redis? (I.e., is memcached faster for simple caching?) I haven't found anything definitive either way.

markquezada
  • 8,444
  • 6
  • 45
  • 52
  • 6
    For anyone else considering this: There's a [redis-store](https://github.com/jodosha/redis-store) plugin for rails that allows you to use redis as a cache store. – markquezada Nov 16 '10 at 06:11

6 Answers6

50

Assuming that migrating from memcached to redis for the caching you already do is easy enough, I'd go with redis only to keep things simple.

In redis persistence is optional, so you can use it much like memcached if that is what you want. You may even find that making your cache persistent is useful to avoid lots of cache misses after a restart. Expiry is available also - the algorithm is a bit different from memcached, but not enough to matter for most purposes - see http://redis.io/commands/expire for details.

markijbema
  • 3,985
  • 20
  • 32
Tom Clarkson
  • 16,074
  • 2
  • 43
  • 51
  • 1
    Thanks for the answer and the relevant docs. I edited my question a bit to make it more clear what I'm looking for. I didn't think about the cache persistence after a restart... that is a nice feature. (Although I'm not sure how useful it is considering I'd be using redis to go with heroku.) – markquezada Nov 16 '10 at 01:58
  • 1
    If you want to keep some some items ephemeral (fragment caching) and some items persistent in redis, do you need to create two separate redis instances? – Brian Armstrong Sep 11 '13 at 21:31
  • 1
    While we use Redis for both jobs queues and cache we run them with different configurations for specifically the reasons that @BrianArmstrong states. Cache is ephemeral so we configure it with it being fast, but it's ok to lose things in memory and drop LRU. For the queue, we really don't want to lose jobs so we configure it with persistence so that it's recoverable. – jwadsack Dec 02 '14 at 23:57
  • @jwadsack do you have a post where you show how you implemented this configuration? – Marklar Sep 28 '15 at 22:01
  • 1
    @Marklar Good idea. I do now: https://ballardhack.wordpress.com/2015/09/30/configuring-redis-for-rails-cache-ephemeral-and-resque-persistence/ – jwadsack Sep 30 '15 at 19:12
45

I'm the author of redis-store, there is no need to use directly Redis commands, just use the :expires_in option like this:

ActionController::Base.cache_store = :redis_store, :expires_in => 5.minutes

The advantage of using Redis is fastness, and with my gem, is that you already have stores for Rack::Cache, Rails.cache or I18n.

Luca Guidi
  • 1,201
  • 10
  • 10
  • Thanks for the response Luca. I'm assuming you can override :expires_in directly when you need to store something persistently? I guess the question is really about using both memcached type functionality *and* using redis as a persistent store alongside each other. – markquezada Oct 04 '11 at 21:21
  • 3
    I don't think it makes sense to have both memcached and redis alongside, since they are in the same NoSQL segment: both are a k/v store. Redis PROS: 1. faster than memcached 2. more powerful commands 3. no cache warmup needed 4. useful for solving other problems (eg. queues with Resque) CONS: 1. you need an external gem 2. after a restart, the server doesn't accepts commands while reading data from append file Memcached PROS: baked in Rails CONS: 1. slower than Redis 2. cache warmup. – Luca Guidi Oct 06 '11 at 13:53
  • 3
    @LucaGuidi I'm presently using RedisStore for my Rails cache. I can't figure out how to set both the Redis URL _and_ the default `:expires_in`. Can you help? – Chris Vincent Jul 05 '12 at 21:41
  • Like me, If you are facing issue setting `:expires_in` using redis_store refer http://stackoverflow.com/questions/20907247/redis-store-sessions-not-expiring-fixed – Anirudhan J Feb 09 '14 at 10:31
21

I've seen a few large rails sites that use both Memcached and Redis. Memcached is used for ephemeral things that are nice to keep hot in memory but can be lost/regenerated if needed, and Redis for persistent storage. Both are used to take a load off the main DB for reading/write heavy operations.

More details:

Memcached: used for page/fragment/response caching and it's ok to hit the memory limit on Memcached because it will LRU (least recently used) to expire the old stuff, and frequently keep accessed keys hot in memory. It's important that anything in Memcached could be recreated from the DB if needed (it's not your only copy). But you can keep dumping things into it, and Memcached will figure which are used most frequently and keep those hot in memory. You don't have to worry about removing things from Memcached.

redis: you use this for data that you would not want to lose, and is small enough to fit in memory. This usually includes resque/sidekiq jobs, counters for rate limiting, split test results, or anything that you wouldn't want to lose/recreate. You don't want to exceed the memory limit here, so you have to be a little more careful about what you store and clean up later.

Redis starts to suffer performance problems once it exceeds its memory limit (correct me if I'm wrong). It's possible to solve this by configuring Redis to act like Memcached and LRU expire stuff, so it never reaches its memory limit. But you would not want to do this with everything you are keeping in Redis, like resque jobs. So instead of people often keep the default, Rails.cache set to use Memcached (using the dalli gem). And then they keep a separate $redis = ... global variable to do redis operations.

# in config/application.rb
config.cache_store = :dalli_store  # memcached

# in config/initializers/redis.rb
$redis = $redis = Redis.connect(url: ENV['REDIS_URL'])

There might be an easy way to do this all in Redis - perhaps by having two separate Redis instances, one with an LRU hard memory limit, similar to Memcache, and another for persistent storage? I haven't seen this used, but I'm guessing it would be doable.

tRuEsAtM
  • 3,517
  • 6
  • 43
  • 83
Brian Armstrong
  • 19,707
  • 17
  • 115
  • 144
15

I would consider checking out my answer on this subject:

Rails and caching, is it easy to switch between memcache and redis?

Essentially, through my experience, I would advocate for keeping them separate: memcached for caching and redis for data structures and more persistant storage

Community
  • 1
  • 1
efalcao
  • 5,106
  • 1
  • 24
  • 19
  • Although I initially planned to consolidate them based on the original answer to my question, I have since come to basically the same conclusion. I'm using memcache for basic caching and redis for resque. – markquezada Dec 03 '10 at 03:56
6

I asked the team at Redis (who provide the Memcached Cloud and Redis Cloud add ons) about which product they would recommend for Rails caching. They said that in general they would recommend Redis Cloud, that Memcached Cloud is mainly offered for legacy purposes, and pointed out that their Memcached Cloud service is in fact build on top of Redis Cloud.

Adam Lear
  • 38,111
  • 12
  • 81
  • 101
Yarin
  • 173,523
  • 149
  • 402
  • 512
  • So no need for both memcached and redis as mentioned in Brian's answer? "people often keep the default Rails.cache set to use memcached (using the dalli gem). And then they keep a separate $redis = ... global variable to do redis operations." – Marklar Oct 29 '14 at 02:57
4

I don't know what you're using them for, but actually using both may give you a performance advantage: Memcached has far better performance running across multiple cores than Redis, so caching the most important data with Memcached and keeping the rest in Redis, taking advantage of its capabilities as database, could increase performance.

salezica
  • 74,081
  • 25
  • 105
  • 166
  • 1
    That's not entirely true - redis uses multiple instances rather than multiple threads, so comparing a single core redis instance with a multi core memcached instance isn't a particularly relevant test. Besides, when benchmarks are available showing both systems to be the fastest the difference is unlikely to matter in the real world. – Tom Clarkson Nov 16 '10 at 02:27
  • The multi process approach of redis scales better on multi core systems than the (default) approach of memcached with multi-threading: http://antirez.com/post/update-on-memcached-redis-benchmark.html – Ludger Sprenker Nov 17 '10 at 10:18
  • 3
    This major shortcoming of Redis is really downplayed a lot. If you are looking for high-concurrency and have many cores, Memcached can run circles around Redis. Sharding is not a good solution since you have to implement consistent hashing in your application and you won't get perfect distribution between Redis instances. For example if shard A caches your application's config that is used in every request, shard A will get more requests than the other shards which are not hit for every request. – ColinM Mar 27 '12 at 00:56