11.7 Redis哨兵和高可用
- 哨兵出现的原因
- Redis的主从复制模式下,一旦主节点由于故障不能提供服务,需要手动将从节点晋升为主节点,同时还要通知客户端更新主节点地址
- Sentinel哨兵是Redis官方提供的高可用方案,可以用它来监控多个Redis服务实例的运行情况
11.7.1 哨兵功能与作用
-
监控(monitoring):
- Sentinel会不断的检查你的主服务器和从服务器是否运作正常
- 哨兵属于多对多监控,一个哨兵可以监控所有的节点
- 一个数据节点也可以被多个哨兵所监控
-
提醒(Notifation):
- 当节点发生故障时,会对运维人员进行提醒
- 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
-
自动故障转移(Automatic failover):
-
当哨兵发现其中的节点宕机后,如果这个节点是,会自动选举备用节点成为新的主节点
-
当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器;
-
当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
11.7.2 哨兵工作原理
- 在redis sentinel中,一共有3个定时任务,通过这些任务,来发现新增节点和节点的状态
- 每10秒每个sentinel节点对master节点和slave节点执行info操作
- 每2秒每个sentinel节点通过master节点的channel(sentinel:hello)交换信息
- 每1秒每个sentintel节点对master节点和slave节点以及其余的sentinel节点执行ping操作
- 主观下线(SDOWN):当前sentintel节点认为某个redis节点不可用
- 如果一个实例(instance)距离最后一次有效回复PING命令的时间超过down-after-milliseconds所指定的值,那么这个实例会被Sentinel标记为主观下线。
- 如果一个主服务器被标记为主观下线,那么正在监视这个主服务器的所有Sentinel节点,要以每秒一次的频率确认主服务器的确进入了主观下线状态
- 客观下线(ODOWN)一定数量sentinel节点认为某个redis节点不可用
- 如果一个主服务器被标记为主观下线,并且有足够数量的Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断,那么这个主服务器被标记为客观下线。
- 在一般情况下,每个Sentinel会以每10秒一次的频率,向它已知的所有主服务器和从服务器发送INFO命令。当一个主服务器被Sentinel标记为客观下线时,Sentinel向下线主服务器的所有从服务器发送INFO命令的频率,会从10秒一次改为每秒一次。
- Sentinel和其他Sentinel协商主节点的状态,如果主节点处于SDOWN状态,则投票自动选出新的主节点。将剩余的从节点指向新的主节点进行数据复制
- 注意
- 当没有足够数量的Sentinel同意主服务器下线时,主服务器的客观下线状态就会被移除
- 当主服务器重新向Sentinel的PING命令返回有效回复时,主服务器的主观下线状态就会被移除
11.7.3 故障转移流程
-
发现master出现故障
- 在 redis 集群中,当 sentinel 检测到 master(redis 主服务)出现故障,那么 sentinel 需要对集群进行故障转移。
-
确认master下线
-
哨兵选举
- 当哨兵发现主节点客观下线,开始进行哨兵Master选举,谁优先发现主节点下线并把它设置为主观下线的哨兵会拥有选举权
-
Master选举
- 由刚刚的那个哨兵去进行故障转移,将原来连接已客观下线 master 最优的一个 slave 提升为新 master 角色。旧 master 如果重新激活,它将被降级为 slave
- 选择slave-priority最高的slave节点
- 选择复制偏移量最大的节点
- 选runId最小的(启动最早)
-
主从节点的状态更换
- 选举出新的master节点,其余的节点变更为新的master节点的slave节点
- 原有的master节点重新上线,成为新的master节点的slave节点
-
通知客户端
- 当所有节点配置结束后,sentinel会通知客户端节点变更信息。
- 客户端连接新的master节点
11.7.4 哨兵环境搭建
-
搭建多台计算机的从主集群
Host | 端口 | 节点分类 | Sentinel |
---|
192.168.58.161 | 20601 | master | 20600 |
192.168.58.162 | 20601 | slave | 20600 |
192.168.58.163 | 20601 | slave | 20600 |
11.7.5 Redis的高可用
-
高可用的技术内容
-
对高可用技术的作用和解决了什么问题的理解
- 持久化:持久化是最简单的高可用方法。它的主要作用是数据备份,即将数据存储在硬盘,保证数据不会因进程退出而丢失。
- 复制:复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的。
- 复制主要实现了数据的多机备份以及对于读操作的负载均衡和简单的故障恢复。
- 缺陷是故障恢复无法自动化、写操作无法负载均衡、存储能力受到单机的限制。
- 哨兵:在复制的基础上,哨兵实现了自动化的故障恢复。缺陷是写操作无法负载均衡,存储能力受到单机的限制。
- 集群:通过集群,Redis解决了写操作无法负载均衡以及存储能力受到单机限制的问题,实现了较为完善的高可用方案
-
集群设计思想
- cluster可以说是sentinel和主从模式的结合体,通过cluster可以实现主从和master重选功能
- 不同节点分别管理不同的key
- 同一个Key的操作只让一个master去处理
- 为了保证master节点的(单点故障和效率)问题,每个主节点至少准备一个slave节点
- 集群是一个可以在多个 Redis 节点之间进行数据共享的设施
- 集群不支持那些需要同时处理多个键的 Redis 命令
11.8 一致性Hash⭐️
11.8.1 数据分片(sharding)
- 传统的对数据存储的方式—数据分片
- 分布式数据存储时,经常要考虑数据分片,避免将大量的数据放在单表或单库中,造成查询等操作的耗时过长。比如,存储订单数据时使用三个mysql库(编号0,1,2),当一条订单数据过来时,对订单id求hash后与机器数量取模,hash(orderId) % 3,假如得到的结果是2,则这条数据会存储到编号为2的mysql中。分表分库存储时,根据数据库的主键或唯一键做hash,然后跟数据库机器的数量取模,从而决定该条数据放在哪个库
- 数据分片存在的问题
- 根据机器数量取模就会存在一个问题,当机器不够用需要扩容或机器宕机,机器的数量就会发生变化,造成数据的命中率下降,所以之前的数据就需要重新hash做一次sharding。这种操作会导致服务在一定的时间不可用,而且每次扩缩容都会存在这个问题
11.8.2 算法原理
-
对一致性Hash的理解
- 一致性hash算法主要应用于分布式存储系统中,可以有效地解决分布式存储结构下普通余数Hash算法带来的伸缩性差的问题,可以保证在动态增加和删除节点的情况下尽量有多的请求命中原来的机器节点
- 一致性哈希算法的出现,避免了大量数据的迁移(交普通哈希算法而言),解决了普通哈希算法取模动态调整带来的全量数据的变动
-
算法原理
- 一致性Hash算法也是使用取模的方法,只是,刚才描述的取模法是对服务器的数量进行取模,而一致性Hash算法是对2^ 32-1取模,简单来说,一致性Hash算法将整个Hash值控件组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1取模(即哈希值是一个32位无符号整型)
- 取模
- 一致性的Hash算法是对 2的32方 取模
- 整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、5、6……直到2^32-1
- 这个由2^32个点组成的圆环称为Hash环
- 服务器
- 将各个服务器使用Hash进行一个哈希,这样每台机器就能确定其在哈希环上的位置
- 数据
- 数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置
- 定位
- 沿环顺时针“行走”,第一台遇到的服务器就是数据应该定位到的服务器
-
一致性Hash解决的问题
- 通过一致性Hash算法后落到环上的机器,负责管理一个范围,当某台机器宕机的时候,仅仅是这个范围内的数据不可用,不会造成因为服务器数量的改变,再次重新分配的情况
-
如何判定哪个key的数据落到了哪个服务器上
- 如何通过数据 key 找到对应的服务器
- 我们约定,通过数据 key 的哈希值落在哈希环上的节点,如果命中了机器节点就落在这个机器上,否则落在顺时针直到碰到第一个机器。如下图所示 : A 的哈希值落在了 D2 节点的前面,往下找落在了 D2 机器上,D的哈希值 在 D1 节点的前面,往下找到了 D1 机器,B的哈希值刚好落在了D1 节点上,其它依次类推。如下图所示:
11.8.3 算法容错性
- 理解
- 通过一致性Hash算法后落到环上的机器,负责管理一个范围,当某台机器宕机的时候,仅仅是这个范围内的数据不可用,不会造成因为服务器数量的改变,再次重新分配的情况
- 这个就是保证了一定的容错性,也是解决了数据分区的问题
11.8.4 数据倾斜和虚拟节点
- 对于一致性Hash算法出现的问题的提出(数据倾斜)
- 均匀一致性hash的目标是如果服务器有N台,客户端的hash值有M个,那么每个服务器应该处理大概M/N个用户的。也就是每台服务器负载尽量均衡
- 一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题
- 一致性哈希算法也是有缺点的,就是数据落到每台机器上的概率不同,可能会出现数据分配不均匀的情况。造成某台服务器压力增大
- 虚拟节点
- 加入虚拟节点,本来一个数据库仅对应一个节点,但是现在将数据库对应多个节点,并将这些节点分布在环上。保证每台服务器上的数据均匀分布
- 为了避免出现数据倾斜问题,一致性 Hash 算法引入了虚拟节点的机制,也就是每个机器节点会进行多次哈希,最终每个机器节点在哈希环上会有多个虚拟节点存在,使用这种方式来大大削弱甚至避免数据倾斜问题
- 同时数据定位算法不变,只是多了一步虚拟节点到实际节点的映射,例如定位到“D1#1”、“D1#2”、“D1#3”三个虚拟节点的数据均定位到 D1 上
- 实际上还是一个节点,虚拟节点只是虚拟出来的,为了保证每台服务器上的数据均匀分布
11.8.5 Redis的Slot槽
- 理解
- Redis集群使用数据分片(sharding)而非一致性哈希(consistencyhashing)来实现
- 一个Redis集群包含16384个哈希槽(hashslot),数据库中的每个键都属于这16384个哈希槽的其中一个,集群使用公式CRC16(key)%16384来计算键key于哪个槽,其中CRC16(key)语句用于计算键key的CRC16校验和
- 过程理解
- 将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞,所以无论是添加新节点还是移除已存在节点,又或者改变某个节点包含的哈希槽数量,都不会造成集群下线。
- 对象保存到Redis之前先经过CRC16哈希到一个指定的Node上
- 每个Node被平均分配了一个Slot段,对应着0-16383,Slot不能重复也不能缺失,否则会导致对象重复存储或无法存储
- Node之间也互相监听,一旦有Node退出或者加入,会按照Slot为单位做数据的迁移
- Node1如果掉线了,0-5640这些Slot将会平均分摊到Node2和Node3上
- Slot槽的优缺点
- 优点
- 将Redis的写操作分摊到了多个节点上,提高写的并发能力,扩容简单
- 缺点
- 每个Node承担着互相监听、高并发数据写入、高并发数据读出,工作任务繁重
十二、ES
12.1 索引
通俗地来讲,正向索引是通过key找value,反向索引则是通过value找key。
12.1.1 正向索引
-
理解
- 以文档的ID为关键字,表中记录文档中每个字的位置信息,查找时扫描表中每个文档中字的信息直到找出所有包含查询关键字的文档
-
优点
- 这种组织方法在建立索引的时候结构比较简单,建立比较方便且易于维护
- 若是有新的文档加入,直接为该文档建立一个新的索引块,挂接在原来索引文件的后面
- 若是有文档删除,则直接找到该文档号文档对应的索引信息,将其直接删除
-
缺点
12.1.2 反向索引
-
理解
- 反向索引(inverted index),一般也被别人称之为倒排索引
- 倒排表以字或词为关键字进行索引,表中关键字所对应的记录表项记录了出现这个字或者词的所有文档
- 一个表项就是一个字段,它记录该文档的ID和字符在该文档中出现的位置情况
-
优点
- 查询的时候由于可以一次得到查询关键字所对应的所有文档,所有查询效率会高于正排序
-
缺点
- 由于每个字或词对应的文档数量在动态变化,所有到排序表的建立和维护都较为复杂
12.1.3 倒排索引的组成
倒排索引主要由单词词典(Term Dictionary)和倒排列表(Posting List)组成。
1. 单词词典(Term Dictionary)
-
理解
- 倒排索引的重要组成,记录所有文档的单词,一般都比较大,记录单词到倒排列表的关联信息
- 单词词典一般用 B+Trees 来实现,存储在内存
2. 倒排列表(PostingList)
-
理解
- 倒排列表记载了出现过某个单词的所有文档的文档列表及单词在该文档中出现的位置信息及频率(作关联性算分),每条记录称为一个倒排项(Posting)
-
列表信息
倒排列表存储在磁盘文件中,主要包含以下信息
- 文档 ID
- 单词频率(TF:Term Frequency)
- 位置(Position)
- 偏移(Offset)
-
单词字段和倒排列表整合在一起的结构如下
12.1.4 索引的更新策略
- 更新索引的原因
- 搜索引擎需要处理的文档集合往往都是动态集合,即在建好初始的索引后,不断有新文档进入系统,同时原先的文档集合内有些文档可能被删除或更改
- 动态索引通过在内存中维护临时索引,可以实现对动态文档和实时搜索的支持
12.2 分词器