主动缓存

878 阅读2分钟

由于数据监管的要求,公司的数据必须放在不同的国家,蛋疼的是第一次感受到了光速的“慢”。数据存储于,印度,美国等,每一次查询都有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);
}