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