WhyRedis
速度快,完全基于内存,使用 C 语言实现,网络层使用 epoll 解决高并发问题,单线程模型避免了不必要的上下文切换及竞争条件;
与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 Redis 被广泛应用于缓存方向,每秒可以处理超过 10 万次读写操作,是已知性能最快的 Key-Value DB。另外,Redis 也经常用来做分布式锁。除此之外,Redis 支持事务 、持久化、LUA 脚本、LRU 驱动事件、多种集群方案。
1、简单高效(redis 为什么这么快)
1)完全基于内存,绝大部分请求是纯粹的内存操作。数据存在内存中,类似于 HashMap,查找和操作的时间复杂度都是 O(1);
2)数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的;
3)采用单线程,避免了多线程不必要的上下文切换和竞争条件,不存在加锁释放锁操作,减少了因为锁竞争导致的性能消耗;(6.0 以后多线程)
4)使用 EPOLL 多路 I/O 复用模型,非阻塞 IO;
5)使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;
2、Memcache
使用场景:
1、如果有持久方面的需求或对数据类型和处理有要求的应该选择 redis。
2、如果简单的 key/value 存储应该选择 memcached。
3、Tair
Tair(Taobao Pair) 是淘宝开发的分布式 Key-Value 存储引擎,既可以做缓存也可以做数据源(三种引擎切换)
-
MDB(Memcache)属于内存型产品, 支持 kv 和类 hashMap 结构, 性能最优;
-
RDB(Redis)支持 List.Set.Zset 等复杂的数据结构, 性能次之, 可提供缓存和持久化存储两种模式;
-
LDB(levelDB)属于持久化产品, 支持 kv 和类 hashmap 结构, 性能较前两者稍低, 但持久化可靠性最高;
分布式缓存
大访问少量临时数据的存储(kb 左右)
用于缓存,降低对后端数据库的访问压力
session 场景
高速访问某些数据结构的应用和计算(rdb)
数据源存储
快速读取数据(fdb)
持续大数据量的存入读取(ldb),交易快照
高频度的更新读取(ldb),库存
**痛点:**redis 集群中,想借用缓存资源必须得指明 redis 服务器地址去要。这就增加了程序的维护复杂度。因为 redis 服务器很可能是需要频繁变动的。所以人家淘宝就想啊,为什么不能像操作分布式数据库或者 hadoop 那样。增加一个中央节点,让他去代理所有事情。在 tair 中程序只要跟 tair 中心节点交互就 OK 了。同时 tair 里还有配置服务器概念。又免去了像操作 hadoop 那样,还得每台 hadoop 一套一模一样配置文件。改配置文件得整个集群都跟着改。
4、Guava
分布式缓存一致性更好一点,用于集群环境下多节点使用同一份缓存的情况;有网络 IO,吞吐率与缓存的数据大小有较大关系;
本地缓存非常高效,本地缓存会占用堆内存,影响垃圾回收、影响系统性能。
本地缓存设计:
以 Java 为例,使用自带的 map 或者 guava 实现的是本地缓存,最主要的特点是轻量以及快速,生命周期随着 jvm 的销毁而结束,并且在多实例的情况,每个实例都需要各自保存一份缓存,缓存不具有一致性。
解决缓存过期:
1、将缓存过期时间调为永久;
2、将缓存失效时间分散开,不要将缓存时间长度都设置成一样;比如我们可以在原有的失效时间基础上增加一个随机值,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
解决内存溢出:
第一步,修改 JVM 启动参数,直接增加内存。(-Xms,-Xmx 参数一定不要忘记加。)
第二步,检查错误日志,查看 “OutOfMemory” 错误前是否有其它异常或错误。
第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。
Google Guava Cache
自己设计本地缓存痛点:
-
不能按照一定的规则淘汰数据,如 LRU,LFU,FIFO 等;
-
清除数据时的回调通知;
-
并发处理能力差,针对并发可以使用 CurrentHashMap,但缓存的其他功能需要自行实现;
-
缓存过期处理,缓存数据加载刷新等都需要手工实现;
Guava Cache 的场景:
-
对性能有非常高的要求
-
不经常变化,占用内存不大
-
有访问整个集合的需求
-
数据允许不实时一致
Guava Cache 的优势:
- 缓存过期和淘汰机制
在 GuavaCache 中可以设置 Key 的过期时间,包括访问过期和创建过期。GuavaCache 在缓存容量达到指定大小时,采用 LRU 的方式,将不常使用的键值从 Cache 中删除。
- 并发处理能力
GuavaCache 类似 CurrentHashMap,是线程安全的。提供了设置并发级别的 api,使得缓存支持并发的写入和读取,采用分离锁机制,分离锁能够减小锁力度,提升并发能力,分离锁是分拆锁定,把一个集合看分成若干 partition, 每个 partiton 一把锁。更新锁定
- 防止缓存击穿
一般情况下,在缓存中查询某个 key,如果不存在,则查源数据,并回填缓存。(Cache Aside Pattern)在高并发下会出现,多次查源并重复回填缓存,可能会造成源的宕机(DB),性能下降 GuavaCache 可以在 CacheLoader 的 load 方法中加以控制,对同一个 key,只让一个请求去读源并回填缓存,其他请求阻塞等待。(相当于集成数据源,方便用户使用)
- 监控缓存加载 / 命中情况
统计
问题:
OOM-> 设置过期时间、使用弱引用、配置过期策略
5、EVCache
EVCache 是一个 Netflflix(网飞)公司开源、快速的分布式缓存,是基于 Memcached 的内存存储实现的,用以构建超大容量、高性能、低延时、跨区域的全球可用的缓存数据层。
E:Ephemeral:数据存储是短暂的,有自身的存活时间
V:Volatile:数据可以在任何时候消失
EVCache 典型地适合对强一致性没有必须要求的场合
典型用例:Netflflix 向用户推荐用户感兴趣的电影
EVCache 集群在峰值每秒可以处理 200kb 的请求,
Netflflix 生产系统中部署的 EVCache 经常要处理超过每秒 3000 万个请求,存储数十亿个对象,
跨数千台 memcached 服务器。整个 EVCache 集群每天处理近 2 万亿个请求。
EVCache 集群响应平均延时大约是 1-5 毫秒,最多不会超过 20 毫秒。
EVCache 集群的缓存命中率在 99% 左右。
典型部署
EVCache 是线性扩展的,可以在一分钟之内完成扩容,在几分钟之内完成负载均衡和缓存预热。
1、集群启动时,EVCache 向服务注册中心(Zookeeper、Eureka)注册各个实例
2、在 web 应用启动时,查询命名服务中的 EVCache 服务器列表,并建立连接。
3、客户端通过 key 使用一致性 hash 算法,将数据分片到集群上。
6、ETCD
和 Zookeeper 一样,CP 模型追求数据一致性,越来越多的系统开始用它保存关键数据。比如,秒杀系统经常用它保存各节点信息,以便控制消费 MQ 的服务数量。还有些业务系统的配置数据,也会通过 etcd 实时同步给业务系统的各节点,比如,秒杀管理后台会使用 etcd 将秒杀活动的配置数据实时同步给秒杀 API 服务各节点。
Redis 底层
1、redis 数据类型
2、相关 API
http://redisdoc.com