线上用户反应某区域更新接口响应太慢(15s+)并且还会容易造成保存数据丢失的情况,原因是区域人员每次点击保存是全量更新操作:
1.先将原先区域内的用户完全解除绑定
2.再将当前的用户添加绑定
这两步操作同时也是非原子操作,其他用户同时操作时会导致添加失败。
第一次优化:
将更新时循环查询用户信息接口调整为批量查询接口,优化并不明显
使用线程池控制执行解绑和添加用户(CountDownLatch确保解绑完成后再添加),效果同样不明显,原因是每次操作用户时都会将此区域加redis锁导致多线程优势无法体现:RedisTemplate.opsForValue().setIfAbsent(key, value)
第二次优化:
考虑到实际业务场景无法支持过多调整,而此处全量更新都是小范围增减用户,想到了用代码先过滤掉大多不需要更新的用户,最终将响应时间控制在合理响应范围。
部分代码如下:
ArrayList<Long> removeList = new ArrayList<>(userWorkAreas.size());
ArrayList<Long> addList = new ArrayList<>();
for (PickerVO pickerVO : pickerVOs) {
addList.add(pickerVO.getUserId());
}
if (!CollectionUtils.isEmpty(userWorkAreas)) {
for (UserWorkArea userWorkArea : userWorkAreas) {
removeList.add(userWorkArea.getUserId());
}
ArrayList<Long> currentList = (ArrayList<Long>) removeList.clone();
removeList.removeAll(addList);
addList.removeAll(currentList);
//remove
for (Long userId : removeList) {
unBingUserWorkArea(workAreaConfigVO.getShopId(), userId, isFixed,WorkAreaTypeEnum.DISPATCH_AREA.getByteValue());
}
}
//add
for (Long userId : addList) {
bingUserWorkArea(workAreaConfigVO.getShopId(),userId, workAreaConfigVO.getId(), isFixed,WorkAreaTypeEnum.DISPATCH_AREA.getByteValue());
}