Memcached 采用「客户端-服务器」的架构,客户端和服务器端的通讯使用自定义的协议标准,只要满足协议格式要求,客户端 Library 可以用任何语言实现。
Memcached 服务器使用基于 Slab 的内存管理方式,有利于减少内存碎片和频繁分配销毁内存所带来的开销。各个 Slab 按需动态分配一个 page 的内存(和 4K page的概念不同,这里默认 page 为 1M),page 内部按照不同 slab class 的尺寸再划分为内存 chunk 供服务器存储 KV 键值对使用(slab 机制相当于内存池机制,实现从操作系统分配一大块内存,然后 memcached 自己管理这块内存,负责分配与回收。)
实际 MySQL 是适合进行海量数据存储的,通过 Memcached 将热点数据加载到 cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和访问量的持续增长,我们遇到了很多问题:
MySQL 需要不断进行拆库拆表,Memcached 也需不断跟着扩容,扩容和维护工作占据大量开发时间
Memcached 与 MySQL 数据库数据一致性问题
Memcached 数据命中率低或 down 机,大量访问直接穿透到 DB,MySQL 无法支撑
跨机房 cache 同步问题
总体上这些 NoSQL 主要用于解决以下几种问题:
少量数据存储,高速读写访问。此类产品通过数据全部 in-momery 的方式来保证高速访问,同时提供数据落地的功能,实际这正是 Redis 最主要的适用场景
海量数据存储,分布式系统支持,数据一致性保证,方便的集群节点添加/删除。这方面最具代表性的是 dynamo 和 bigtable 2篇论文所阐述的思路。前者是一个完全无中心的设计,节点之间通过 gossip 方式传递集群信息,数据保证最终一致性,后者是一个中心化的方案设计,通过类似一个分布式锁服务来保证强一致性,数据写入先写内存和 redo log,然后定期 compat 归并到磁盘上,将随机写优化为顺序写,提高写入性能
Schema free,auto-sharding 等。比如目前常见的一些文档数据库都是支持 schema-free 的,直接存储 json 格式数据,并且支持 auto-sharding 等功能,比如 mongodb
Redis 最适合所有数据 in-momory 的场景,虽然 Redis 也提供持久化功能,但实际更多的是一个 disk-backed 的功能,跟传统意义上的持久化有比较大的差别,那么可能大家就会有疑问,似乎 Redis 更像一个加强版的 Memcached,那么何时使用 Memcached,何时使用Redis呢?
没有必要过多的关心性能,因为二者的性能都已经足够高了。无论你使用哪一个,每秒处理请求的次数都不会成为瓶颈。(比如瓶颈可能会在网卡)
使用简单的 key-value 存储,Memcached 的内存利用率更高,而如果 Redis 采用 hash 结构来做 key-value 存储,由于其组合式的压缩,其内存利用率会高于 Memcached。
如果你对数据持久化和数据同步有所要求,那么推荐你选择 Redis,因为这两个特性 Memcached 都不具备。
Redis 相比 Memcached 来说,拥有更多的数据结构和并支持更丰富的数据操作,通常在 Memcached 里,你需要将数据拿到客户端来进行类似的修改再 set 回去。这大大增加了网络 IO 的次数和数据体积。在 Redis 中,这些复杂的操作通常和一般的 GET/SET 一样高效。所以,如果你需要缓存能够支持更复杂的结构和操作,那么 Redis 会是不错的选择。Memcached 值最大为 1M,Redis 值最大为 512M。
Memcached 是多线程,分为监听线程、worker 线程,引入锁,带来了性能损耗。Redis 使用单线程的 IO 复用模型,将速度优势发挥到最大,也提供了较简单的计算功能。
Memcached 使用预分配的内存池的方式,带来一定程度的空间浪费并且在内存仍然有很大空间时,新的数据也可能会被剔除,而 Redis 使用现场申请内存的方式来存储数据,不会剔除任何非临时数据 Redis 更适合作为存储而不是 cache 数据的一致性方面:Memcached 提供了 cas 命令来保证。而 Redis 提供了事务的功能,可以保证一串命令的原子性,中间不会被任何操作打断。
如果简单地比较 Redis 与 Memcached 的区别,大多数都会得到以下观点:
Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储
Redis 支持数据的备份,即 master-slave 模式的数据备份
Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
Redis 可以实现主从复制,实现故障恢复
Redis 的 Sharding 技术: 很容易将数据分布到多个 Redis 实例中
Redis 最为常用的数据类型主要有以下:
string 是 Redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。
string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如 jpg 图片或者序列化的对象。
string 类型是 Redis最基本的数据类型,一个键最大能存储 512MB。
Redis hash 是一个键名对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
Redis 的 Set 是 string 类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
Redis zset 和 set 一样也是 string 类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个 double 类型的分数。Redis 正是通过分数来为集合中的成员进行从小到大的排序。
zset 的成员是唯一的,但分数(score)却可以重复。
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:
事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
显示最新的项目列表
删除与过滤
排行榜相关
按照用户投票和时间排序
处理过期项目
计数
特定时间内的特定项目
实时分析正在发生的情况,用于数据统计与防止垃圾邮件等
Pub/Sub
队列
缓存