分布式基础概念 - 分布式缓存 [2]
分布式缓存寻址算法
hash 算法:
根据 key 进行 hash 函数运算、结果对分片数取模,确定分片适合固定分片数的场景。
扩展分片或者减少分片时,所有数据都需要重新计算分片、存储
一致性 hash:
将整个 hash 值得区间组织成一个闭合的圆环,计算每台服务器的 hash 值、映射到圆环中。使用相同的 hash 算法计算数据的 hash 值,映射到圆环,顺时针寻找,找到的第一个服务器就是数据存储的服务器。
新增及减少节点时只会影响节点到他逆时针最近的一个服务器之间的值存在 hash 环倾斜的问题,即服务器分布不均匀,可以通过虚拟节点解决
hash slot:
将数据与服务器隔离开,数据与 slot 映射,slot 与服务器映射,数据进行 hash 决定存放的 slot
新增及删除节点时,将 slot 进行迁移即可
Redis 的持久化机制
RDB
RDB:Redis DataBase 将某一个时刻的内存快照(Snapshot),以二进制的方式写入磁盘。
手动触发:
save 命令,使 Redis 处于阻塞状态,直到 RDB 持久化完成,才会响应其他客户端发来的命令,所以在生产环境一定要慎用
bgsave 命令,fork 出一个子进程执行持久化,主进程只在 fork 过程中有短暂的阻塞,子进程创建之后,主进程就可以响应客户端请求了
自动触发:
save m n:在 m 秒内,如果有 n 个键发生改变,则自动触发持久化,通过 bgsave 执行,如果设置多个、只要满足其一就会触发,配置文件有默认配置(可以注释掉)
flushall:用于清空 redis 所有的数据库,flushdb 清空当前 redis 所在库数据(默认是 0 号数据库),会清空 RDB 文件,同时也会生成 dump.rdb、内容为空
主从同步:全量同步时会自动触发 bgsave 命令,生成 rdb 发送给从节点
优点:
整个 Redis 数据库将只包含一个文件 dump.rdb,方便持久化。
容灾性好,方便备份。
性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,所以是 IO 最大化。使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 redis 的高性能
相对于数据集大时,比 AOF 的启动效率更高。
缺点:
数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候)
由于 RDB 是通过 fork 子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是 1 秒钟。会占用 cpu
AOF
AOF:Append Only File 以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录,调操作系统命令进程刷盘
所有的写命令会追加到 AOF 缓冲中。
AOF 缓冲区根据对应的策略向硬盘进行同步操作。
随着 AOF 文件越来越大,需要定期对 AOF 文件进行重写,达到压缩的目的。
当 Redis 重启时,可以加载 AOF 文件进行数据恢复。
同步策略:
每秒同步:异步完成,效率非常高,一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失
每修改同步:同步持久化,每次发生的数据变化都会被立即记录到磁盘中,最多丢一条
不同步:由操作系统控制,可能丢失较多数据
优点:
数据安全
通过 append 模式写文件,即使中途服务器宕机也不会破坏已经存在的内容,可以通过 redis-check-aof 工具解决数据一致性问题。
AOF 机制的 rewrite 模式。定期对 AOF 文件进行重写,以达到压缩的目的
缺点:
AOF 文件比 RDB 文件大,且恢复速度慢。
数据集大的时候,比 rdb 启动效率低。
运行效率没有 RDB 高
AOF 文件比 RDB 更新频率高,优先使用 AOF 还原数据。AOF 比 RDB 更安全也更大 RDB 性能比 AOF 好如果两个都配了优先加载 AOF
也可参考对线面试官系列文章:
https://mp.weixin.qq.com/s/SSYCYJKpTjsFvpwb0r4zqQ
Redis 单线程为什么这么快
Redis 基于 Reactor 模式开发了网络事件处理器、文件事件处理器 file event handler。它是单线程的,所以 Redis 才叫做单线程的模型,它采用 IO 多路复用机制来同时监听多个 Socket,根据 Socket 上的事件类型来选择对应的事件处理器来处理这个事件。可以实现高性能的网络通信模型,又可以跟内部其他单线程的模块进行对接,保证了 Redis 内部的线程模型的简单性。
文件事件处理器的结构包含 4 个部分:多个 Socket、IO 多路复用程序、文件事件分派器以及事件处理器(命令请求处理器、命令回复处理器、连接应答处理器等)。
多个 Socket 可能并发的产生不同的事件,IO 多路复用程序会监听多个 Socket,会将 Socket 放入一个队列中排队,每次从队列中有序、同步取出一个 Socket 给事件分派器,事件分派器把 Socket 给对应的事件处理器。
然后一个 Socket 的事件处理完之后,IO 多路复用程序才会将队列中的下一个 Socket 给事件分派器。文件事件分派器会根据每个 Socket 当前产生的事件,来选择对应的事件处理器来处理。
Redis 启动初始化时,将连接应答处理器跟 AE_READABLE 事件关联。
若一个客户端发起连接,会产生一个 AE_READABLE 事件,然后由连接应答处理器负责和客户端建立连接,创建客户端对应的 socket,同时将这个 socket 的 AE_READABLE 事件和命令请求处理器关联,使得客户端可以向主服务器发送命令请求。
当客户端向 Redis 发请求时(不管读还是写请求),客户端 socket 都会产生一个 AE_READABLE 事件,触发命令请求处理器。处理器读取客户端的命令内容,然后传给相关程序执行。
当 Redis 服务器准备好给客户端的响应数据后,会将 socket 的 AE_WRITABLE 事件和命令回复处理器关联,当客户端准备好读取响应数据时,会在 socket 产生一个 AE_WRITABLE 事件,由对应命令回复处理器处理,即将准备好的响应数据写入 socket,供客户端读取。
命令回复处理器全部写完到 socket 后,就会删除该 socket 的 AE_WRITABLE 事件和命令回复处理器的映射。
单线程快的原因:
纯内存操作
核心是基于非阻塞的 IO 多路复用机制
单线程反而避免了多线程的频繁上下文切换带来的性能问题
也可参考对线面试官系列文章:
https://mp.weixin.qq.com/s/SSYCYJKpTjsFvpwb0r4zqQ
说一下你知道的 redis 高可用方案
主从
哨兵模式:
sentinel,哨兵是 redis 集群中非常重要的一个组件,主要有以下功能:
集群监控:负责监控 redis master 和 slave 进程是否正常工作。
消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。
哨兵用于实现 redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。
故障转移时,判断一个 master node 是否宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举
即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的
哨兵通常需要 3 个实例,来保证自己的健壮性。
哨兵+ redis 主从的部署架构,是不保证数据零丢失的,只能保证 redis 集群的高可用性。
对于哨兵+ redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练。
Redis Cluster 是一种服务端 Sharding 技术,3.0 版本开始正式提供。采用 slot(槽)的概念,一共分成 16384 个槽。将请求发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执行
方案说明
通过哈希的方式,将数据分片,每个节点均分存储一定哈希槽(哈希值)区间的数据,默认分配了 16384 个槽位
每份数据分片会存储在多个互为主从的多节点上
数据写入先写主节点,再同步到从节点(支持配置为阻塞同步)
同一分片多个节点间的数据不保持强一致性
读取数据时,当客户端操作的 key 没有分配在该节点上时,redis 会返回转向指令,指向正确的节点
扩容时需要需要把旧节点的数据迁移一部分到新节点
在 redis cluster 架构下,每个 redis 要放开两个端口号,比如一个是 6379,另外一个就是加 1w 的端口号,比如 16379。
16379 端口号是用来进行节点间通信的,也就是 cluster bus 的通信,用来进行故障检测、配置更新、故障转移授权。cluster bus 用了另外一种二进制的协议,gossip 协议,用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间。
优点
无中心架构,支持动态扩容,对业务透明
具备 Sentinel 的监控和自动 Failover(故障转移)能力
客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
高性能,客户端直连 redis 服务,免去了 proxy 代理的损耗
缺点
运维也很复杂,数据迁移需要人工干预
只能使用 0 号数据库
不支持批量操作(pipeline 管道操作)
分布式逻辑和存储模块耦合等
Redis Sharding 是 Redis Cluster 出来之前,业界普遍使用的多 Redis 实例集群方法。其主要思想是采用哈希算法将 Redis 数据的 key 进行散列,通过 hash 函数,特定的 key 会映射到特定的 Redis 节点上。Javaredis 客户端驱动 jedis,支持 Redis Sharding 功能,即 ShardedJedis 以及结合缓存池的 ShardedJedisPool
优点:
优势在于非常简单,服务端的 Redis 实例彼此独立,相互无关联,每个 Redis 实例像单服务器一样运行,非常容易线性扩展,系统的灵活性很强
缺点
由于 sharding 处理放到客户端,规模进一步扩大时给运维带来挑战。客户端 sharding 不支持动态增删节点。服务端 Redis 实例群拓扑结构有变化时,每个客户端都需要更新调整。连接不能共享,当应用规模增大时,资源浪费制约优化
也可参考对线面试官系列文章:
https://mp.weixin.qq.com/s/2HoOd_d6tLFWQi1BpopSyw
如有问题,欢迎加微信交流:w714771310,备注- 技术交流 。或关注微信公众号【码上遇见你】。
版权声明: 本文为 InfoQ 作者【派大星】的原创文章。
原文链接:【http://xie.infoq.cn/article/a4b8989fd0134d0aefc5405b9】。
本文遵守【CC BY-NC-ND】协议,转载请保留原文出处及本版权声明。
评论