memcache和redis是互联网分层架构中最常用的KV缓存。很多同学在选择模型的时候都会纠结,是选择memcache还是redis。画外音:不鼓励粗暴的练习,比如“memcache提供的功能是redis提供的功能的一个子集,别想太多,你可以选择redis”。虽然redis比memcache出来的晚,功能也多,但是对于一个技术人来说,理解“为什么”恐怕比“选择谁”更重要。你倾向于什么时候选择redis?业务需求决定技术选择。当业务有这样的特点时,选择redis会更合适。当复杂数据结构值是hash、list、set、orderedset等复杂数据结构时,会选择redis,因为mc无法满足这些要求。最典型的场景,用户订单列表,用户留言,帖子评论列表等,持久化的mc无法满足持久化的要求,所以不得不选择redis。不过,这里要提醒的是,redis的持久化功能真的使用正确吗?不要把redis当数据库使用:redis的定期快照不能保证数据不丢失。redis的AOF会降低效率,不能支持太多不要指望redis对大数据做固化存储比mysql好。不同的工具各有所长,使用redis作为数据库很可能是错误的。缓存场景和开启固化功能有什么优缺点?如果只缓存场景,数据存入数据库,缓存在redis中,而此时如果开启固化功能:好处是redis挂掉后,热数据可以快速恢复到内存中,重新启动。它会立即对数据库施加压力,而无需缓存预热过程。缺点是在redis挂掉的过程中,如果数据库中有数据修改,可能会导致redis重启后数据库和redis的数据不一致。所以,对于只读场景,或者允许一些不一致的业务场景,可以尝试开启redis的固化功能。天然高可用redis天然支持集群功能,可以实现主动复制和读写分离。redis官方还提供了sentinel集群管理工具,可以实现主从服务监控和故障自动转移。所有这一切对客户端都是透明的,无需更改程序或人工干预。对于memcache,为了实现高可用,需要进行二次开发,比如客户端双读双写,或者服务端集群同步。不过,这里要提醒的是,在大多数业务场景下,缓存真的需要高可用吗?在缓存场景中,很多情况下,缓存未命中是允许的。缓存被挂起,很多时候可以通过DB读取数据。因此需要仔细分析业务场景,高可用真的是缓存的主要需求吗?画外音:在即时通讯业务中,用户的在线状态有很高的可用性要求。存储的内容大于memcache的值存储,最大1M。如果存储的值很大,只能使用redis。你什么时候更喜欢内存缓存?纯KV,数据量非常大,业务并发量非常大,用memcache可能更合适。这就要从mc和redis的底层实现机制的区别说起。内存分配Memcache使用预先分配的内存池来管理内存,可以节省内存分配时间。Redis是临时申请空间,可能会造成碎片。从这点来说,mc会快一点。虚拟内存使用内存缓存将所有数据存储在物理内存中。Redis有自己的VM机制,理论上可以存储比物理内存更多的数据。当数据超过数量时,会触发swap将冷数据刷入磁盘。从这一点来说,mc在数据量大的时候会比较快。网络模型memcache采用了非阻塞IO多路复用模型,redis也采用了非阻塞IO多路复用模型。但是由于redis在KV存储之外还提供了排序聚合功能,复杂的CPU计算在执行这些功能时会阻塞整个IO调度。从这一点来说,由于redis提供的功能更多,mc会更快。线程模型memcache采用多线程,主线程监控,worker子线程接受请求并进行读写。在这个过程中,可能会出现锁冲突。Redis使用单线程。虽然没有锁冲突,但是很难利用多核的特性来提高整体的吞吐量。从这一点来看,mc会更快。***说两点1.代码可读性和代码质量我看过mc和redis的代码。就可读性而言,redis是我见过代码最清爽的软件。甚至没有一个。可能只是redis的设计初衷,编译redis连configure都不需要,不需要依赖第三方库,一个make就可以搞定。至于memcache,可能是考虑了太多的扩展性和多系统兼容性,代码不清晰,显得费力。比如网络IO的部分,redis源码1-2个文件就可以搞定,mc用的是libevent,来回传一个fd,传pipe和thread,特别容易让人头晕。画外音:理论上mc只支持kv,redis支持那么多功能。mc的性能应该高很多很多,但事实并非如此。这可能真的与代码质量有关。2.支持水平扩展无论是mc还是redis,服务器集群天然不支持水平扩展,需要在客户端进行分片,其实对调用者并不友好。如果服务器集群能够支持水平扩展,效率会更高。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文
