共计 5405 个字符,预计需要花费 14 分钟才能阅读完成。
31 事务机制
Redis 提供了 MULTI、EXEC 两个命令来实现事务。
原子性
原子性的要求就是一个事务中的多个操作必须都实现,或者都不实现。
状况 1:在执行 EXEC 命令前,客户端发送的命令有谬误,且 Redis 实例检出了(如语法错误)。
后果:执行 EXEC 时拒绝执行所有命令,返回事务失败。
状况 2:在执行 EXEC 命令前,命令有谬误但 Redis 实例没有检出(如操作数据类型不匹配)。
后果:Redis 会对谬误命令报错,但还是会把正确的命令执行完。
影响:事务的原子性无奈保障。
留神:Redis 没有提供回滚机制。
DISCARD 命令:被动放弃事务执行,把暂存的命令队列清空。
状况 3:执行 EXEC 时实例故障,导致事务执行失败。
后果 1:如果开启了 AOF,会有局部日志记录到 AOF 中,须要应用 redis-check-aof 命令,将未实现的事务操作剔除,保障原子性。
后果 2:如果没有开启 AOF,实例重启后数据无奈复原。
因为 RDB 不会在事务执行时执行,所以 RDB 文件中不会记录只执行了一部分的后果数据。之后用 RDB 复原实例数据,复原的还是事务之前的数据。
一致性
数据库中的数据在事务执行前后是统一的。
状况 1:命令入队时就报错
后果:事务放弃执行,能够保障一致性。
状况 2:命令入队时没报错,执行时报错
后果:谬误命令不会执行,能够保障一致性
解析:统一的概念是数据合乎数据库自身的定义和要求,没有蕴含非法或者有效的谬误数据,只有没有执行谬误的命令,那么就保障了一致性。
状况 3:EXEC 命令执行时实例故障
后果 1:没有开启 RDB 或 AOF,数据失落,能够保障一致性。
后果 2:应用 RDB 快照,RDB 不会在事务中执行,能够保障一致性。
后果 3:应用 AOF 日志,须要应用 redis-check-aof 清理事务中已实现的操作,清理后数据一致性。
总结:Redis 能够保障事务一致性。
隔离性
数据库在执行一个事务时,其它操作无奈存取到正在执行事务拜访的数据。
事务的隔离性受并发操作的影响,分为 EXEC 执行前和执行后两个阶段。
- EXEC 执行前并发:须要应用 WATCH 机制保障隔离性;
- EXEC 执行后并发:能够保障隔离性。
WATCH 机制
在事务执行前,监控一个或多个键的值变动状况,当事务调用 EXEC 命令执行时,WATCH 机制会先查看监控的键是否被其它客户端批改了。
- 如果批改了,就放弃事务执行,防止事务的隔离性被毁坏。
- 客户端能够再次执行事务,如果没有并发批改事务数据的操作了,事务就能失常执行,保障了隔离性。
Redis 是用单线程执行命令,EXEC 命令执行后,Redis 会保障先把命令队列中的所有命令执行完。所以,在这种状况下,并发操作不会毁坏事务的隔离性。
持久性
数据库执行事务后,数据的批改要被长久化保留下来。当数据库重启后,数据的值须要是被批改后的值。
状况 1:未开启 AOF 和 RDB,重启数据失落,没有持久性。
状况 2:RDB 模式,如果在事务执行后,RDB 快照执行前宕机,数据会失落。
状况 3:AOF 三种配置都存在数据失落状况(always 会失落一个事件循环的数据)。
解析:
每次执行客户端命令的时候操作并没有写到 aof 文件中,只是写到了 aof_buf 内存当中,当进行下一个事件循环 (event_loop) 的时候执行 beforeSleep 之时,才会去 fsync 到 disk 中。
论断:Redis 无奈保障事务的持久性。
32 主从同步与故障切换
Redis 的主从同步机制不仅能够让从库服务更多的读申请,分担主库的压力,而且还能在主库产生故障时,进行主从库切换,提供高牢靠服务。
主从数据不统一
主从数据不统一,指的是客户端从库中读取到的值和主库中的最新值不统一。
起因:主从库的命令复制是异步进行的。
- 主库收到新的写命令,发送给从库;
- 主库在本地执行命令后,向客户端返回后果
- 如果从库没有执行命令,主从数据就不统一了
从库滞后执行命令起因:
- 网络传输提早
- 从库阻塞(执行汇合操作等简单命令)
解决方案:内部程序监控
- Redis 的 INFO replication 命令,能够查看主库接管写命令的进度信息(master_repl_offset)和从库复制写命令的进度信息(slave_repl_offset)
- 开发监控程序监控 master_repl_offset 和 slave_repl_offset 的差值,超过阈值客户端不再读该从库
读取过期数据
应用 Redis 主从集群时,有时会读取到过期数据,这是由 Redis 的过期数据删除策略引起的。
Redis 过期数据删除策略:
惰性删除:数据过期后不会立刻删除,而是等到有申请读写该数据时进行查看,发现过期时再删除。
- 长处:缩小 CPU 资源应用。
- 毛病:占用内存。
- 定期删除:每隔一段时间(默认 100ms)随机选出一些数据判断是否过期,删除过期数据。
状况 1:
如果客户端从主库读取过期数据,主库会触发删除操作;
如果客户端从库读取过期数据,从库不会触发删除操作,会返回空值(3.2 以上版本)。
状况 2:
Redis 设置过期工夫命令在从库上可能被延后,此时可能读取到过期数据。
过期工夫命令:
- EXPIRE:设置存活工夫 x 秒
- PEXPIRE:设置存活工夫 x 毫秒
- EXPIREAT:设置过期工夫戳(秒)
- PEXPIREAT:设置过期工夫戳(毫秒)
倡议:
- 在业务利用中应用 EXPIREAT/PEXPIREAT 命令,把数据的过期工夫设置为具体的工夫点,防止读到过期数据。
- 留神主从节点时钟要统一,让主从节点和雷同的 NTP(工夫)服务器进行时钟同步。
不合理配置项
protected-mode 配置项:限定哨兵是否被其它服务器拜访,设置 yes 时哨兵间无奈通信,无奈判断主库下线,造成 redis 不可用。
- 留神将 protected-mode 设置为 no
- bing 配置项设置为其它哨兵实例的 IP 地址
cluster-node-timeout 配置项:设置集群实例响应心跳音讯超时工夫。如果主从且切换工夫较长,会导致实例心跳超时;如切换实例超过半数,会被 Redis Cluster 判断为异样,导致集群挂掉。
- 倡议设置为 10~20 秒
- slave-server-stale-data 配置项:设置从库是否解决数据读写命令,yes 可能解决到过期数据,倡议设置为 no,在主从失去链接或信息同步时,slave 会对除了 INFO 和 SLAVEOF 外的所有命令回复 ”SYNC with master in progress”
- slave-read-only 配置项:从库是否解决写命令(只读),yes 时只能解决读申请,无奈解决写申请。
33 脑裂
脑裂指主从集群中,同时有两个主节点,都能接管读写申请,导致不同客户端向不同主节点写入数据,导致数据失落。
数据失落起因:
从库降级为主库后,原主库和新主库从新进行全量同步,须要清空本地数据,加载新主库的 RDB 文件,切换期间原主库写入的数据就失落了。
查找起因
1. 确认数据同步:
主从集群数据失落最常见起因是主库的数据还没有同步到从库时,主库产生故障,从库降级为主库后,未同步数据失落。
判断办法:计算 master_repl_offset 和 slave_repl_offset 的差值,如果 slave 小于 master,则数据失落是因为同步未实现导致的。
2. 排查客户端操作日志:
如果主从切换后,有客户端仍在和原主库通信,则认为产生了脑裂。
3. 脑裂起因:原主库假故障
主库下线起因:超过(quorum 配置)的哨兵实例和主库心跳都超时了,判断主库主观下线,哨兵开始执行切换。切换实现后,客户端和新主库进行通信。
主库假故障:主库没有响应哨兵心跳,被判断为主观下线,在没有实现主从切换时,又重新处理申请了,此时客户端仍能够和原主库通信,写入数据。
解决方案
1. 限度主库申请解决:
- min-salves-to-write:设置主库能进行数据同步的起码从库数量;
- min-slaves-max-lag:设置了主从库间进行数据复制时,从库给主库发送 ACK 音讯的最大提早(以秒为单位)。
这两个配置项搭配起来应用,别离给它们设置肯定的阈值,假如为 N 和 T。
组合后主库连贯的从库中至多有 N 个从库,和主库进行数据复制时的 ACK 音讯提早不能超过 T 秒,否则,主库就不会再接管客户端的申请了。
倡议:从库有 K 个,能够将 min-slaves-to-write 设置为 K/2+1(如果 K 等于 1,就设为 1),将 min-slaves-max-lag 设置为十几秒(例如 10~20s),在这个配置下,如果有一半以上的从库和主库进行的 ACK 音讯提早超过十几秒,咱们就禁止主库接管客户端写申请。
CAP
应用 CAP 实践来剖析一下课程的内容:
- redis 集群容许脑裂存在,其实是一种可用性高的特色,但不保证数据始终。
- redis 通过设置两个参数,肯定水平上其实是在升高可用性,以提供数据一致性。
- 为什么违心升高可用性?因为那局部的数据会因为主从切换而失落,所以宁愿不可用。
Redis 自身不反对强一致性,因为保障强一致性的代价太大,从 CAP 角度看,就是放弃 C,抉择 A 和 P。
min-slaves-to-write 和 min-slaves-max-lag 的设置,是为了防止主从数据不统一水平减轻。两个参数起作用时,相当于对主库做降级,放弃了 A,抉择 C 和 P。
35 Codis 集群计划
Codis 集群中蕴含了 4 类要害组件。
- codis server:这是进行了二次开发的 Redis 实例,其中减少了额定的数据结构,反对数据迁徙操作,次要负责解决具体的数据读写申请。
- codis proxy:接管客户端申请,并把申请转发给 codis server。
- Zookeeper 集群:保留集群元数据,例如数据地位信息和 codis proxy 信息。
- codis dashboard 和 codis fe:独特组成了集群管理工具。其中,codis dashboard 负责执行集群管理工作,包含增删 codis server、codis proxy 和进行数据迁徙。而 codis fe 负责提供 dashboard 的 Web 操作界面,便于咱们间接在 Web 界面上进行集群治理。
工作流程
- 先应用 codis dashboard 设置 codis server 和 codis proxy 的拜访地址,而后它们开始接管连贯。
- 当客户端要读写数据时,客户端间接和 codis proxy 建设连贯(RESP 交互协定)。
- codis proxy 接管到申请,依据映射关系把申请转发给相应的 codis server 进行解决,解决实现后由 proxy 再返回数据给客户端。
数据分布
- Codis 集群一共有 1024 个 Slot(逻辑槽),手动或主动调配给 codis server。
- 客户端读取数据时,应用 CRC32 算法计算 key 的哈希值,对 1024 取模,对应 slot 编号。
- Slot 和 codis server 的映射关系称为数据路由表(简称路由表),保留在 proxy 和 Zookeeper。
- 实例增减时,路由表被批改,dashbaord 会把新表发给 proxy。
注:Redis Cluster 中,路由表在每个实例上保留一份,变动时须要在所有实例间传递。
集群扩容
减少 server:
Codis 集群依照 Slot 的粒度进行数据迁徙,咱们来看下迁徙的根本流程。
- 在源 server 上,Codis 从要迁徙的 Slot 中随机抉择一个数据,发送给目标 server。
- 目标 server 确认收到数据后,会给源 server 返回确认音讯。这时,源 server 会在本地将方才迁徙的数据删除。
- 第一步和第二步就是单个数据的迁徙过程。Codis 会一直反复这个迁徙过程,直到要迁徙的 Slot 中的数据全副迁徙实现。
同步迁徙:数据发送到目标 server 并执行完的过程中,源 server 阻塞,无奈解决新申请。
异步迁徙:
- 目标 server 收到数据后返回 ACK,示意迁徙实现,源 server 删除数据,不须要等命令执行完。
- 拆分指令:对 bigkey 中每个元素用一条指令迁徙,并设置长期过期工夫,迁徙失败后会过期删除。
减少 proxy:
codis proxy 的拜访连贯信息都会保留在 Zookeeper 上。
当新增了 proxy 后,Zookeeper 上会有最新的拜访列表,客户端也就能够从 Zookeeper 上读取 proxy 拜访列表,把申请发送给新增的 proxy。
可靠性
Codis server 其实就是 Redis 实例,只不过减少了和集群操作相干的命令。
Codis 给每个 server 配置从库,并应用哨兵机制进行监控,当产生故障时,主从库能够进行切换,从而保障了 server 的可靠性。
codis proxy 应用 Zookeeper 集群保留路由表,能够充分利用 Zookeeper 的高可靠性保障来确保 codis proxy 的可靠性。
当 codis proxy 产生故障后,间接重启 proxy 就行。重启后的 proxy,能够通过 codis dashboard 从 Zookeeper 集群上获取路由表,而后,就能够接管客户端申请进行转发了。
计划抉择
- Codis 更成熟稳固
- 单实例客户端改集群,选 Codis 能够防止批改业务利用中的客户端
- Codis 不反对 Redis 新版本 (>3.2.8) 命令和数据类型
- Codis 反对异步迁徙,集群迁徙比拟频繁时优先选择
倡议:
当你有多条业务线要应用 Codis 时,能够启动多个 codis dashboard,每个 dashboard 治理一部分 codis server,同时,再用一个 dashboard 对应负责一个业务线的集群治理,这样,就能够做到用一个 Codis 集群实现多条业务线的隔离治理了。