组织架构数据同步效率优化,百倍提速

1,146 阅读7分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

首先介绍下这个功能的背景:

这是一个多租户系统,即一个用户可以同时有多个租户,系统中有user表(记录登录账号的信息),employee表(记录租户下员工的信息),而用户所拥有的租户就是通过这两个表关联的(即user表一对多employee表)。

正常需要使用系统,需要新建用户,员工,两者之间的关联关系以及用户和员工相关的额外信息,涉及的表结构较多,而且流程比较复杂。

为了方便客户能够更快的接入,我们提供了API给第三方客户调用,来同步他们的员工数据,第三方通过系统提供的API同步员工数据(用户),但是部分客户的反馈并不是很好,具体问题看下文。

1 优化前的流程

处理的方式:一次接口请求接收到一个数据集合,之后一条条消化处理落库,最后返回处理的情况给调用者。

对于五千内量级的用户来说其实影响不大,也可以接受。但是当企业的用户量在一万以上,第一次同步的时候是全量数据就花费很长的时间,在一小时以上,随着数据量的增加时间只会更长。

图片

流程如下:

  • 调用API,list集合传输批量数据;
  • for循环处理list集合,获取单条数据;
  • 校验数据的有效性:手机号/邮箱/工号格式,使用google的libphonenumber校验手机号是否合法,性别/员工状态是否合法,岗位/部门/额外字段(员工扩展信息)是否存在,生成姓名生成拼音等;
  • 校验不符合条件的数据标注其状态,符合条件的继续后面的流程;
  • 员工入库:新增或更新员工表信息;
  • 员工岗位关联入库:新增或更新员工和部门岗位的关联关系表;
  • 额外字段入库:新增或更新员工额外信息表;
  • 用户入库:根据姓名生成头像,新增或更新员工对应的用户表;
  • 用户角色入库:新增或更新用户对应的用户角色关联表;
  • 用户员工关联入库:新增或更新用户和关联的关联关系表;
  • 刷新es:把员工和用户数据更新到elasticsearch中,方便移动端搜索查询;
  • 一条数据完成后继续下一条数据,循环处理每一条数据,有问题的数据标注错误状态,然后给出具体错误的message;
  • 全部更新完成之后返回;

缺点: 速度慢,虽然是批量接收但是为了保持数据的正确性和完整性,校验和入库的逻辑处理都是单条顺序处理的。由于涉及的表较多而且逻辑复杂,存在锁的使用。

优点: 各项数据的完整性比较好,入库的数据规范控制比较好。

由于API的同步速度实在不太好, 在功能都已经开发完之后重新整理的下相关的逻辑,准备重新开发一个API,提高其同步效率。系统中同步数据的时候不仅仅有员工和用户,还包括数据正确性的校验,如手机号,邮箱,工号,性别,部门,额外字段,还有根据姓名生成头像,姓名生成拼音等操作,一长串逻辑在事务中处理并最终所有结果返回给调用端。

假如按照原来的设计执行,如果有一万条数据 那么最终调用数据库处理的次数会超过10万次(啊,这么多)。如果要缩短时间提高效率,上图提到的业务是不能缩减的,不然就会出现数据不完整进而影响用户正常使用,只能在调用次数上优化。

2 优化后的API流程

最终设计的的方案:实现真正的批量处理,新增一张中间表,用来存储API请求的所有数据集合(不管数据是否符合条件全部存入中间表),后续所有的正式表通过和这个中间表关联一次请求n条数据批量处理。数据校验,入库等都在数据库中批量完成。速度还是很快的,1万数据在1分钟内完成。

流程如下:

图片

处理流程:

  • 调用API,list集合传输批量数据;
  • 按照每次请求的批次 插入到中间表;
  • 数据校验:直接用sql校验中间表的邮箱/手机号/工号格式是否符合;用两表关联的sql校验工号/邮箱/手机号/岗位/部门等是否与正式表中的重复;
  • 员工相关表:用中间表与需要操作的员工相关的表关联,新增/更新员工表,员工岗位表,额外字段表等;
  • 用户相关表:用中间表与需要操作的用户相关的表关联,新增/更新用户表,用户info表,用户员工关联表等;
  • 状态更改:每次数据校验和更新相关表的时候,不符合条件的中间表数据都会被更改状态。
  • 流程执行完之后 把这一批次的所有数据再次返回给接口(包含每条数据的处理状态)。
  • 用消息队列更新es数据和姓名拼音,而头像直接使用默认的图片,不根据姓名生成。

当然,为了数据的正确性还做了事务的控制以及API的请求限制。

优点: 相比之前的API的速度要提升了百倍,再也不用在同步的时候苦苦等待了,可以在短时间内把主要数据同步成功。

缺点: 要求数据的格式控制不那么精确了。例如 放弃手机有效性检查(只检查是不是数字),同步es,更新拼音等不再是实时的了,头像不使用姓名生成,而是使用默认的图片。

如下是使用优化后的API同步数据的测试结果:

单次API数据量(条)花费时间(ms)
20004965
50007556
1000016950
1000020202 |

从测试结果可以看出 一万条数据可以在半分钟内结束,大大的减少了同步的时间。

3 总结

本次优化是使用批量操作数据库,减少数据库的调用次数,以及在业务层去除单条数据处理的方式。就像用户头像,elasticsearch数据等非主数据可以放入队列异步处理。还有手机号使用正则表达式只校验是数字即可,至于是不是有效手机号可以先忽略,后续可以使用其他方式校验(例如后续系统自检查然后推给管理员修改)。


我是纪先生,用输出倒逼输入而持续学习,持续分享技术系列文章,以及全网值得收藏好文,欢迎关注或者关注公众号,做一个持续成长的技术人。

实际问题系列的历史文章(也可以在掘金专栏中看其他相关文章)

1. 好用工具:慢SQL分析pt-query-digest;

2. 好用工具: pt-online-schame-change;

3. 怎么防止短信被白嫖;

4. 巧用双索引避免es出现索引不存在的问题;

5. 本地复现不了问题,那就线上debug;