alibaba / Sentinel

A powerful flow control component enabling reliability, resilience and monitoring for microservices. (面向云原生微服务的高可用流控防护组件)
https://sentinelguard.io/
Apache License 2.0
22.32k stars 8k forks source link

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

Open zuoqi1993125 opened 3 years ago

zuoqi1993125 commented 3 years ago

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);
    }
sczyh30 commented 3 years ago

Thanks for reporting. Would you like to submit a PR to fix it?

zuoqi1993125 commented 3 years ago

Thanks for reporting. Would you like to submit a PR to fix it?

你们解决方案是什么,是热点参数限流的入参为pojo类时抛异常?我们在使用时是避开了这个bug,不允许参数为pojo类

kaori-seasons commented 3 years ago

@sczyh30 Maybe we can refer to the implementation of ObjectEncoder in netty4.0? First let the POJO object inherit from the serializable serialized object, Then in ParamFlowRequestDataDecoder#decode, is it compatible with Netty's ObjectEncoder decoding logic?

Whether the judgment in decodeParam is the overloaded decoding method of Serializable object, write the following logic

hellomyboy commented 3 years ago

Thanks for reporting. Would you like to submit a PR to fix it?

Can you assign it to me