【RPC】一步一步实现基于netty+zookeeper的RPC框架(五)

上一篇实现了服务的链路追踪,本篇带来限流。

关于服务限流,比较流行的是
1:令牌桶算法:桶算法的升级版,实现简单,应对热点请求效果更理想。
2:动态限流:根据实时的统计当前时间段请求响应时间来动态调整限流数量,实现复杂,但应对各种情况效果更好。

这里还是贴出github代码地址,想直接看代码的可以直接下载运行:https://github.com/whiteBX/wrpc

本篇带来令牌桶实现限流的实现,核心代码很简单,主要就下面一个类:

public class ConsumerLimiter {

    /**
     * 存放限流器
     */
    private ConcurrentMap<String, RateLimiter> rateLimiterMap = new ConcurrentHashMap<String, RateLimiter>();

    /**
     * 限流
     * @param appCode
     * @return
     */
    public boolean limit(String appCode) {
        RateLimiter rateLimiter = rateLimiterMap.get(appCode);
        if (rateLimiter == null) {
            rateLimiterMap.putIfAbsent(appCode, RateLimiter.create(1));
        }
        rateLimiter = rateLimiterMap.get(appCode);
        // 默认等待500mS
        return rateLimiter.tryAcquire(500, TimeUnit.NANOSECONDS);
    }
}

这里核心就是用到了guava包的RateLimiter,它内部实现了令牌桶,默认情况下RateLimiter.create(1)表示每秒向令牌桶中投放1个令牌,当然它也支持自己传入时间单位。

家下来改造RPCConsumer类的getServer方法:

/**
 * 获取服务
 * @param appCode
 * @return
 */
private String getServer(String appCode) {
    // 限流
    if (!consumerLimiter.limit(appCode)) {
        System.out.println("请求被限流");
        return null;
    }
    // 从zookeeper获取服务地址
    String serverHost = urlHolder.getUrl(appCode);
    if (serverHost == null) {
        return null;
    }
    return serverHost;
}

运行我们的代码,客户端日志如下:

zookeeper连接成功
链路追踪,调用远程服务:{"appCode":"100000","localIp":"10.0.75.1","operationName":"hello","parentSpanId":"0","remoteIp":"127.0.0.1,8092","spanId":"5bd706ef9f703a049cf62dd7","timestamp":1540818671137,"traceId":"5bd706ef9f703a049cf62dd6"}
调用服务器:127.0.0.1,8092,请求参数:{"clazzName":"org.white.wrpc.hello.service.HelloService","data":"{\"seq\":0}","methodName":"hello","paramTypeName":"org.white.wrpc.hello.model.request.HelloRequest","span":{"appCode":"100000","localIp":"10.0.75.1","operationName":"hello","parentSpanId":"0","remoteIp":"127.0.0.1,8092","spanId":"5bd706ef9f703a049cf62dd7","timestamp":1540818671137,"traceId":"5bd706ef9f703a049cf62dd6"}},响应参数:{"code":200,"message":"success:0"}
客户端收到响应:{"code":200,"message":"success:0"}
请求被限流
链路追踪,调用远程服务:{"appCode":"100000","localIp":"10.0.75.1","operationName":"hello","parentSpanId":"0","spanId":"5bd706f19f703a049cf62ddd","timestamp":1540818673006,"traceId":"5bd706f19f703a049cf62ddc"}
远程调用错误:当前无服务提供者
客户端收到响应:{"code":404,"message":"no provider"}
请求被限流
链路追踪,调用远程服务:{"appCode":"100000","localIp":"10.0.75.1","operationName":"hello","parentSpanId":"0","spanId":"5bd706f19f703a049cf62ddf","timestamp":1540818673307,"traceId":"5bd706f19f703a049cf62dde"}
远程调用错误:当前无服务提供者
客户端收到响应:{"code":404,"message":"no provider"}
链路追踪,调用远程服务:{"appCode":"100000","localIp":"10.0.75.1","operationName":"hello","parentSpanId":"0","remoteIp":"127.0.0.1,8093","spanId":"5bd706f19f703a049cf62de1","timestamp":1540818673609,"traceId":"5bd706f19f703a049cf62de0"}
调用服务器:127.0.0.1,8093,请求参数:{"clazzName":"org.white.wrpc.hello.service.HelloService","data":"{\"seq\":5}","methodName":"hello","paramTypeName":"org.white.wrpc.hello.model.request.HelloRequest","span":{"appCode":"100000","localIp":"10.0.75.1","operationName":"hello","parentSpanId":"0","remoteIp":"127.0.0.1,8093","spanId":"5bd706f19f703a049cf62de1","timestamp":1540818673609,"traceId":"5bd706f19f703a049cf62de0"}},响应参数:{"code":200,"message":"success:5"}
客户端收到响应:{"code":200,"message":"success:5"}
请求被限流

可以看到其中的限流日志。

另外说一点,本篇实现的是客户端限流,也有很多是支持服务端限流的,各有各的好处,可以按各位实际场景决定,或者两者都用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值