环境搭建
基础环境
用户
1 | # 增加用户,并赋予其密码 |
目录
1 | $ cd /home/redis |
分布式集群
下载
1 | $ cd ~/install |
解压分发
1 | $ tar zxvf redis-3.2.9.tar.gz -C ~/software |
安装
1 | $ cd ~/software/redis |
配置
1 | $ mv redis.conf redis.conf.bak |
启动
1 | $ nohup redis-server redis.conf 1>/dev/null 2>&1 & |
集群配置
安装 Ruby
1 | # Debian / Ubuntu |
安装 Redis 插件
1 | # Online |
redis-trib 创建分布式集群
1 | $ redis-trib.rb create --replicas 1 192.168.1.101:6379 192.168.1.102:6379 192.168.1.103:6379 192.168.1.101:6380 192.168.1.102:6380 192.168.1.103:6380 |
redis-cli 集群状态检查
1 | # 至此,大功告成~ |
关闭
1 | $ pkill redis |
遇到的坑
cannot load such file — zlib
描述
1 | $ gem install -l redis-3.2.2.gem |
解决
1 | $ yum install zlib-devel |
ERR Slot 0 is already busy
描述
1 | # 执行 redis-trib.rb 遇到 |
解决
1 | # 通过 cluster reset soft 命令解决 |
ERR Invalid node address specified
描述
1 | # 执行创建 Redis 集群 |
解决
1 | # 目前为止,只支持 IP,不支持 Hostname,因此将主机名替换为 IP 即可(PR#2323 中准备解决该问题) |
Jedis 客户端
连接集群
1 | private void init(DynamicPropUtils DP) { |
集群操作
1 | public Long putSet(String key, String... values) { |
资源释放
1 | public void close() throw IOException { |
过期事件回调
配置集群
1 | # 通过 redis-cli 进行动态配置 |
服务端验证
1 | $ redis-cli |
连接集群
1 | private String getClusterList(DynamicPropUtils DP) { |
回调监听器
1 | try (RedisClusterConnPool pool = new RedisClusterConnPool(dp, true)) { |
测试
1 | pool.put("yuzhouwan01", "blog01"); |
实战技巧
匹配删除
1 | $ redis-cli flushdb |
数据容灾
主从热备 + 二级缓存 + 从库 AOF(主从切换)
参考
- Redis 持久化
- Redis 哨兵模式实现主从故障互切换
- 《Redis in Action》 第 4 章
全局流控
流控方案
Leaky bucket 漏桶算法
桶内水溢出时,可以把消息放到队列中等待
Token bucket 令牌桶算法
桶内令牌不足时,可以把消息放到队列中等待
实现方式
Guava RateLimiter
Guava 无法做到全局流控
Redis Expire 机制
如果设置的超时时间过长,可能对内存有一定的损耗
Hystrix 限流
支持 自动降级、熔断与恢复、依赖隔离、异常记录、流量控制、实时监控,不过会存在一定的 代码侵入 和 性能损耗 的问题(1%~5%)
参考
- 单机版
- 分布式
- Hystrix
- 理论基础
Tips: Full code is here.
技术内幕
缓存穿透 vs. 缓存雪崩 vs. 缓存失效
缓存穿透
场景描述
一般的缓存系统,都是按照 key 去缓存查询,如果不存在对应的 value,就应该去后端系统查找(比如 DB)。如果 key 对应的 value 是一定不存在的,并且对该 key 并发请求量很大,就会对后端系统造成很大的压力,我们称之为缓存穿透
解决方案
- 对查询结果为空的情况也进行缓存,缓存过期时间设置短一点(避免消耗太多的缓存空间),或者该 key 对应的数据 insert 了之后清理缓存
- 对一定不存在的 key 进行过滤。可以把所有的可能存在的 key 放到一个大的 Bitmap 中,查询时通过该 Bitmap 过滤
- 排查是否是自身程序或者数据的问题,亦或是外部恶意攻击或者爬虫,导致大量访问不存在的 key 值
缓存雪崩
场景描述
缓存雪崩,是指当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如 DB)带来很大压力
解决方案
- 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个 key 只允许一个线程查询数据和写缓存,其他线程等待
- 不同的 key,设置不同的过期时间,让缓存失效的时间点尽量均匀
- 做二级缓存,A1 为原始缓存,A2 为拷贝缓存。A1 失效时,可以访问 A2。A1 缓存失效时间设置为短期,A2 设置为长期
- 保证缓存层服务的高可用,后端组件做好限流措施,并提前预演缓存层失效的场景
缓存失效
场景描述
缓存失效,是指缓存集中在一段时间内失效,DB 的压力凸显
解决方案
这个没有完美解决办法,但可以分析用户行为,尽量让失效时间点均匀分布。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上
其他
当发生大量的缓存穿透,例如对某个失效的缓存的大并发访问就造成了缓存雪崩
缓存失效的同时发生雪崩效应,对底层系统的冲击将会非常大。这时候,可以使用双缓存机制,在工作缓存之外另外维护一层灾备缓存
双缓存 vs. 二级缓存
一般的,用 Keepalived 做双机热备,而用 J2Cache 来做二级缓存
Tips: Full code is here.
为什么 Redis 一致性算法使用 Raft,而不是 Paxos?
没有应用场景上的区别,主要是因为 Raft 算法更为简单、好懂 和 易实现
协议上的简化
最后主要 RPC 只有两个,其他协议的二阶段、三阶段也都变成 看起来像是一阶段
Term 概念的强化
看起来似乎 Paxos 也有重选 Leader 的机制,但是强化概念,并增加一个 Term,包含有一个 Leader、Entry 与 Term 相关的属性等都大大简化了流程
Log 只会从 Leader 到 Follower 单向同步
实现一下,会发现减少了很多问题,代码实现的复杂度也下降了很多
Redis vs. Memcached vs. MongoDB
性能
都比较高,性能对我们来说应该都不是瓶颈
从 TPS 的角度来看,Redis 和 Memcached 差不多,要略优于 MongoDB
操作的便利性
Redis 丰富一些,数据操作方面,Redis 更好一些,较少的网络 I/O 次数
Memcached 数据结构单一
MongoDB 支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富
内存空间的大小和数据量的大小
Redis 在 2.0 版本后增加了自己的 VM 特性,突破物理内存的限制;可以对 K-V
设置过期时间 (类似 Memcached)
Memcached 可以修改最大可用内存,采用 LRU 算法
MongoDB 适合大数据量的存储,依赖操作系统 VM 做内存管理,吃内存也比较厉害,服务不要和其他的放在一起
可用性(单点问题)
Redis 依赖客户端来实现分布式读写;主从复制时,每次从节点重新连接主节点都要依赖整个快照,无增量复制,因性能和效率问题,所以单点问题比较复杂
不支持自动 sharding,需要依赖程序设定一致 hash 机制
一种替代方案是,不用Redis本身的复制机制,采用自己做主动复制(多份存储),或者改成增量复制的方式(需要自己实现),一致性问题和性能的权衡
Memcached 本身没有数据冗余机制,也没必要;对于故障预防,采用依赖成熟的 hash 或者环状的算法,解决单点故障引起的抖动问题。
MongoDB 支持 master-slave、replicaset(内部采用 Paxos 选举算法,自动故障恢复)、auto sharding 机制,对客户端屏蔽了故障转移和切分机制。
可靠性(持久化)
Redis 对于数据持久化和数据恢复,Redis 支持(快照、AOF):依赖快照进行持久化,AOF 增强了可靠性的同时,对性能有所影响
Memcached 不支持,通常用在做缓存,提升性能
MongoDB 从 1.8 版本开始采用 binlog 方式支持持久化的可靠性
数据一致性(事务支持)
Redis 事务支持比较弱,只能保证事务中的每个操作连续执行
Memcached 在并发场景下,用 CAS 保证一致性
MongoDB 不支持事务
数据分析
MongoDB 内置了数据分析的功能(MapReduce),其他不支持
应用场景
Redis 数据量较小的更性能操作和运算上
Memcached 用于在动态系统中减少数据库负载,提升性能;做缓存,提高性能(适合读多写少,对于数据量比较大,可以采用 sharding)
MongoDB 主要解决海量数据的访问效率问题
资料
Doc
Blog
- Redis 数据类型详解,以及 Redis 适用场景场合
- Cassandra、Mongodb、CouchDB、Redis、Riak、Membase、Neo4j、HBase 最佳应用场景
- 适用场景和量化分析
- 数据结构的选择
- 调优与运维