之前在写开放平台的接口的时候,碰到了一些问题,记录一下
api接口速度优化
由于工期很赶,所以还没来得及自己测试,接口匆匆忙忙上线,当客户在用时,发现查询接口使用特别慢。然后分析原因,发现有慢sql引起的。
- 首先,接口调用的是我们系统的一个现成接口,主表的数据量很大,又冗余了一些不需要的关联表,于是我决定用自己的sql来执行,
- 其次我们接口给出的时间参数发现没有加索引,导致全表扫描。所以加了索引后接口从5s降低到1s,
- 其次,我使用arthas发现接口的时间一半多的时间都在请求count,而调用方只需要第一次请求获取总条数,后面调用不需要获取总条数。所以我们把是否获取总条数增加到接口参数中,这样如果不获取总条数的话,接口速度可以到ms级
怎么提升对接方的调用速度
这个需求我们提供了两个api接口,一个查询接口,一个更新接口。
原方案
- 我们一开始讨论的方案是让客户直接用更新接口,我们云端更新数据。这样就不需要查询接口,避免了同步数据的耗时和不准确。
- 否定原因:但是客户那边要求接口更新的速度很快,最好在几十ms级,不能卡,只用我们接口更新的话,首先速度不止支持这个速度,其次稳定性会降低,客户不愿意
新方案
- 所以我们讨论后采取了,客户自己拉取数据,持久化在自己本地,然后他们需要更新时只更新本地的数据,等到后台空闲的时候,再统一上传调用我们的更新接口。更新本地数据很快,满足客户的需求
如何拉数据
我们会记录一个游标,定时拉取。假设我们存储的游标是 1:40分,我每5分钟同步一次
那么我下次开始的时候就是抓 1:40分开始 到开始执行时间的点作为结束时间,例如开始执行时间是1:46分,那么本轮抓取的单据就是1:40 -1:46分有变化的单据,抓取结束之后,我再把这个1:46分持久化到DB,下一轮我就是1:46分开始 抓有变化的
怎么尽可能避免漏单
首先我们需要了解mysql分页的语法,首先mysql的初始分页是从0开始的,例如 limit 5,10 这个语法查询的是第6行到第15行的数据。
下面是一个小例子,首先我们通过查询数据发现有3条数据,而这个接口限定一次只能查询两条数据。那么正常情况下需要查询两次接口才能把数据查全。
即 limit 0,2 和limit 2,2
select count(*) from test where modified < '2021-10-31 11:26:00';
-- 总共3条数据,分两次拉取
select * from test where modified < '2021-10-31 11:26:00' order by modified limit 0,2;
-- 1,2
select * from test where modified < '2021-10-31 11:26:00' order by modified limit 2,2;
-- 3
如果我们在第一次接口调完之后,前面的两条数据发生了更新,那么它的更新时间会不在我们查询的范围内,那么总体查询的数量就从3条变成了1条。
那么第二个接口limit 2,2 就会查询不到数据。导致3这条数据漏单。
-- 第二轮
select * from test where modified < '2021-10-31 11:26:00' order by modified limit 0,2;
-- 1,2
update test set status =5 where id in (1,2);
select * from test where modified < '2021-10-31 11:26:00' order by modified limit 2,2;
-- null,3漏单
如果我们从一开始就采取从后往前翻页的方式调用接口,那么前面数据的更新则不会影响前面的分页
-- 第三轮
select * from test where modified < '2021-10-31 11:26:00' order by modified limit 2,2;
-- 3
update test set status =5 where id in (3);
select * from test where modified < '2021-10-31 11:26:00' order by modified limit 0,2;
-- 1,2
-- 不漏