Dubbo中服务降级服务限流限流措施

Posted Leo Han

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo中服务降级服务限流限流措施相关的知识,希望对你有一定的参考价值。

作为一个RPC框架,Dubbo同时提供了兼具微服务的一些服务管理功能:
服务降级、限流

服务降级

Dubbo中服务降级可以通过mock实现,在消费端,通过配置mock选项,来支持服务降级
如:

@DubboReference(mock = "force:return null")
@DubboReference(mock = "return null")

@DubboReference(mock = "throw") // 抛出 RpcException
@DubboReference(mock = "throw com.xxx.XXXException")  // 抛出RpcException,并传入自定义异常

@DubboReference(mock = "com.xxx.XXXServiceImpl") // 实现调用接口,mock时调用该实现对应的接口方法

可以通过如上几种方式,其中force是强制mock,不管调用的服务是否正常,都走mock流程,其他的都是在调用失败之后走mock。

mock代码实现在MockClusterInvoker中:

public Result invoke(Invocation invocation) throws RpcException 
        Result result = null;
        String value = getUrl().getMethodParameter(invocation.getMethodName(), MOCK_KEY, Boolean.FALSE.toString()).trim();
        if (value.length() == 0 || "false".equalsIgnoreCase(value)) 
            result = this.invoker.invoke(invocation);
         else if (value.startsWith("force")) 
            if (logger.isWarnEnabled()) 
                logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + getUrl());
            
            result = doMockInvoke(invocation, null);
         else 
            //fail-mock
            try 
                result = this.invoker.invoke(invocation);
                if(result.getException() != null && result.getException() instanceof RpcException)
                    RpcException rpcException= (RpcException)result.getException();
                    if(rpcException.isBiz())
                        throw  rpcException;
                    else 
                        result = doMockInvoke(invocation, rpcException);
                    
                
             catch (RpcException e) 
                if (e.isBiz()) 
                    throw e;
                
                result = doMockInvoke(invocation, e);
            
        
        return result;
    

可以看到,对于force这种mock,不管服务提供方是否正常都走mock,而具体执行mock在MockInvoker中:

public Result invoke(Invocation invocation) throws RpcException 
        if (invocation instanceof RpcInvocation) 
            ((RpcInvocation) invocation).setInvoker(this);
        
        String mock = null;
        if (getUrl().hasMethodParameter(invocation.getMethodName())) 
            mock = getUrl().getParameter(invocation.getMethodName() + "." + MOCK_KEY);
        
        if (StringUtils.isBlank(mock)) 
            mock = getUrl().getParameter(MOCK_KEY);
        

        if (StringUtils.isBlank(mock)) 
            throw new RpcException(new IllegalAccessException("mock can not be null. url :" + url));
        
        mock = normalizeMock(URL.decode(mock));
        if (mock.startsWith(RETURN_PREFIX)) 
            mock = mock.substring(RETURN_PREFIX.length()).trim();
            try 
                Type[] returnTypes = RpcUtils.getReturnTypes(invocation);
                Object value = parseMockValue(mock, returnTypes);
                return AsyncRpcResult.newDefaultAsyncResult(value, invocation);
             catch (Exception ew) 
                throw new RpcException("mock return invoke error. method :" + invocation.getMethodName()
                        + ", mock:" + mock + ", url: " + url, ew);
            
         else if (mock.startsWith(THROW_PREFIX)) 
            mock = mock.substring(THROW_PREFIX.length()).trim();
            if (StringUtils.isBlank(mock)) 
                throw new RpcException("mocked exception for service degradation.");
             else  // user customized class
                Throwable t = getThrowable(mock);
                throw new RpcException(RpcException.BIZ_EXCEPTION, t);
            
         else  
            try 
                Invoker<T> invoker = getInvoker(mock);
                return invoker.invoke(invocation);
             catch (Throwable t) 
                throw new RpcException("Failed to create mock implementation class " + mock, t);
            
        
    

服务限流

服务限流,为了防止服务的QPS突然飙升或者太大导致服务频繁失败甚至崩溃重启,对一些重要服务进行限流,虽然会导致一些请求失败,但是能够保证服务平稳运行
Dubbo中的限流有如下几个措施:

accepts:限制服务器端接受的连接数,对于服务提供方,Dubbo默认基于Netty协议的底层网络可以限制客户端连接数量进行限制dubbo.protocol.accepts=10 或者dubbo.provider.accepts=10 只能在服务提供端

connections:限制客户端服务使用连接数,使用@DubboReference(connections = 10)或者
@DubboService(connections = 10) 作用在接口或方法级别上,如果两个都有,@DubboReference(connections = 10)优先

executes: 服务提供者并发限制,作用在服务提供者接口或者方法上,@DubboService(connections = 10,executes = 10)@Method(executes = 10),Dubbo中会根据接口或者方法上的该配置,然后在每次执行方法前,会判断当前接口或者方法并行的数量是否大于该值,如果大于抛出异常,否则当前接口和方法active+1.在ExecuteLimitFilter实现了该过滤处理

actives:与executes类似,但是可以作用在服务提供者和消费者的接口或方法上,但是不同于executes不同的是,这里是表示同事能够活跃的处理数,如果超过该值,则需要等待timeoutms,超时则抛出异常,在ActiveLimitFilter实现了active处理

以上是关于Dubbo中服务降级服务限流限流措施的主要内容,如果未能解决你的问题,请参考以下文章

限流限流算法

聊一聊限流降级熔断

使用Guava RateLimiter限流以及源码解析

使用Guava RateLimiter限流以及源码解析

限流降级方案

高可用系统设计 | 分布式限流策略:计数器算法漏桶算法令牌桶算法