高并发之请求合并

应用场景

Redis官方介绍,Redis单机读写性能12万/s,批量处理能达到70w/秒。不管是缓存还是数据库,都有批量处理能力。当系统达到瓶颈时,才充分考虑压榨性能。适用于电商双十一,特定高并发场景。

思路

1、一个用户请求到来时,将请求放在一个队列中,单线程定时任务10ms从队列中取数据进行处理。
2、定时任务,把队列中的请求,批量的方式向后端和Redis缓存或数据库发起批量请求。
3、请求合并,请求阻塞等待请求处理完毕,需要用到Future

代码实现:
/**
* @author MrCai
* @date 2020/05/30
*/
public class MergeRequestTest {

	//阻塞队列
    static BlockingDeque<Request> blockingDeque = new LinkedBlockingDeque<>();
    
    //定时任务单线程
    static ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(1);

    public static void main(String[] args) {

	//定时任务
    scheduled.scheduleAtFixedRate(() -> {
        int size = blockingDeque.size();
        if (size == 0){
            return;
        }

        Map<Integer, Request> map = Maps.newHashMap();
        List<Integer> codes = Lists.newArrayList();
        for (int i = 0; i < size; i++) {
            Request request = blockingDeque.poll();
            codes.add(request.code);
            map.put(request.code, request);
        }

        System.out.println("--------------------------- " + codes.size());
        Map<Integer, String> results = getResults(codes);

        for (Integer code : results.keySet()) {
            String value = results.get(code);
            Request request = map.get(code);
            request.future.complete(value);
        }
    },0,1, TimeUnit.MILLISECONDS);

    AtomicInteger count = new AtomicInteger(0);
    for (int i = 0; i < 1000; i++) {
        new Thread(() -> {
            int code = count.addAndGet(1);
            try {
                TimeUnit.MILLISECONDS.sleep(code % 10);
                String result = getResult(code);
                // System.out.println("Thread " + code + " : " + result);
            }catch (Exception e){
        }
   }).start();
  }
}


//获取单个结果 
public static String getResult(Integer code) throws Exception{
    Request request = new Request();
    request.code = code;
    CompletableFuture<String> future = new CompletableFuture<>();
    request.future = future;
    blockingDeque.add(request);
    return future.get();
}

//多结果查询(批量接口)
public static Map<Integer,String> getResults(List<Integer> codes){
    System.out.println(JSON.toJSONString(codes));
    Map<Integer, String> map = Maps.newHashMap();
    for (Integer code : codes) {
        map.put(code, code.toString());
    }
    return map;
}

    static class Request{
        Integer code;
        CompletableFuture<String> future;
    }
}
总结:

1、特定特大高并发场景使用,平时可通过参数配置,对请求合并进行动态配置
2、依旧存在阻塞队列中数据无限大的问题(10ms中请求合并过于庞大)
个人解决方案:

  • 多队列,请求hash存到队列中,每个队列都有定时任务进行处理请求
  • 定时任务请采用 scheduleatfixedrate(时间超过10ms,处理完后直接继续处理)
  • 定时任务间隔时间,可进行量的预估,设置合理的值
  • 按照各中间件refresh思想,设置定时时间、队列大小,两个参数任意一点满足则任务执行
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值