redis的选择和定位
传统memcached + mysql遇到的问题
实际mysql是适合大量数据存储的,通过memcached将热点数据加载到cache,加速访问。很多公司都曾用过这种架构,但是随着业务数据量的不断增长,访问量的不断加大,遇到了很多问题
mysql需要不断的拆库拆表,memcached需要不断的扩容,扩容和维护占据着大量开发时间
memcached和mysql数据库的数据一致性问题
memcached数据命中率低或down机,大量访问直接穿穿透到DB,mysql无法支撑
跨机房cache同步问题
redis的适用场景
redis最适合所有数据in-momory的场景,虽然redis支持数据持久化功能,但实际更多的是disk-backed的功能,跟传统意义上的持久化有比较大的差别
redis和memcached的区别
网络IO模型
memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程,监听网络连接,接受请求后将链接描述符pipe传递给worker线程,进行读写IO,网络层使用libevent封装的事件库。多线程可以发挥多核作用。但是也引入了cache coherency和锁的问题。比如memcache的最常使用的命令stats,实际上memcached的所有的操作都需要对这个全局变量加锁,进行技术等工作。带来了性能损耗。redis使用简单的单线程IO模型,自己封装了一个简单的aeEvent事件处理框架,主要实现了epoll, kqueue, select, 对于单纯只有IO操作,单线程可以将速度优势发挥到最大。但是redis也提供了一些简单的计算功能,排序,聚合等。对于这些操作,单线程模型实际会严重影响整体的吞吐量。CPU计算过程中,整个IO调度都是阻塞的。
内存管理方面
memcached使用预分配的内存池的方式,使用slab和大小不同的chunk来管理内存。itme根据大小选择合适的chunk来存储数据,内存池的方式能省去申请/释放内存的开销。并且减小内存碎片的存在,但是这有一定上程度上的空间浪费。并且在内存仍然有很大的空间时,新数据也可能会被删除。redis使用现场申请内存的方式存储数据。并且很少使用free-list等方式优化内存分配。redis根据存储命令参数,会把带有过期命令的数据存放在一起。并把它们称为临时数据。非临时数据是永远不会被剔除的。即使物理内存不够,swap也不会剔除非临时数据。在这一点上,redis更适合做存储,而不是cache。
数据一致性问题
memcached提供了cas命令,保证在多个并发访问下操作同一份数据的一致性问题。redis没有提供cas命令,但是redis提供了事务的功能,保证一连串命令的顺序执行,不会被任何操作打断。
存储方式及其他问题
memcached只支持了基础的key-value的存储方式,不支持枚举,持久化,赋值等功能。
redis除了提供key-value的存储方式,还提供了 list,set, sort, hash等众多数据结构,提供了keys进行枚举操作,但不能线上使用,如果线上使用,redis提供了工具可以扫描dump文件,枚举出所有数据,redis还提供了持久化,复制等功能。
小结
从以上能看出, 当我们不希望数据被剔除,或者需要跟多的数据类型,或者需要落地功能时,使用redis更为方便。
关于redis的一些周边功能
redis除了作为存储,还有一些其他的功能,pubsub,scripting,对于此类功能,需要了解其实现原理。当使用pubsub时,没有任何持久化支持的。消费者链接闪断或者重连之后,消息会全部丢失。又比如聚合计算,scripting功能都受单线程模型限制,是不可能达到很高的吞吐量的,需要谨慎使用。总结
redis使用最佳方式是数据全部in-momory
redis的更多场景是作为memcached的替代者来使用
当需要key-value之外的更多数据类型时,redis更为合适
当存储数据不能被剔除时,使用redis更为合适
需要了解的
redis数据类型和容量规划
如何根据业务场景搭建稳定,可靠,可扩展的redis集群