分布式Redis深度历险-复制

摘要

Redis深度历险分为两个部分,单机Redis和分布式Redis。本文为分布式Redis深度历险系列的第一篇,主要内容为Redis的复制功能。Redis的复制功能的作用和大多数分布式存储系统一样,就是为了支持主从设计,主从设计的好处有以下几点:读写分离,提高读写性能数据备份,减少数据丢失的风险高可用,避免单点故障旧版复制实现Redis的复制主要分为同步和命令传播两个步骤:同步可以理解为全量,是将主

Redis深度历险分为两个部分,单机Redis和分布式Redis。

本文为分布式Redis深度历险系列的第一篇,主要内容为Redis的复制功能。

Redis的复制功能的作用和大多数分布式存储系统一样,就是为了支持主从设计,主从设计的好处有以下几点:

  • 读写分离,提高读写性能
  • 数据备份,减少数据丢失的风险
  • 高可用,避免单点故障
《分布式Redis深度历险-复制》

旧版复制实现

Redis的复制主要分为同步和命令传播两个步骤:

同步可以理解为全量,是将主服务器某一时刻的所有数据全部同步到从服务器。

命令传播可以理解为增量,当主服务器数据被修改时,主服务器向从服务器发送对应的数据修改命令。

同步

同步分为以下几个步骤:

1.从服务器向主服务器发送 SYNC 命令(执行 SLAVE OF 命令的第一步也会执行 SYNC 

2.主服务器在收到从服务器命令时,会执行 BGSAVE ,也就是新开一个子进程将内存中的数据保存到RDB文件中。同时使用一个内存缓冲区记录从现在开始执行的写命令,该内存缓冲区的作用就是记录RDB文件生成期间的增量。

3.向从服务器发送RDB文件

4.将缓冲区中的写命令发送给从服务器

同步可以分为两种情况,一种是从服务器第一次连接主服务器,另一种是从服务与主服务器的网络链接断开了,重新连上主服务器并重新同步。

命令传播

命令传播实现逻辑比较简单,当主服务器执行了写命令后,为了保证从服务器与主服务器数据的一致性,主服务器会将写命令发送给从服务器,从服务器执行完收到的写命令后其数据就能和主服务器保持一致了(当然会有延时),注意,从服务器对于客户端来说是只读的,因此从服务器的所有数据都是来自于主服务器的同步or命令传播。

旧版复制存在的问题

假设Redis主从服务器之间的网络环境不太可靠,我们来看看上述复制方法会出现什么问题。假设有主服务器A和从服务器B,主服务器中目前存在1-10000共一万条数据。

1.初始连接,从服务器第一次从主服务器同步数据,同步完成后,从服务器也有1-10000共一万条数据。

2.主服务器新增10001,10002两条数据

3.通过命令传播,从服务器也新增10001,10002两条数据

4.这时候主从服务器之间的网络断开

5.主服务器新增数据10003,因为网络断开,所以从服务器感受不到数据变化

6.网络恢复,从服务器重新连接上主服务器,并发送SYNC命令,进行同步操作

7.主服务器将所有数据发送给从服务器(1-10003)

从上述步骤中可以看到,当从服务器重新连接上主服务器时,会重新进行全量同步,造成大量不必要的IO开销,如果网络环境不稳定时,会导致主服务器一直将内存中的数据写到磁盘再发送给从服务器。

新版复制实现

为了解决老版复制问题,Redis2.8对于复制功能进行了优化。实现如下:

1.主服务器会维护一个偏移量,每次向服务器传播N个字节的数据时,该偏移量就会加上N,比如说一开始是0,接受到一条set key1 value1 后,其偏移量就为13(真实偏移可能不是13,只是举个例子)。//这里可能要看下代码确认

2.从服务器也维护一个偏移量,当从服务器收到到主服务器的N个字节数据时,该偏移量会加上N。

3.主服务器维护一个固定大小的缓冲区,每次接受到客户端写命令后,都会将对应 命令 往这个缓冲区写入。当写入内容超出固定大小后,会覆盖原来的数据。

4.主服务器有一个唯一id

5.从服务器连接上主服务时,会向主服务器发送上一次连接的主服务器的id以及偏移量,这里又分几种情况:

  1. 如果从服务器没传id或者id与当前主服务器不匹配,那主服务器将传送全量数据
  2. 如果从服务器的offset在缓冲区中不能找到(落后太多导致缓冲区已经被新数据覆盖了),那也会进行全量同步
  3. 如果offset能在缓冲区找到,则主服务从offset开始,将缓冲区的数据依次发送给从服务器。(有做pipeline的优化吗)

以上就是新版复制的大致思路,要注意的是,主服务器缓冲区的大小设置很关键,如果设置的太大会导致空间浪费,如果太小会导致网络环境不好时,其退化为老版复制。

之前我就踩过这样的坑:在上云时,redis集群在两个不同机房,主从之前网络环境不太稳定,而redis机器上存储的value比较大,很容易就将缓冲区占满导致每次全量同步,形成恶性循环,从服务器落后不可读,主服务器不可写(当从Redis落后太多时,主Redis将拒绝写入,具体参数可以配置的,下文还会提到)

所以建议将缓冲区大小设置为 平均重连间隔*每秒写入数据量*2

主从心跳机制

从服务器默认会每秒一次的频率向主服务器发送心跳: 
REPLCONF AÇK <replication_offset> , 
replication_offset代表从服务器当前的复制偏移量。

心跳有三个作用:

1.检测主从服务器的网络连接

2.实现min-slaves功能

3.检测命令丢失

检测主从服务器的网络连接

主服务器会记录从服务器上次发送心跳是什么时间,根据这个时间,我们能知道主从服务器之间的连接是不是出现了故障

实现min-slaves功能

Redis为了保证数据的安全性,可以配置当从服务器小于 min-slaves-to-write 个或者 min-slaves-to-write 个从服务器的延迟都大于等于 min-slaves-max-lag 时,主服务器拒绝写。

检测命令丢失

主从之间的复制,其实是以主服务器作为从服务器的客户端来实现的(在Redis中,所有服务器之间的数据传递都是以该种方式)。假设主服务器向从服务器发送一条写命令,但网络出现异常,从服务器并没有收到该命令。


这就会导致数据不一致的状态(你可能想主服务器发送命令时,如果从没返回失败,进行重发不就好了吗?如果说从成功执行了命令,但是再回复主的时候出现了问题,那主如果重发就会造成数据异常了)。所以主服务器会根据心跳信息来决定要发送的数据。看个例子:

初始,主服务器和从服务器偏移量都是100。

主服务器收到客户端的写命令,将偏移量改成110,同时向从服务器发送写命令,但因网络原因,从服务器并没有收到,其偏移量仍然是100。主服务器根据心跳发现从服务器的偏移量是100落后于自己,所以会将100-110的数据进行重发。

看到这里,你可能对于上述方案的正确性感到质疑:在从服务器接收到100-110的数据前,它发送心跳包告诉主服务器自己当前偏移为100,然后接收到了100-110的数据。这时下个心跳还没发出,主服务器认为从服务器落后于自己,再次发送100-110的数据,导致从服务器再次写入100-110的数据,导致数据异常!

如果你有想到这个问题,说明你是有在认真思考了~

其实是不存在这种情况的,原因是redis是 单线程 的!记住 单线程 三个字,再回头看一遍问题描述,相信你能想明白~

原文: Java架构笔记

Image placeholder
许炳师
未设置
  53人点赞

没有讨论,发表一下自己的看法吧

推荐文章
一个简单的基于 Redis 的分布式任务调度器 —— Java 语言实现

折腾了一周的JavaQuartz集群任务调度,很遗憾没能搞定,网上的相关文章也少得可怜,在多节点(多进程)环境下Quartz似乎无法动态增减任务,恼火。无奈之下自己撸了一个简单的任务调度器,结果只花了

深入浅出百亿请求高可用Redis(codis)分布式集群揭秘

摘要:作为noSql中的kv数据库的王者,redis以其高性能,低时延,丰富的数据结构备受开发者青睐,但是由于redis在水平伸缩性上受限,如何做到能够水平扩容,同时对业务无侵入性是很多使用redis

Go语言高级编程_6.1 分布式id生成器

6.1分布式id生成器 有时我们需要能够生成类似MySQL自增ID这样不断增大,同时又不会重复的id。以支持业务中的高并发场景。比较典型的,电商促销时,短时间内会有大量的订单涌入到系统,比如每秒10w

Go语言高级编程_6.2 分布式锁

6.2分布式锁 在单机程序并发或并行修改全局变量时,需要对修改行为加锁以创造临界区。为什么需要加锁呢?我们看看在不加锁的情况下并发计数会发生什么情况: packagemain import( "sy

Go语言高级编程_6.4 分布式搜索引擎

6.4分布式搜索引擎 在Web一章中,我们提到MySQL很脆弱。数据库系统本身要保证实时和强一致性,所以其功能设计上都是为了满足这种一致性需求。比如writeaheadlog的设计,基于B+树实现的索

Go语言高级编程_6.6 分布式配置管理

6.6分布式配置管理 在分布式系统中,常困扰我们的还有上线问题。虽然目前有一些优雅重启方案,但实际应用中可能受限于我们系统内部的运行情况而没有办法做到真正的“优雅”。比如我们为了对去下游的流量进行限制

Go语言高级编程_6.7 分布式爬虫

6.7分布式爬虫 互联网时代的信息爆炸是很多人倍感头痛的问题,应接不暇的新闻、信息、视频,无孔不入地侵占着我们的碎片时间。但另一方面,在我们真正需要数据的时候,却感觉数据并不是那么容易获取的。比如我们

滴滴 曾奇:谈谈我所认识的分布式锁

桔妹导读:随着计算机技术和工程架构的发展,微服务变得越来越热。如今,绝大多数服务都处于分布式环境中,其中,数据一致性是我们一直关注的重点。分布式锁到底是什么?经过了哪些发展演进?工程上有哪些实现方案?

从关系型数据库到分布式机器学习,揭秘腾讯大数据十年发展历程

大数据技术在过去10多年中极大改变了企业对数据的存储、处理和分析方式。如今,大数据技术逐渐成熟,涵盖了计算、存储、数仓、数据集成、可视化、NOSQL、OLAP分析、机器学习等丰富领域。在未来,大数据技

云原生时代,分布式系统设计必备知识图谱(内含22个知识点)

作者|杨泽强(竹涧)阿里云技术专家我们身处于一个充斥着分布式系统解决方案的计算机时代,无论是支付宝、微信这样顶级流量产品、还是区块链、IOT等热门概念、抑或如火如荼的容器生态技术如Kubernetes

中国移动智能硬件质量报告解读 分布式路由市场你了解多少?

今年6月份,中国移动终端实验室发布了《中国移动2019年智能硬件质量报告》(第一期),并于近日对该报告进行了相关解读,同时对优秀智能硬件产品进行颁奖。根据介绍,本次报告在内容上主要包括手机产品综合评测

分布式时序数据库QTSDB的设计与实现

现有的开源时序数据库influxdb只支持单机运行,在面临大量数据写入时,会出现查询慢,机器负载高,单机容量的限制。为了解决这一问题,360基础架构团队在单机influxdb的基础上,开发了集群版——

10分钟搞懂:亿级用户的分布式数据存储解决方案!

来源:IT进阶思维原创,转载请注明原出处内容提供:李智慧,前阿里巴巴技术专家,《大型网站技术架构》作者6月6日晚,林志玲与Akira公布婚讯、徐蔡坤祝福高考同学超常发挥,粉丝们百万的转发和点赞造成微博

干货 | 揭秘京东数科强一致、高性能的分布式事务中间件JDTX

导读:在分布式数据库、云原生数据库、NewSQL等名词在数据库领域层出不穷的当今,变革——在这个相对稳定的领域已愈加不可避免。相比于完全革新,渐进式增强的方案在拥有厚重沉淀的行业则更受青睐。同所有分布

为什么分布式网络是一种新兴趋势?

互联网的大规模采用可归功于以下五个重要因素:TCP/IPTCP/IP(传输控制协议/Internet协议)是指Internet上使用的标准数据通信协议集。它由DARPA开发,并由互联网工程任务组(IE

分布式存储时代,横空出世的OceanBase

数据,被誉为新时代的石油。几乎任何一个企业的IT管理者,都会在演讲、采访或其他形式的交流分享中强调数据的重要性。获取洞察、行为预测、市场分析、业务转型升级……数据能够为企业带来巨大的商业价值。但与此同

快看,我们的分布式缓存就是这样把注册中心搞崩塌

写公众号两年以来,每当有机会写故障类主题的时候,我都会在开始前静静地望着显示器很久,经过多次煎熬和挣扎之后才敢提起笔来,为什么呢?因为这样的话题很容易招来吐槽,比如“说了半天,不就是配置没配好吗?”,

分布式事务实战

引言:微服务倡导将复杂的单体应用拆分为若干个功能简单、松耦合的服务,这样可以降低开发难度、增强扩展性、便于敏捷开发,从而被越来越多的开发者和公司推崇运用。但系统微服务化后,一个看似简单的功能,内部可能

基于 Zookeeper 的分布式锁实现

1.背景最近在学习Zookeeper,在刚开始接触Zookeeper的时候,完全不知道Zookeeper有什么用。且很多资料都是将Zookeeper描述成一个“类Unix/Linux文件系统”的中间件

《从PPTV网络视频,到PPIO区块链分布式存储》

摘要:2019年11月26日,同济创业谷与PPIOCodeTalks联合举办了《创新X-区块链与创新创业》区块链技术分享会,本期我们为读者带来主题分享--《从PPTV网络视频,到PPIO区块链分布式存

分布式场景下Kafka消息顺序性的思考

在业务中使用kafka发送消息异步消费的场景,并且需要实现在消费时实现顺序消费,利用kafka在partition内消息有序的特点,实现消息消费时的有序性。1、在发送消息时,通过指定partition

如果有人再问你怎么实现分布式延时消息,这篇文章丢给他

1.背景上篇文章介绍了RocketMQ整体架构和原理有兴趣的可以阅读一下,在这篇文章中的延时消息部分,我写道开源版的RocketMQ只提供了18个层级的消息队列延时,这个功能在开源版中显得特别鸡肋,但

10 分钟彻底理解 Redis 的持久化和主从复制

在这篇文章,我们继续有关Redis方面知识的学习,一起了解一下其中一个非常重要的内容:Redis的持久化机制。什么是Redis持久化?Redis作为一个键值对内存数据库(NoSQL),数据都存储在内存

PostgreSQL DBA(31) – Backup&Recovery#4(搭建流复制)

PostgreSQL通过流复制StreamingReplication可轻松实现高可用HA环境的搭建.本节简单介绍了搭建流复制环境的基本步骤.Step1主库:创建用户 创建复制用户replicator

深度解读当代前端架构演进与趋势(上)

软件架构的核心思想,就是推断软件系统各个组件之间数据流动的方式。软件架构的质量取决于你设法推断这些数据流的难易程度!本文要讲的内容,就是在今天的Web应用程序背后探索这些数据流和最终的体系结构。We