高性能RPC实现基础之CompletableFuture

ThreadManager.java

package org.example.testRpc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

public class ThreadManager {
    /*** 业务线程 */
    public static ExecutorService logicThread = Executors.newSingleThreadExecutor(r -> {
        Thread t = new Thread(r);
        t.setName("LogicThread");
        return t;
    });

    /*** 服务端业务线程 */
    public static ScheduledExecutorService scheduleThread = Executors.newScheduledThreadPool(1, r -> {
        Thread t = new Thread(r);
        t.setName("RpcThread");
        return t;
    });

    public static void init() {
    }
}

RpcManager.java

package org.example.testRpc;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;

@Slf4j
public class RpcManager {
    /*** key:rpc内部请求唯一标识 value:一次请求*/
    public static Cache<Long, CompletableFuture> map = CacheBuilder.newBuilder()
            .expireAfterAccess(1, TimeUnit.HOURS)
            .expireAfterWrite(1, TimeUnit.HOURS)
            .maximumSize(50000)
            .build();

    /*** 内部请求序列号 */
    public static AtomicLong seqNumObj = new AtomicLong(0);

    /**
     * 发起rpc请求
     *
     * @param req      请求
     * @param resClass 返回的类
     * @param consumer 回调
     */
    public static <REQ, RES> void sendRpcRequest(REQ req, Class<RES> resClass, Consumer<RpcResponseData<RES>> consumer) {
        CompletableFuture<RES> c = new CompletableFuture<>();

        // 设置20s后超时返回null
        c.completeOnTimeout(null, 20, TimeUnit.SECONDS);

        // 模拟发起了一次rpc请求
        long seqNum = seqNumObj.incrementAndGet();

        map.put(seqNum, c);

        // 得到结果后,指定的es就是要回到的线程LogicThread
        c.whenCompleteAsync((ret, e) -> {
            if (e != null) {
                log.error("error=", e);
                consumer.accept(new RpcResponseData<>(RPCResultEnum.EXCEPTION, null));
                return;
            }

            log.info("[客户端]收到服务端的处理结果seqNum={}", seqNum);

            if (ret == null) {
                log.error("[客户端]判断出:rpc超时!!! 请求类型={} 期待返回类型是{}", req.getClass(), resClass);
                consumer.accept(new RpcResponseData<>(RPCResultEnum.TIMEOUT, null));
                return;
            }

            if (!resClass.isInstance(ret)) {
                log.error("[客户端]判断出:返回类型错误!!! 请求类型={}, 期待服务端返回类型是{},实际返回类型是{}", req.getClass(), resClass, ret.getClass());
                consumer.accept(new RpcResponseData<>(RPCResultEnum.TYPE_ERROR, null));
                return;
            }

            consumer.accept(new RpcResponseData<>(RPCResultEnum.OK, ret));
        }, ThreadManager.logicThread);

        log.info("[客户端]发起rpc请求req={}, reqNum={}", req, seqNum);

        // TODO 通过网络发起调用
        remoteCall(req, seqNum);
    }

    private static <REQ> void remoteCall(REQ req, long seqNum) {
        ThreadManager.scheduleThread.schedule(() -> {
            log.info("[服务端]开始处理请求seq={}, seqNum={}, 还有任务数量taskSize={}", req, seqNum, map.asMap().size());

            try {
                // 模拟在远端处理完毕后,1s给回应
                TimeUnit.MILLISECONDS.sleep(ThreadLocalRandom.current().nextInt(500, 3000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            log.info("[服务端]处理请求完毕seq={}, seqNum={}", req, seqNum);

            // 这里直接移除
            CompletableFuture completableFuture = map.asMap().remove(seqNum);

            log.info("[服务端]还有任务数量taskSize={}", map.asMap().size());
            if (completableFuture == null) {
                log.error("seqNum={}没有对应的CompletableFuture", seqNum);
                return;
            }

            int res = 3;
//            String res = "abc";

            completableFuture.complete(res);
        }, 0, TimeUnit.SECONDS);
    }

}

RpcResponseData.java

package org.example.testRpc;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class RpcResponseData<RES> {
    private RPCResultEnum result;
    private RES res;
}

RpcResultEnum.java

package org.example.testRpc;

import lombok.Getter;

public enum RPCResultEnum {
    OK("成功"),
    EXCEPTION("异常"),
    TIMEOUT("超时"),
    TYPE_ERROR("服务器返回类型错误"),
    ;

    @Getter
    private String desc;

    RPCResultEnum(String desc) {
        this.desc = desc;
    }

}

Main.java

package org.example.testRpc;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Main {
    public static void main(String[] args) {
        ThreadManager.init();

        // 模拟在业务线程提交一个任务,其实就是处理玩家的请求
        ThreadManager.logicThread.execute(() -> {
            RpcManager.sendRpcRequest("abc", Integer.class, (res) -> {
                if (res.getResult() != RPCResultEnum.OK) {
                    log.info("rpc请求失败,reason={}!!!", res.getResult().getDesc());
                    return;
                }

                log.info("得到返回:{}", res.getRes());
            });
        });
    }
}

/*
正常情况:
16:03:10.636 [LogicThread] INFO org.example.testRpc.RpcManager -- [客户端]发起rpc请求req=abc, reqNum=1
16:03:10.649 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]开始处理请求seq=abc, seqNum=1, 还有任务数量taskSize=1
16:03:11.912 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]处理请求完毕seq=abc, seqNum=1
16:03:11.914 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]还有任务数量taskSize=0
16:03:11.914 [LogicThread] INFO org.example.testRpc.RpcManager -- [客户端]收到服务端的处理结果seqNum=1
16:03:11.915 [LogicThread] INFO org.example.testRpc.Main -- 得到返回:3


异常情况:
16:03:47.110 [LogicThread] INFO org.example.testRpc.RpcManager -- [客户端]发起rpc请求req=abc, reqNum=1
16:03:47.122 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]开始处理请求seq=abc, seqNum=1, 还有任务数量taskSize=1
16:03:49.166 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]处理请求完毕seq=abc, seqNum=1
16:03:49.172 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]还有任务数量taskSize=0
16:03:49.173 [LogicThread] INFO org.example.testRpc.RpcManager -- [客户端]收到服务端的处理结果seqNum=1
16:03:49.173 [LogicThread] ERROR org.example.testRpc.RpcManager -- [客户端]判断出:返回类型错误!!! 请求类型=class java.lang.String, 期待服务端返回类型是class java.lang.Integer,实际返回类型是class java.lang.String
16:03:49.175 [LogicThread] INFO org.example.testRpc.Main -- rpc请求失败,reason=服务器返回类型错误!!!
 */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值