Join the discussion

Write your take first — we'll ask for email only when you're ready to publish.

  • Hacker News
  • The comment about memcached being ephemeral is orthogonal to whether people will use it as if it persistent. If the cache appears to get hit 99.9% of the time and is always there, sooner or later people will write code that relies on that behavior.

    Maybe the client libraries can help by returning nulls 10% of time, in dev mode?

  • Memcached was a savior for caching when it launched. I love that it was created in 2003 by Brad Fitzpatrick for LiveJournal. Each post on a users feed could have different access restrictions, and this allowed posts (or entire pages) to be cached.

    I used it with Ruby on Rails for many years. It sped up pages, and just worked.

    The downside (and upside for speed) is (and always was) that cache was saved in memory not disk. This meant hosting would be expensive if you have a large scale site with a wide amount of data to cache.

    Solid cache has been a savior for those cases for me. We have over 100gb of cache for a project I'm working on, and it's stored in postgres on disk, with fast lookups with an index and expirations that happen automatically in Rails to delete those rows.

    If I had a smaller cache need and was already using Redis, I'd probably just use that. But if speed was the number 1 factor, and I'd try benchmarking Memcached vs Redis.

  • memcached is about a bazillion times faster than redis at doing the simple KV cache job. it’s got threads. it’s highly optimized to do its one job super well, where redis is more a arbitrary shared Python heap kinda thing with all the data structures and single thread and whatnot.

    at notion we use redis for a lot of things, but actual caching we leave to memcached

    by jitl
  • Threads are not free - they allow to use more CPU cores but if you load is not too high than with a single thread memcached uses less CPU than with multiple.
  • Can confirm it's not that much faster at k/v. 300 vs 350 microseconds per read on average. The single thread thing doesn't matter much since it's not cpu bound, it's reactive I/O
  • I remember one "fun" feature in Memcached, is that each client did it's own hashing/sharding system... and when trying to share cached values across platforms/languages in order to further reduce resources, that was fun... writing a custom .Net/C# client to match the Java implementation. This was in the .Net 1/2 timeframe around 2002-2003 before NuGet.

    That said, it's interesting when you learn in practice that sometimes an N+1 problem is actually faster as N+1 than trying to query across separate DBMS systems.

  • > it's interesting when you learn in practice that sometimes an N+1 problem is actually faster as N+1 than trying to query across separate DBMS systems.

    This is specially visible in SQLite workflows.

    The roundtrip for querying a local SQLite file is so fast that it's passable to execute N SELECTS inside a loop instead of a single SELECT with a JOIN, for example.

    by bel8
  • I like memcached, but its really not redis's fault if you set it up as a volatile cache but people treat it as a persistent data store.

    The comparison is especially weird as memcached is also not persistent.

  • At many companies (I want to say most), Redis is seen as an actual durable production database and operated that way, not just as a cache that can disappear at any time. It's not unreasonable for a new dev to assume this unless told otherwise.
  • Redis works great as a cache, but there are a few things you need to do in order to use it reliably as a cache.

    1) Wrap your client library so that it's impossible to store anything without an expiry date. You don't want 6-months-old data suddenly coming up in your app!

    2) Either turn off persistence, or use a separate database for the cache. In other words, don't mix volatile data with stuff you actually care about.

    3) Set up a reasonable maxmemory value with an appropriate maxmemory-policy, so that Redis doesn't eat up all your RAM.

    4) Resist the urge to use complex data structures. If you try to update a single field on an expired hash, you will end up with an incomplete object.

    If you don't want all that hassle, then yes, Memcached probably works better out of the box.

  • > 1) Wrap your client library so that it's impossible to store anything without an expiry date. You don't want 6-months-old data suddenly coming up in your app!

    No need for this client-side complexity, as you should be using `allkeys-lru`. FWIW, should likely be doing this anyway, as (generally speaking) all data stored in Redis is usually regarded as volatile because of what Redis actually is.

    by dvt
  • I've done a bunch of Flask work over the past couple of years - not full time but as part of the tech stack for my small eCommerce business. Have run into all kinds of footguns and weirdness with MongoEngine, SQLAlchemy, Celery (seriously, if you value your sanity, don't use Celery!), the Python stacks for Google, eBay and Shopify but never Redis.

    Perhaps that's because I'm not giving admin access to random people who think that Redis is a persistent storage, but honestly it's one of those technologies I'd describe as absolutely rock solid and well designed. The API is dead basic and every time I need to do something slightly weird, there's a sensible and well thought out way to achieve it.

  • > every time I need to do something slightly weird, there's a sensible and well thought out way to achieve it.

    In my world cache systems like memcached and redis are just that, a cache to put and get from. Possibly use some invalidation system like tagging.

    What can you do with a cache system that is 'wierd'? What are people doing with caches other than just caching data?

    Genuinely interested.

  • I am currently in the process of starting a project with Flask, SQLAlchemy, Celery. Say more about why I should avoid Celery and what to use instead.
  • This kind of thing tends to happen a lot with open source projects or programs that are maintained long term. As the codebase grows, it inevitably starts supporting things that weren't part of the original plan.

    More features mean more users. Some stick to the old stuff, some embrace the new, and eventually certain values become the de facto default, not really optional anymore.

    Take Redis. Turn off AOF and it works as a volatile in memory cache. But most of us don't even think about it that way. So there is this argument that fewer features and simpler is better.(Memcached is such an example in this context) The so called 'straitjacket' approach. That makes total sense for big teams. But on the other hand, open source projects need regular updates to keep getting funding or contributions, so there is a built in tension.

    And sometimes that leads to specialized forks or spin offs that excel in one niche area. My personal take? There is no right answer. It all depends on the context. Communication itself isn't free, after all

  • AOF at scale causes failures, so you turn it off. Still makes a great cache though.
  • I think the clearest example of that is that people think Redis can only function as a cache that loses data on crash or shutdown.

    I think that’s because people replaced Memcached with Redis, and expect the same from it.

  • "Communication itself isn't free, after all"

    Off topic, but that's my problem with microservices, devs seem to be totally unaware of this.

  • One other feature of memcache that is rarely mentioned is that all operations are O(1) by design, which is a conscious design choice from the authors: yes, it is limiting, but it also ensures no random stalls on simple operations, whereas Redis with its single-threaded core design can't guarantee that since you can run operations of arbitrary complexity (which surely as a developer make you feel very smart about it) and everything else will be waiting for them to complete
  • There's nothing about memcache that avoids these problems.

    Back in the mid-2000s I worked on a scaled system that used memcache, and developers fell victim to all the exact same problems that are cited with Redis in the article.

    - Developers attempting to endrun every one of the laws of distributed systems by using memcache.

    - We had cache addiction, so the fleets got sized on the assumption that memcache was up, and then memecache had a problem, and suddenly we were DDOSed.

    - write amplification, where one host would nuke a high-TPS key and every other host would DDOS a dependency to repopulate the key.

    - hot keys which led to hot hosts and because we cohosted memcached with the service daemons, it meant mystery CPU spikes.

    - stickiness from stale DNS entries causing memcache calls to blackhole.

    Every single one was avoidable by using memcache in a better way, but the temptation to abuse it was too strong.

  • I think I've seen all of the Redis/Valkey issues the author mentioned in production.

    * Outages where Valkey had no memory policy, ate all the memory, and then caused write errors to its append-only file. Bonus points for another one where the disk itself was full, and AOF writes failed.

    * 500s where Redis was fully expected to be live, running, and populated with data for every user, and no fallback to a slower path.

    * Creative uses of sorted sets and other data structures which depended on the sets never being evicted.

    Despite the observations from the field, I think it's still hard to recommend memcache ahead of Redis. It can be difficult to architect an app to have a memcache-friendly cache layout.

    I'd almost guarantee a large enough team using memcache will find a way to need Redis. And then we're maintaining 2 cache technologies.

  • Not maintaining 2 cache technologies is always a winning argument.
  • I tend to write an abstraction interface, if there isn't already one, where you request a key and pass an async function/lambda that will return the value from source in case of a cache miss.

        var value = cache.lookup<T>(
          keyname, 
          () => db.query<T>(...), 
          TimeSpan.FromMinutes(5) // or CacheOptions
        );
    
    This way it can fallback/insert on a cache miss directly...
  • Once someone decides they want to use redis as something other than a cache, you sort of do have 2 cache technologies anyway. You can't use a redis instance that is configured for caching for any other purpose (caching instance must have eviction, non-caching instance must not have eviction). You need a second redis with a different configuration.

    Honestly designing your app to have a "memcache-friedly cache layout" is the same thing as designing it to have a redis-friendly cache layout. The pattern for this kind of application cache is identical: "get, and if not there, calculate and set".

  • Redis is a great piece of tech but it suffers from trying to be good at two different jobs (persistent data structures, volatile cache) which should not be combined. And indeed in Redis itself they don't combine well - persistence is globally on or off.

    Personally I'd use memcached or some equivalent for strictly cacheing, and then bring on Redis with persistence if you need its data structures for e.g scoreboards.

    At $WORK we never imported either, our cache layer for slow operations keeps its data in both the filesystem and a db table (used as a k/v store). The database helps coordinate thundering herd problems - this operation is being calculated by another thread, so just wait for it. Reads from the same server just hit the filesystem, and reads from another server hit the db once and then keep it in the filesystem. We could change the fs layer to memcached but so far it's working great.

  • > We could change the fs layer to memcached but so far it's working great.

    This so much. (Ab)Using a db table as a k/v store + the FS can do so much before even considering paying the price of setting up a dedicated caching store. I’ve fought countless foes in the engineering world when proposing solutions like yours just because (incompetent) people feel like caching should live in its dedicated store.

  • I had some experience wrangling Memcachedb (memcache + bdb for persistence) in the late 2000s, and came to much the same conclusion.

    Redis was definitely more featureful, and antirez is both an engaging character and admirably humble, so I can see why redis overtook it in popularity - but, for me, memcached has always been the pinnacle of "choose boring technology".

    As a platform engineer, I'm happy to support either - but when developers start using some of the more advanced redis features (persistence, replication, clustering), I try to make sure that they've fully understood the downsides of that decision.