聊聊数据同步

article/2025/9/11 21:43:22

一、简述

        数据同步,这是一个很宽泛的概念,在互联网或者传统软件公司,一定会遇到数据同步的场景。数据同步一般会遇到的问题诸如同步时延、数据一致性、性能低、强依赖于中间件、失败后无法补偿等。本文笔者试图简要总结下常见的数据同步场景,并对其中一种遇到的场景给一个案例分享。这个案例其实是所有数据同步场景中最简单的一种情况,但是依然走了很多坑,所以记录一下。对于其他中间件比如db/redis/mq的数据同步,底层实现更加优雅,涉及到通信协议和操作系统相关的知识,且每一种都不太一样,后期会再专门总结。

二、为什么要做数据同步?

1、业务需要

       比如说你和第三方系统对接,对方只提供一个数据库视图给你,对于数据的变动,没有所谓本地的触发器或者binlog日志通知你数据变更了,人家也不想开发一个通知机制,只是丢给你一个视图,你自己从视图中拉取所有数据到本地库,做自己的业务逻辑判断;在一个大型分布式系统中,部分核心数据需要做全量拷贝,后面做数据分析和挖掘用户行为,但又不想直接基于你的业务库,因为会影响业务性能;再或者你和你们公司另一个业务部门,有些数据需要从他们库中同步到你本地来;还有更常见的,数据库和缓存的双写一致性等等。

2、高可用

       所谓高可用,有人发明出所谓n个9,也就是说在99.9%还是99.99%的时间里,系统能正常对外提供服务,这对于大型互联网公司,一般要求是至少4个9,如果动不动系统不可用,对公司的损失少则几十万,多则上千万的损失,所以,在超大型分布式架构中,必须做高可用。广义的高可用,总结起来,方案主要有多副本、隔离、限流、熔断、降级、灰度发布与回滚、监控和日志等。其中多副本是很多中间件主从架构的必备方案。

可用性指标计算方式不可用时间(分钟)
99.9%0.1%*365*24*60525.6
99.99%0.01%*365*24*6052.56
99.999%0.001%*365*24*605.256

      对于数据库,做主从提升数据库并发读写性能,分库分表和相关数据库中间件必不可少,你就必须考虑数据库主从库之间数据同步的细节以及相关问题,比如主从时延以及性能,主从数据一致性内部是如何保证的等等;

       对于分布式缓存,如redis,单机redis虽然号称能抗6-10万并发,但是存在单点故障,虽然你可以开启rdb和aof的混合同步快速恢复数据,但是相比于fail over还是逊色不少,单点故障还是会让你整个系统短时间不可用。所以你必须要做主从架构来减轻高并发压力并提升性能的,数据量大的时候,也需要考虑水平扩容,做数据分片存储,每个分片再做主从,又会涉及到很多数据同步的场景;

        对于MQ,也需要保证MQ集群中单点问题导致的系统不可用问题,不论是kafk这种分布式的还是RabbitMQ的镜像集群模式,集群中主从同步的相关问题依然是你必须要考虑到的;

 

3、数据灾备

        假如说你的系统是你公司的核心业务系统,甚至涉及到资金相关的。你没做数据容灾?天啊,太可怕了。数据一旦丢失,不就全完了?你得有n份的数据备份,在主库有宕机时,做主备切换,BAT等大型互联网公司的数据中心,是异地多活的,保证数据不丢,这里面,每时每刻都在发生着数据同步;

 

三、怎么做数据同步?

       千万不要企图寻找一种完全通用的数据同步方案,因为任何方案和技术,都是要根据不同的业务场景和不同的技术去分别讨论的。理论上来说,数据同步很难做到绝对的强一致性,一般情况下都是最终一致性,即允许中间过程短暂的不一致。常见的中间件的数据同步,其中间件本身都有相关的配置参数和对应的架构方案来保证数据同步的数据一致性和尽量低时延。

先给出几种数据库同步的方案:

方案1:分页查询批量插入

适合数量较少,且不需要时时刻刻一致性。实现简单,一般不用;

方案2:触发器增量复制

基于数据库的触发器,当有数据增删改时,将数据放入增量表,然后处理增量数据。比较依赖触发器,假如触发器触发时出现网络问题等情况,会出现少量数据不一致情况,关键是下一次也无法补偿回来。

方案3:基于mysql的binlog日志

可以伪装成一个从库,让mysql把数据同步到虚拟的从库中,不做详细介绍,具体参考阿里的canal中间件,就是基于此原理;

方案4:大数据方案

       现在都是大数据时代了,可以基于BulkLoad的数据同步,比如从hive同步数据到hbase;也可以基于sqoop的全量导入;也可以在HBase中建表,然后Hive中建一个外部表,这样当Hive中写入数据后,HBase中也会同时更新。当然,类似于数据同步这种如此常见的场景,肯定有人已经为你造好了轮子,比如说Debezium+bireme:Debezium for PostgreSQL to Kafka Debezium是一个通过监控数据库的日志变化,通过对行级日志的处理来达到数据同步,而且Debezium 可以通过把数据放入到kafka,这样就可以通过消费kafka的数据来达到数据同步的目的。而且还可以给多个地方进行消费使用。这样,你的数据就可以同步到很多地方去啦!具体参见其github:https://github.com/debezium/debezium 

          然鹅!

          以上牛逼的方案和不牛逼的方案,都不是我们项目的方案,已哭晕在厕所......

         以后有时间会再总结一下数据库及其相关中间件(mycat、Sharding-jdbc)、redis及其代理中间件(如codis)、MQ集群自身的主从同步原理做深入探讨。本文只结合一个实际案例,来总结一下做过的一个数据同步的几点优化。

四、案例分享

1、场景

       我们公司一个项目,需要和第三方的人员进行同步,第三方给了一个他们人员库的视图和数据库连接信息,我们需要连接他们的数据库将人员拉取到我们系统中。且每次都需要找出哪些人被删除了、哪些人需要新增、哪些人需要修改。即需要将第三方库与我们本地库的数据做比对,来保证数据的最终一致性。

        基于某种原因,我不能直接连接我们本地人员库,而只能通过别人暴露出来的CRUD接口来对本地人员库做变更。坑爹啊!先给出最开始的一种比较坑爹的一种方案,复杂而不实用。

方案1:

          本地三张表

                tb_person_recent:最新人员表 -> 存储当前第三方库的所有人员

                tb_person_last:上次人员表 -> 存储上一次人员同步时,第三方库的所有人员

                tb_person_increment:人员增量表 -> 通过存储过程将recent和last表进行逐行全量比对,找出需要增删改三种状态的人员,放入人员增量表。

    整体流程图如下图所示:

         很显然,这种方案最坑爹的地方在于说,人员张三一旦同步失败了,那么如果不进行人为干涉,就永远没机会再添加进来了。

         对于这种方案,我最开始开发时就预感到这种问题,但是项目时间紧张、方案本身也不是我自己设计,将就用了,就自己在人员同步组件中去做补偿。一旦一个人添加失败了,就放入失败表中,下一次人员同步任务时,先处理失败表中的数据,再处理增量表的数据。但是,这种设计,为自己后面埋了很大的坑。这个错误表,会给下一次同步任务造成很多问题,读者可以自己假设多种场景,看看每个场景下会遇到什么问题。

        于是乎,经常遇到人员没同步过来,数据不一致,少了一些人甚至很多人。初期的时候,由于第三方库的连接经常有问题,导致可能数据只拉取了一部分,然后比对的时候,只有一部分人员参与了存储过程的比对。再比如说连接失效了,拉取数据失败了。再比如说人员拉取的自动任务是单线程的,遇到过自动任务没有执行的问题。几乎每周都会遇到人员不一致的情况,头大。

        头大没用,还是要硬着头皮看下问题到底出在哪,由于日志不是很充足,不太容易定位出问题出在存储过程比对还是数据拉取还是数据增删改。所以干脆不优化了,直接放弃这种方案。接下来,就简单分析下,新方案的思路历程。       

        你想啊,上面那个同步方案的最大问题就是这一次同步失败了的人员,下一次居然没办法弥补,必须强行人工来干预。那我们能不能设计出一种方案,每次自动任务都是做全量同步,也就是说,我每次自动任务,把第三方的数据全部拉过来放在内存的一个map1中,我们人员管理服务的数据全部拉过来也放在内存的map2中,然后map1和map2直接代码做比对。

以下是新方案的一个总思路:去存储过程、去last和recent表、内存比对、多线程拉取

方案2

1、先查询第三方视图库的数据总页数n(每页1000条)
2、从线程池中开n个线程任务用于并行执行第1到第n页的数据,每个线程查其中一页
3、将这n个线程拉取的n页的数据汇总(CountDownLatch),放在map中
4、同理,人员管理服务这边也先查有m页,从线程池中开启m个线程任务拉取放在map中
5、两边map比对,找出增删改的数据,分别处理
    第三方map中有,人员管理的map没有--------------------> 要新增
    第三方map中没有,人员管理的map中有-----------------> 要删除
    第三方map和人员管理的map中都有-----------------------> 要更新
6、将第5步中的3种状态的数据添加到增量表中,后续的处理复用以前的代码;

这样做要考虑两个问题:

      1、使用CountDownLatch来协调多个线程,要注意线程创建的数量和上下文切换,线程池参数要调节好;

      2、两边的数据放在内存,jvm和gc参数要适当调整,如果数据量足够大,还是放在redis或者数据库中再比对。

      3、拉取数据的过程要保证全量,一旦有一个线程抛异常,整个任务需要return退出,否则容易出现第三发的人员没拉全,而没拉到的那些人误认为是要删除的,结果全删了。

 

五、总结

          这个方案的主要思路是全量比对,每次都是走全量的比对,能保证我这一次同步失败的人员,下一次只要你程序比对没有逻辑问题,就一定能在之后的同步任务中弥补回来。为了提升拉取数据的性能,使用了分段拉取,实测2万人也只需要4-6s左右。性能较方案1有数十倍的提升。但是随之而来的问题你也要尤其的注意,比如多线程间的同步问题,有一个线程失败了怎么办?线程长期阻塞了怎么办?线程池参数等等问题都要考虑到。如果不在乎性能,笔者建议采用单线程分页拉取所有数据可能更好。

         其次,将存储过程的比对逻辑,写入到代码中去,这样能更好的定制化个性化的同步需求,比如说有部分人我想做过滤,做特殊的校验,存储过程实现起来就不够灵活,其带来的性能提升,远远小于它引申出来的一系列难以排查的问题,得不偿失。我想,这也是阿里巴巴不建议使用存储过程和外键的原因了吧。

         整个方案其实并不复杂,实际业务中,比对的逻辑也不像图中那么简单,做了一些过滤和校验等操作。但大体上,这种方案很适合我们这个项目的场景,当然,肯定也不是最优方案。主要是因为前期的方案,排查问题花了很多时间,很多又是偶现,日志又不充分,排查又需要远程,很多代码又不是自己写的,整个排查过程让人很心累,索性重写了整个逻辑。并反复的测试了其可行性。不过,也要运行至少三个月才能知道这种方案有没有问题了。欢迎大家指出其中的问题,或者给出更加优雅的方案来适配我们项目中的这种人员同步场景,散会,下次见!
  


http://chatgpt.dhexx.cn/article/BNITmTrX.shtml

相关文章

大数据的数据同步方式

一、全量覆盖 不需要分区,同步时直接覆盖插入。适用于数据不会有任何新增和变化的情况。比如地区、时间、性别等维度数据,不会变更或变更不影响业务,可以只保留最新值 二、仅新增同步 每天新增一个日期分区,同步并存储当天的新…

DataLink 数据同步平台

文章目录 一、数据同步平台概述核心能力工作原理详细流程 二、快速接入部署中间件程序配置创建数据库表启动应用注意事项 三、扩展:四种 CDC 方案比较优劣 一、数据同步平台 在项目开发中,经常需要将数据库数据同步到 ES、Redis 等其他平台,通…

数据同步之全量同步与增量同步

一、什么是数据同步 业务数据是数据仓库的重要数据来源,我们需要每日定时从业务数据库中抽取数据,传输到数据仓库中,之后再对数据进行分析统计。 为保证统计结果的正确性,需要保证数据仓库中的数据与业务数据库是同步的&#xff0…

你了解数据同步吗?

1.写在前面 本篇博客参考《操作系统实战 45 讲》 上篇博客主要介绍的是程序放在什么地方,开发操作系统要了解的最核心的硬件——CPU、MMU、Cache、内存,知道了它们的工作原理。在程序运行中,它们起到了至关重要的作用。 在开发我们自己的操…

数据库同步有哪些方式?【怎么保障目标和源数据一致性】

文章目录 摘要一、几种主流的数据库同步方式二、架构及工作原理三、全量同步和实时增量同步机制四、源和目标五、举例:Oracle 数据实时同步到 Elasticsearch六、目标和源数据一致性七、异构数据类型转换八、总结 摘要 数据库同步有3大难题: 1是如何保障…

数据技术篇之数据同步

第3章 数据同步 1.数据同步基础 直连同步 (1)什么是直连同步?直连同步是指通过定义好的规范接口 API 和基于动态链接库的方式直接连接业务库,如 ODBC/JDBC 等规定了统 一规范的标准接口,不同的数据库基于这套标准接口…

聊聊数据同步方案

文章目录 常用的数据同步方案数据库迁移场景数据同步场景应用代码中同步定时任务同步通过MQ实现同步通过CDC实现实时同步 CDC(change data capture,数据变更抓取)Canal基于日志增量订阅&消费支持的业务工作原理Mysql主备复制实现Canal架构…

大数据之路——数据同步

三、数据技术篇—— 数据同步 3.1 数据同步基础 3.1.1 直连同步3.1.2 数据文件同步3.1.3 数据库日志解析同步 3.2 数据仓库同步方式3.2.1 批量数据同步3.2.2 实时数据同步 3.3 同步遇到的问题3.3.1 分库分表3.3.2 增量全量同步的合并3.3.3 数据漂移的处理 有多种不同应用场景&…

关于数据同步的几种实现

关于数据同步的几种实现 概述 关于数据同步主要有两个层面的同步,一是通过后台程序编码实现数据同步,二是直接作用于数据库,在数据库层面实现数据的同步。通过程序编码实现数据同步,其主要的实现思路很容易理解,即有…

数据同步技术

本次旨在分享数据同步技术的相关知识点,包括数据同步概述、数据同步工具、数据库、数据同步到大数据平台。 首先来介绍一下数据同步的概念: 数据同步是为保持数据源与目的地数据一致性而进行的数据传输、处理的过程。 数据同步的场景: 1、主…

几种常见的数据同步方式

数据仓库的特性之一是集成,即首先把未经过加工处理的、不同来源的、不同形式的数据同步到ODS层,一般情况下,这些ODS层数据包括日志数据和业务DB数据。对于业务DB数据而言(比如存储在MySQL中),将数据采集并导入到数仓中(通常是Hive…

内网穿透frpc ,frps的使用

情况是这样的,公司内网中一个设备接了路由器下发的地址,内网地址是192.168.1.100,可以访问我的台式机,但我的台式机访问192.168.1.100是无法连通的 这种情况下,在我机器上运行frps.exe,frps.ini如下 [com…

Frp内网穿透——frps服务端部署

由于现在IPv4地址的短缺,在国内不可能每个设备都会分配到一个公网IP,因此从公网中访问自己的私有设备向来是一件难事儿。本次带大家了解一下frp内网穿透的服务端教学,让你也能够部署一个内网穿透服务。 frp简介 通俗的说,frp是一…

记一次使用frpc/frps进行内网穿透

1. 前提条件: 有一个公网ip,这里用x.x.x.x代替 2. 配置 【服务器端】 S_NUMBER是一个端口号 #服务端口 bind_port S_NUMBER #监听地址 bind_addr 0.0.0.0 #认证token token xxxx【客户端】(也就是需要被内网穿透的服务器) C_NUMBER是一个端口号 …

内网穿透神器Frps一键安装脚本及设置教程

frps 是一个高性能的反向代理应用,可以帮助您轻松地进行内网穿透,对外网提供服务,支持 tcp, http, https 等协议类型,并且 web 服务支持根据域名进行路由转发。 *因为frps是go语言写的,所以在路由器上使用的时候&#…

frpc和frps 内网穿透越狱插件

内网穿透、frp、frpc、frps https://zhaoboy9692.github.io/repo 越狱源 https://zhaoboy9692.github.io/repo 苦于在ios越狱下没有frp穿透使用 特地开发了的越狱插件 基于最新frp0.48编译 ios14.6测试没问题 有问题及时反馈

使用frps和frpc实现内网穿透

内网穿透的作用包括跨网段访问一个局域网中的一台主机。 如上图,假设我们想要通过主机A访问主机C,但是主机A和主机C绑定的都是私有ip地址,所以它们之间是无法直接进行通信的。要想使得A和C能够进行通信,就需要用到内网穿透的技术。…

frp服务端(frps) 安装及使用

FRP官方文档 https://gofrp.org/docs/ 服务端安装 环境 ubuntu 22.04 下载 Github 的 Release 中下载到最新版本的客户端和服务端二进制文件 可以指定你的目录,这里用 /usr/local/frp cd /usr/local/frp wget https://github.com/fatedier/frp/releases/dow…

CentOS Frp内网穿透:Frps+Nginx反向代理

目录 服务器使用配置 一、Nginx安装 二、Frps安装 三、frpc安装 服务器使用配置 CentOS 7.6 CPU: 2核 内存: 4GB 一、Nginx安装 参考《Centos配置Nginxtomcat》,这里就不做过多阐述 二、Frps安装 这里使用的是阿里源 #下载脚本 wget https://code.aliyun.com…

nginx反向代理frps frpc穿透

frps 和 nginx 在同一台机器,假设ip192.168.166.17 1. frps服务器端配置 测试时,frps服务器跟nginx在同一台机器(192.168.166.17),理论上可以不在同一台机器,nginx可以代理http请求,发给frps服务端。 frps.ini # fr…