由于数据监管的要求,公司的数据必须放在不同的国家,蛋疼的是第一次感受到了光速的“慢”。数据存储于,印度,美国等,每一次查询都有200ms的延迟。而且这延迟是由于光速的限制,是物理限制,买再大的带宽也没有用。
只好自己写了一个主动缓存的方案。
挺有意思的,仅供参考~
@Slf4j
@Component
public class UserLoginListener implements MessageListener {
@Autowired
private RegisterUserService registerUserService;
@Override
public Action consume(Message message, ConsumeContext context) {
DefaultJDKMessageSeri defaultJDKMessageSeri = new DefaultJDKMessageSeri();
log.info("Receive:{}, ConsumeContext:{}", message, context);
try {
UserMessage userMessage = (UserMessage) defaultJDKMessageSeri.deserialize(message.getBody());
log.info("Receive Message:{}, ConsumeContext:{}", userMessage, context);
if (userMessage == null || StringUtils.isEmpty(userMessage.getClientId())) {
return Action.CommitMessage;
}
if ("LOGIN".equals(message.getTag())) {
registerUserService.login(userMessage.getClientId());
}
if ("LOGOUT".equals(message.getTag())) {
registerUserService.loginOut(userMessage.getClientId());
}
return Action.CommitMessage;
} catch (Exception e) {
log.error("消费失败,message:{}, context:{}", message, context, e);
return Action.ReconsumeLater;
}
}
}
@Slf4j
@Component
public class RegisterUserService {
@Autowired
private CacheActivityHandlerService activityHandlerService;
private static Map<String, Long> clientIdLoginTimeMap = Maps.newConcurrentMap();
private Long tokenExpireTime = 60 * 60 * 2L;
private final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(
new BasicThreadFactory
.Builder()
.namingPattern("register-User-Scheduled-%d")
.build()
);
// 每次调度会有一堆的任务被塞进来,而且都是IO类型的任务
private static ExecutorService activityCacheParallelExecutor = new ThreadPoolExecutor(
16,
32,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(512), new BasicThreadFactory.Builder().namingPattern("activity-Cache-Thread-%d").build());
@PostConstruct
public void init() {
scheduledExecutorService.scheduleAtFixedRate(() -> {
log.info("cacheInfo, clientIdLoginTimeMap:{}", clientIdLoginTimeMap);
Iterator<String> iterator = clientIdLoginTimeMap.keySet().iterator();
while (iterator.hasNext()) {
String clientId = iterator.next();
if (StringUtils.isEmpty(clientId)) {
return;
}
Long time = clientIdLoginTimeMap.get(clientId);
if (time == null) {
this.loginOut(clientId);
continue;
}
if ((System.currentTimeMillis() - time) / 1000 > tokenExpireTime) {
this.loginOut(clientId);
continue;
}
try {
activityCacheParallelExecutor.submit(() -> {
ActivityRequest activityRequest = new ActivityRequest();
activityRequest.setClientId(clientId);
activityRequest.setPageSize(10);
activityRequest.setPageNo(1);
activityHandlerService.putCacheActivity(activityRequest);
activityRequest.setPageNo(2);
activityHandlerService.putCacheActivity(activityRequest);
ActivityRequest dashboardActivityRequest = new ActivityRequest();
dashboardActivityRequest.setClientId(clientId);
dashboardActivityRequest.setPageSize(5);
dashboardActivityRequest.setPageNo(1);
activityHandlerService.putCacheActivity(dashboardActivityRequest);
});
} catch (Exception e) {
// 可能队列满了,抛出错误
log.error("error happen when submit job, clientIdLoginTimeMap:{}", clientIdLoginTimeMap, e);
}
}
}, 0, 15, TimeUnit.SECONDS);
}
public void login(String clientId) {
clientIdLoginTimeMap.put(clientId, System.currentTimeMillis());
ActivityRequest dashboardActivityRequest = new ActivityRequest();
dashboardActivityRequest.setClientId(clientId);
dashboardActivityRequest.setPageSize(5);
dashboardActivityRequest.setPageNo(1);
activityHandlerService.putCacheActivity(dashboardActivityRequest);
ActivityRequest activityRequest = new ActivityRequest();
activityRequest.setClientId(clientId);
activityRequest.setPageSize(10);
activityRequest.setPageNo(1);
activityHandlerService.putCacheActivity(activityRequest);
activityRequest.setPageNo(2);
activityHandlerService.putCacheActivity(activityRequest);
}
public void loginOut(String clientId) {
ActivityRequest activityRequest = new ActivityRequest();
activityRequest.setClientId(clientId);
activityRequest.setPageSize(10);
activityRequest.setPageNo(1);
activityHandlerService.deleteCacheActivity(activityRequest);
activityRequest.setPageNo(2);
activityHandlerService.deleteCacheActivity(activityRequest);
ActivityRequest dashboardActivityRequest = new ActivityRequest();
dashboardActivityRequest.setClientId(clientId);
dashboardActivityRequest.setPageSize(5);
dashboardActivityRequest.setPageNo(1);
activityHandlerService.deleteCacheActivity(dashboardActivityRequest);
clientIdLoginTimeMap.remove(clientId);
}
}
@Cacheable(cacheNames = "activity"
, key = "#activityRequest.clientId + '_' + #activityRequest.pageSize + '_' + #activityRequest.pageNo"
, condition = "#activityRequest.pageNo <= 2")
public List<UserActivityDTO> cacheActivity(ActivityRequest activityRequest) {
log.info("cacheActivity, activityRequest:{}", activityRequest);
return this.queryActivity(activityRequest);
}
@CachePut(cacheNames = "activity"
, key = "#activityRequest.clientId + '_' + #activityRequest.pageSize + '_' + #activityRequest.pageNo"
, condition = "#activityRequest.pageNo <= 2")
public List<UserActivityDTO> putCacheActivity(ActivityRequest activityRequest) {
log.info("putCacheActivity, activityRequest:{}", activityRequest);
return this.queryActivity(activityRequest);
}
@CacheEvict(cacheNames = "activity"
, key = "#activityRequest.clientId + '_' + #activityRequest.pageSize + '_' + #activityRequest.pageNo"
, condition = "#activityRequest.pageNo <= 2",
beforeInvocation = true)
public List<UserActivityDTO> deleteCacheActivity(ActivityRequest activityRequest) {
log.info("deleteCacheActivity, activityRequest:{}", activityRequest);
return this.queryActivity(activityRequest);
}