本文共 3400 字,大约阅读时间需要 11 分钟。
上一篇实现了服务的链路追踪,本篇带来限流。
关于服务限流,比较流行的是
1:令牌桶算法:桶算法的升级版,实现简单,应对热点请求效果更理想。 2:动态限流:根据实时的统计当前时间段请求响应时间来动态调整限流数量,实现复杂,但应对各种情况效果更好。这里还是贴出github代码地址,想直接看代码的可以直接下载运行:https://github.com/whiteBX/wrpc
本篇带来令牌桶实现限流的实现,核心代码很简单,主要就下面一个类:
public class ConsumerLimiter { /** * 存放限流器 */ private ConcurrentMaprateLimiterMap = new ConcurrentHashMap (); /** * 限流 * @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"}请求被限流
可以看到其中的限流日志。
另外说一点,本篇实现的是客户端限流,也有很多是支持服务端限流的,各有各的好处,可以按各位实际场景决定,或者两者都用。
转载地址:http://qhsni.baihongyu.com/