alibaba/Sentinel

[BUG] 热点参数集群限流,参数为非基本类型时,server 侧decode时data会是null,导致 NPE

Open

#1,906 opened on 2020年12月16日

GitHub で見る
 (4 comments) (0 reactions) (0 assignees)Java (8,150 forks)batch import
area/cluster-flowgood first issuekind/bug

Repository metrics

Stars
 (23,109 stars)
PR merge metrics
 (30d に merged PR はありません)

説明

Issue Description

热点参数集群限流,如果参数是一个对象,因为netty在encode时会过滤掉,在tokenserver那解码时data会是null,导致空指针

Describe what happened (or what feature you want)

我在使用@sentinelresource注解时,使用了对象为参数,测试热点集群限流,希望可以总体阈值生效,但是metric日志总是不生效

Describe what you expected to happen

How to reproduce it (as minimally and precisely as possible)

image

Tell us your environment

jdk1.8 sentinel1.8

Anything else we need to know?

编码时跳过参数

int calculateParamTransportSize(Object value) {
        if (value == null) {
            return 0;
        }
        // Layout for primitives: |type flag(1)|value|
        // size = original size + type flag (1)
        if (value instanceof Integer || int.class.isInstance(value)) {
            return 5;
        } else if (value instanceof String) {
            // Layout for string: |type flag(1)|length(4)|string content|
            String tmpValue = (String) value;
            byte[] tmpChars = tmpValue.getBytes();
            return 1 + 4 + tmpChars.length;
        } else if (boolean.class.isInstance(value) || value instanceof Boolean) {
            return 2;
        } else if (long.class.isInstance(value) || value instanceof Long) {
            return 9;
        } else if (double.class.isInstance(value) || value instanceof Double) {
            return 9;
        } else if (float.class.isInstance(value) || value instanceof Float) {
            return 5;
        } else if (byte.class.isInstance(value) || value instanceof Byte) {
            return 2;
        } else if (short.class.isInstance(value) || value instanceof Short) {
            return 3;
        } else {
            // Ignore unexpected type.
            return 0;
        }

解码时

public class ParamFlowRequestDataDecoder implements EntityDecoder<ByteBuf, ParamFlowRequestData> {

    @Override
    public ParamFlowRequestData decode(ByteBuf source) {
        if (source.readableBytes() >= 16) {
            ParamFlowRequestData requestData = new ParamFlowRequestData()
                .setFlowId(source.readLong())
                .setCount(source.readInt());
           
            int amount = source.readInt();
            //因为amount为0,所以跳出判断,返回一个null
            if (amount > 0) {
                List<Object> params = new ArrayList<>(amount);
                for (int i = 0; i < amount; i++) {
                    decodeParam(source, params);
                }

                requestData.setParams(params);
                return requestData;
            }
        }
        return null;
    }
public class ParamFlowRequestProcessor implements RequestProcessor<ParamFlowRequestData, FlowTokenResponseData> {

    @Override
    public ClusterResponse<FlowTokenResponseData> processRequest(ClusterRequest<ParamFlowRequestData> request) {
        TokenService tokenService = TokenServiceProvider.getService();
        //data为null,报空指针,导致我的令牌请求失败
        long flowId = request.getData().getFlowId();
        int count = request.getData().getCount();
        Collection<Object> args = request.getData().getParams();

        TokenResult result = tokenService.requestParamToken(flowId, count, args);
        return toResponse(result, request);
    }

コントリビューターガイド