carlosfu
作者carlosfu·2021-09-27 09:39
软件开发工程师·快手

Redis和Memcached的恩怨情仇

字数 3323阅读 1195评论 0赞 1

近些年来各路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机制:

With slab allocation, memory is reserved in blocks of 1MB. The slab is divided up into a number of blocks of equal size. When youtry to store a value into the cache, Memcached checks the size of the value that you are adding to the cache and determines whichslab contains the right size allocation for the item. If a slab with the item size already exists, the item is written to the blockwithin the 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。

本文作者:快手 焦瑞刚

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

1

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广