Redis和Memcached的恩怨情仇
近些年来各路KV缓存强势崛起,尤其Redis一骑绝尘,很多新进的程序员可能都没听说过Memcached,还有很多老程序员觉得Memcached不行:功能少,不持久化,高可用差,但事实并非如此,本文将对Redis和Memcached进行对比看看Memcached是不是真的”一无是处“了
下面我们来看一个场景
业务同学A:你好,我申请了一个20G,100000 QPS的Memcached,麻烦审批下?
业务同学B:hello,请问什么时候用Redis?什么时候用Memcached?
业务同学C: Memcached支持数据迁移和持久化吗?
业务同学D:我这里可能会有一些热点和大key的需求,Redis还是Memcached有什么建议吗?
......
不少同学在选型的时候会纠结,到底是选Memcached还是Redis,该考虑哪些因素?
一、考虑因素
首先我们需要知道,自己业务有哪些特点,需要考虑哪些因素?如下是在选型对比中,通常需要考虑的因素。
二、Redis与Memcached对比
1、数据类型
Redis支持丰富的数据类型,比如string、hash、list、set、zset。
Memcached只支持简单的key/value数据结构。
2、单线程/多线程/承载QPS
Redis是单线程请求,所有命令串行执行,并发情况下不需要考虑数据一致性问题;性能受限于CPU,单实例QPS在4-6w。
Memcached是多线程,可以利用多核优势,单实例在正常情况下,可以达到写入60-80w qps,读80-100w qps。
3、持久化/数据迁移
Redis支持持久化操作,可以进行aof及rdb数据持久化到磁盘。
Memcached无法进行持久化,数据不能备份,只能用于缓存使用,且重启后数据全部丢失。
4、对热点、bigkey支持的友好度
Redis的big key与热key类操作,如果qps较高则容易造成Redis阻塞,影响整体请求。
Memcached因为是多线程,与Redis相比,在big key与热key类操作上支持较好。
5、高可用/HA
Redis支持通过Replication进行数据复制,通过master-slave机制,可以实时进行数据的同步复制,
支持多级复制和增量复制,master-slave机制是Redis进行HA的重要手段。
Memcached无法进行数据同步,不能将实例中的数据迁移到其他MC实例中。
6、发布订阅机制
Redis支持pub/sub消息订阅机制,可以用来进行消息订阅与通知。
Memcached不支持发布订阅。
7、周边支持
Redis相对Memcached,周边工具支持较好,比如迁移、数据分析等方便,目前KCC支持全量和指定前缀等数据分析和删除功能。
Memcched周边支持较少,且原生不支持key分析等操作,目前KCC自研实现针对中小memached集群的key分析和指定前缀数据删除功能。
注:KCC是公司Redis、Memcached、ElasticSearch、Pika管控平台,目前管理70w+Cache实例,3000+ElasticSearch实例的智能化运维。
三、常见核心问题
1、Memcached内存分配原理
(1) Slab Allocator的机制
Memcached默认情况下采用了名为Slab Allocator的机制分配、管理内存。
slab机制相当于内存池机制, 实现从操作系统分配一大块内存, 然后 Memcached 自己管理这块内存, 负责分配与回收。
咱们深入浅出,官方原文这样描述slab机制:
像一般的内存池一样,从操作系统分配到一大块内存后,为了方便管理,把这大块内存划分为各种大小的 chunk,chunk的大小按照一定比例逐渐递增,如下图所示:
Slab Allocation的主要术语:
Page :分配给Slab的内存空间,默认是1MB。分配给Slab之后根据slab的大小切分成chunk。(这也是为什么默认value不能超过1M的原因,不过可以调整。)
Chunk:用于缓存记录的内存空间,是存储的最小单位。
Slab Class:特定大小的chunk的组。
(2) 数据是如何存储的
Memcached根据收到的数据的大小,选择最适合数据大小的slab。Memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk,然后将数据缓存于其中。
(3) slab带来的挑战
由于分配的是特定长度的内存,因此无法有效利用分配的内存。例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了;所以需注重value的设计。
2、Redis内存碎片是什么
(1) 定义
其中,used_memory_rss表示 操作系统角度Redis占用的物理内存大小;used_memory表示Redis进程以及存储所有数据占用的大小。
(2) 碎片原理
Redis默认的内存分配器采用jemalloc, 可选的分配器还有:glibc、tcmalloc。内存分配器为了更好地管理和重复利用内存, 分配内存策略一般采用固定范围的内存块进行分配。例如jemalloc在64位系统中将内存空间划分为:小、 大、 巨大三个范围。每个范围内又划分为多个小的内存块单位,如下所示:
比如当保存5KB对象时jemalloc可能会采用8KB的块存储, 而剩下的3KB空间变为了内存碎片不能再分配给其他对象存储。
jemalloc针对碎片化问题专门做了优化(Redis 4.0版本加入了碎片清理功能), 一般不会存在过度碎片化的问题, 正常的碎片率( mem_fragmentation_ratio) 在1.03左右。
内存碎片过大的可能原因:
频繁做更新操作, 例如频繁对已存在的键执行append、 setrange等更新操作。大量过期键删除, 键对象过期删除后, 释放的空间无法得到充分利用, 导致碎片率上升。
四、典型应用架构
下面是一些Memcached的典型用法
1、Memcached的双活用法
Memcached本身不支持持久化和数据迁移,而其对QPS和热点key等支持较好,所以在用法上可以做些改变;
即一个逻辑机房对应两个一模一样的集群(即双活),利用双活集群来保证可用性;如下:
双活模式下,即使其中一活的节点宕机,在另外一活和回写机制的保证下,也可以保证整个Memcached的可用性;并且在此基础上,又演变出双机房单活和多活模式。
目前,线上单活最高QPS 6000w+,单活最大容量40T,单活单key最大512M,而且线上一些小文件对象也有用到Memcached缓存。
2、多级缓存
Memcached挡在Redis的前面,利用各自优势,形成多级缓存,满足业务需求的同时承担更多的读请求,某个计数应用架构如下:
相比纯Redis,可以支撑更大的读请求。
五、总结
Redis和Memcached各有千秋,对于一些超高QPS(例如千万级别)、超大big key、以及存在较高热点的业务,在memcahced满足相关功能需求的情况下,建议大家使用Memcached;否则建议大家使用Redis。
文章转自公众号:Redis开发运维实战