系统设计 - 两个平台数据的同步系统设计和实现

3,763 阅读5分钟

背景: 实现设备信息在两个平台之前的同步。我们的平台需要保存设备的信息,同时我们还需要将设备信息同步到第三方平台。第三方平台提供RESTful接口。

整个系统的设计如下:

设备操作(添加,删除,修改)分析

  1. 设备操作分成两部分:设备信息更新到本地数据库和同步到电信Iot平台
  2. “设备信息更新到本地数据库”实现比较简单,只要更新本地数据库对应记录即可
  3. “同步到电信Iot平台”相对复杂一些,它在设备信息导入到数据库成功后,立即触发同步操作。由于同步操作可能出现失败(或网络异常,第三服务或自身系统bug等),所以还需要定时任务(xxl-job)定时对失败的任务进行同步
  4. 由于可能有多个时机触发同步操作,为了避免对同一个设备同时被多个线程执行多次同步操作而出现数据不一致的问题,所以需要在同步模块中增加同步机制,通过redis的分布式锁保证同一时刻,同一个设备同时只能被一个线程操作

设备状态机设计

这里我们引入状态机保证设备操作的事物性。设备状态图如上图,详细描述如下:

  1. 新增设备 a. 当新增设备时,添加设备到电信Iot平台,如果执行成功,则状态设置为 “已完全同步”。如果执行失败,则状态设置为 “同步失败”; b. 对“同步失败”的设备执行重新添加,如果成功则设置 “已完全同步”,否则状态不变

  2. 当设备完全同步后,然后设备的信息被修改,再将修改的信息同步到第三方平台 a. 修改设备后,设备的状态修改为 “部分同步” b. 调用设备修改接口同步信息到第三方平台,如果成功,则状态设置为 “已完全同步”,如果失败,则状态不变

这里:第三方的设备同步接口必须保证幂等

设备增加操作 设备增加同步的详细步骤

详细描述如下:

  1. 判断当前分布式锁是否可用,如果锁不可用,则立即结束,否则下一步(此步保证当有很多线程时同时触发同步操作时,保证只有一个或少量线程进入后面的步骤)
  2. 获取分布式锁,如果获取失败,则等待。如果获取锁成功,则下一步
  3. 获取所有状态为 “未同步” 的设备,调用第三方添加接口执行添加操作,当执行完毕后,会执行如下判断 a. 调用第三方可能会第三方平台限流的原因失败,此时如果我们还继续调用接口进行添加是没有意义,则当前线程重新获取锁延长持有锁的时间,并等待Ns直到限流的期限结束,再进行后续操作 b. 判断当前已经持有锁的时间,如果持有锁的时长超过一定的阈值(此时当前线程还在锁的持有时间内),则重新获取锁延长持有锁的时间
  4. 获取所有状态为 “同步失败” 的设备,然后执行和 “未同步”的设备相同的步骤
  5. 最后在finally代码块中释放锁

触发“设备增加同步”的时机:

  1. 当新增设备成功
  2. 当批量导入任务立即执行
  3. 定时任务定时触发

设备删除

详细步骤如下:

  1. 获取分布式锁,这里的步骤和“设备同步增加”类似,这里略
  2. 标记可以删除设备
  3. 调用第三方接口进行删除 a. 如果设备的状态为 “未完成”或 “同步失败”(此时设备未同步到第三方平台),则跳过本步骤,只要从本地数据删除即可 b. 如果设备的状态为 “未完成”或 “同步失败”(此时设备未同步到第三方平台),则需要同时从第三方平台删除记录和本地数据删除。如果从第三方删除成功或第三方提示设备不存在,则再从本地删除记录。如果第三方提示删除失败,则立即结束
  4. 从本地删除记录

删除操作有可能在第2,3步失败,所以需要定时任务,扫描已经标记删除的设备,重新执行2,3步。同时这里需要保证第2,3步的幂等操作。由于业务的需要,可能需要在第2,3步前先获取分布式锁。

触发“设备删除同步”的时机:

  1. 当删除设备时成功
  2. 定时任务定时触发

设备修改 设备修改使用类似设备添加方法来实现

  1. 当设备被修改触发设备同步流程
  2. 更新设备的信息,并设置状态为 “未完全同步”
  3. 将设备信息同步到第三方平台,如果成功,则设置状态为“已完全同步”,如果失败,则状态不变

定时任务获取设备状态为 “未完全同步”,并执行上面的第2,3步步骤执行同步操作

这里保证同一个设备只能被一个线程操作,即使我们使用分布式服务同一设备同时也只能一个服务一个线程操作

此方案后续可以优化之处

  1. 优化分布式锁的粒度,从而提高效率
  2. 获取分布式锁后,通过多线程进行同步从而操作提高同步效率
  3. 第三平台也有可能执行设备的修改和删除操作,此时此平台也需要通知我们的系统并执行同步操作。我们平台可以考虑使用MQ解耦。