是什么
纯内存的kv缓存
适用场景是什么, 为什么
首先看看不适用的场景
1.数据量特别大的,如100G以上. 因为redis是全内存的,成本太高
2.value是大对象的. 因为redis是单线程模型, 大对象容易造成服务端阻塞
3.对数据可靠性要求特别高的. 因为redis定位是缓存,正常集群模式下,也存在数据丢失的可能.除非高成本的构建多master双写集群
适用场景有
1.热数据明显的业务场景. 因为其是纯内存,容量小,热数据才能发挥价值 2.较为复杂的数据结构
自身有什么优势和缺点是什么
优势: 1.丰富的数据结构 2.纯内存保证了其低延时
缺点: 容量小
横向对比其它技术, 有什么优势和缺点
跟tair对比: redis优势在于纯内存,延时更低. 缺点是容量小,持久化存在丢数据问题
跟mc对比: redis优势在于mc有的,redis都有
技术特性有哪些, 实现原理是怎么样的
持久化机制
A. 持久化机制RDB:
会在一段时间内,生成指定时间点的 数据集快照 snapshot
优点:
1.rdb文件简洁, 适于做备份,可定时进行备份
2.性能也较好,因为是通过fork一个子进程,用copy on write机制进行的, 不会对redis主进程造成影响
3.在数据量比较大的情况下,rdb启动恢复更快
缺点:
1.容易造成数据丢失. 时间窗口内的数据会丢失
2.容易影响性能. 一般一次save会造成几毫秒的停顿. 大数据+机器性能不好,可能会到秒级别.
B.持久化机制AOF:
记录每一条写write命令.(可在后台重写rewrite,减少冗余命令). AOF 持久化实现可以分为命令追加(append)、文件写入(write)、文件同步(fsync) 三个步骤。Append 追加命令到 AOF 缓冲区,Write 将缓冲区的内容写入到程序缓冲区,Fsync 将程序缓冲区的内容写入到文件。
优点: 比RDB可靠. 可配置不同的 fsync 策略:no、everysec 和 always。默认是 everysec。这意味着你最多丢失一秒钟的数据。
缺点: 一般体积比RDB大
主从复制
全量重同步: 略
部分重同步: 适用于 断线重连 . 根据版本发展,涉及2个阶段.
1.psync 涉及3个概念: 复制偏移量 offset + 复制积压缓冲区 + 运行时run_id. 其中run_id的作用是判断重连后, 连上的master是否是之前连接的master.(如果是,就部分重同步, 如果不是,则因为master对该slave没有相关offset的记录,就需要全部重同步)
2.psync2 Redis 4.0 版本新增 混合持久化,还优化了psync(以下称 psync2),psync2 最大的变化支持两种场景下的部分重同步,一个场景是 slave 提升为 master 后,其他 slave 可以从新提升的 master 进行部分重同步,这里需要 slave 默认开启复制积压缓冲区;另外一个场景就是 slave 重启后,可以进行部分重同步。这里要注意和 psync1 的运行 ID 相比,这里的复制 ID 有不一样的意义。
在 分布式 / 高并发 / 高QPS / 数据一致性 等环境下, 有什么问题或有什么特性, 如何解决的
分布式
Redis集群
1.集群方案的演变
集群需要解决的2个问题是: 数据分片的逻辑如何实现, 以及在哪里实现该逻辑. 常规的方案有2种: 1.通过proxy层实现. 例如之前DB中间件XXX. 好处是迁移升级方便, 缺点是损失性能(因为加了一层). 2.客户端实现. 好处是性能比proxy方式好, 但是在实现故障转移,策略的及时更新等方面不足. Redis的方案是一种新的第3种: 去中心化的集群模式. 集群通过分片进行数据共享.
三种集群方式的优缺点: TODO
2.集群方案的实现细节
哈希槽: 16384个. 其中有个概念是 哈希标签(Hash Tag)。哈希标签是确保两个键都在同一个 slot 里的一种方式。简单来说,如果一个键包含一个 “{…}” 这样的模式,只有 { 和 } 之间的字符串会被用来做哈希以获取 slot。
哈希槽的迁移: 每个slot在迁移时,有2个状态: migrating和importing
moved和ask命令: MOVED 意为这个 slot 的负责已经永久转交给另一个节点,因此可以直接把请求准发给现在负责该 slot 的节点。但是考虑在 slot 迁移过程中,会出现属于该 slot 的一部分 Key 已经迁移到目的地节点,而另一部分 Key 还在源节点,那如果这时收到了关于这个 slot 的请求,那么源节点会现在自己的数据库里查找是否有这个 Key,查到的话说明还未迁移那么直接返回结果,查询失败的话就说明 Key 已经迁移到目的地节点,那么就向客户端返回一个 ASK 错误,指引客户端转向目的地节点查询该 Key。
客户端处理: 如果客户端每次都随机连接一个节点然后利用 MOVED 或者 ASK 来重定向其实是很低效的,所以一般客户端会在启动时通过解析 CLUSTER NODES 或者 CLUSTER SLOTS 命令返回的结果得到 slot 和节点的映射关系缓存在本地,一旦遇到 MOVED 或者 ASK 错误时会再次调用命令刷新本地路由(因为线上集群一旦出现 MOVED 或者是 ASK 往往是因为扩容分片导致数据迁移,涉及到许多 slot 的重新分配而非单个,因此需要整体刷新一次),这样集群稳定时可以直接通过本地路由表迅速找到需要连接的节点。
3.故障检测与转移
检测: 涉及几个概念 failure report 和 '节点为 FAIL' 和 '该节点进一步被标记为 FAIL '. 根据gossip协议,形象理解来说就是: 如果A监测到B不通, 则A认为B疑似挂掉了, 而此时如果 之前已经 有C和D都也以为B不通, 则A会将B对应的失败报告中添加上C和D, 此时,就相当于A,C,D都认为B不通. 此时如果超过半数了, 就会认为B真的不通了,就像集群中发送一个B已经fail的消息.这样所有其它master都认为B不通,将其标记为下线! 谣言谣言, 说的人多了就成的真的了.
转移: 通过epoch机制来实现. 有2个纪元 currentEpoch 和 configEpoch. 其中currentEpoch是当slave发现master挂掉后, slave给其它master发送让其选择该slave为master. 如果该slave得到过半master的意见(同意该slave成为master), 就升级为master. 所有的master同一个currentEpoch只能投票一次. 形象点解释就是: 每一轮, 各个slave去找所有的master讨票, 讨的票过半了,就当选了. 如果这一轮没有讨到过半支持的, 就开启下一轮!
高并发
redis本身是采用的单线程模型,避免了并发控制,锁的开销等.
风险: 对于大key,大value 耗时较长, 可能会阻塞redis (由于单线程串行执行命令,就会造成其它命令超时)
高QPS
数据一致性
只保证数据的最终一致性. 因为其定位是 高性能 的缓存系统,所以牺牲了主从数据的强一致性. 如果想强一致, 需要强制读master.
常见问题有哪些
大key
扩展性成为瓶颈
例如,大key撑满整个分片的容量,无法通过扩分片解决
全量读取会堵塞redis
例如, 大key的全量读,造成堵塞,响应时间增长到200ms以上
最佳实践
1. 集合类型(Hash、List、Set、Zset)的数据,打散到N个key中,保证每个key元素个数不超过50000个
大key打散到各个节点,便于扩展
2. 禁止对元素数量超过10000个的key进行全量读取(包括hgetall、smembers、lrange 0 -1、 zrange 0 -1)
避免慢查询堵塞redis
3. 及时对key中元素进行清理,尤其是用来做队列的业务场景,消费者挂掉数据就会堆积。(类似场景推荐使 用组件:Mafka)
避免产生大key
热点key
导致QPS不均
例如,热点key,导致其所在分片的QPS远高于其他分片
最佳实践
小容量热key的读
• 做本地缓存,利用应用服务器本身的内存空间
• 存多个副本,key名不同,将流量打散到各个节点
大容量热key的读
• 拆成多个key,将流量打散到各个节点
热key的写
DBA限流
通过运营提早发现,提早治理,防患于未然
其他
路由策略开启master-slave
做好降级方案
缓存过期与淘汰
合理设置过期时间
使用increase导致无过期时间的key存满整个redis内存空间
缓存穿透
大量key同时过期,引起缓存穿透,对DB产生巨大压力
最佳实践
非持久化的业务数据,一定要合理设置过期时间,尤其是集合类型(Hash、List、Set这些)
• 节省内存开销
• 容量越小稳定性越高
主动更新缓存,不要同时过期大量key
• 避免缓存穿透、雪崩
对响应时间敏感的应用,即使开启了淘汰策略,也应当保持集群不要写满
• 保证性能稳定