gRP C переопределить атрибут remote-addr перед отправкой запроса - PullRequest
0 голосов
/ 24 марта 2020

У меня довольно странный случай использования, когда я хочу переопределить атрибут Grpc.TRANSPORT_ATTR_REMOTE_ADDR на стороне клиента перед отправкой моего запроса.

На стороне сервера я получаю запросы от многих клиентов и извлекаю их источники, используя этот атрибут. Затем я добавляю источник в кеш, чтобы поддерживать состояние на сервере до истечения срока его действия.

Теперь я хочу выполнить некоторые нагрузочные тесты на стороне сервера и запустить много клиентов на одном хосте. сделать это. Я пытался запустить эти клиенты в docker контейнерах, но атрибут remote-addr, когда запрос достигает сервера, всегда соответствует внешнему IP-адресу компьютера, на котором работает контейнер, то есть он не уникален и будет рассматриваться как кстати по серверу.

Вот как я получаю IP-адрес источника на сервере:

@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(final ServerCall<ReqT, RespT> call,
                                                             final Metadata headers,
                                                             final ServerCallHandler<ReqT, RespT> next) {

    if (call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR) != null) {
        final InetSocketAddress remoteAddress = (InetSocketAddress) call.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR);
        if (remoteAddress == null) {
            throw DeviceModuleException.create(null,"Could not get remote address of grpc client");
        }
        final Context context = Context.current().withValue(ORIGIN_IP, remoteAddress.getHostName());
        return Contexts.interceptCall(context, call, headers, next);
    }
    return next.startCall(call, headers);
}

И вот что я пытался сделать на стороне клиента:

return BaseApiGrpc.newBlockingStub(NettyChannelBuilder.forAddress(BRIDGE_HOST, BRIDGE_DEVICE_MODULE_PORT)
        .sslContext(buildSslContext())
        .intercept(new ClientInterceptor() {
            @Override
            public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
                return new ForwardingClientCall.SimpleForwardingClientCall<>(next.newCall(method, callOptions)) {
                    @Override
                    public Attributes getAttributes() {
                        return Attributes.newBuilder()
                                .setAll(super.getAttributes())
                                .set(Grpc.TRANSPORT_ATTR_REMOTE_ADDR, new InetSocketAddress("fakeip", 1337))
                                .set(Grpc.TRANSPORT_ATTR_LOCAL_ADDR, new InetSocketAddress("fakeip", 1337))
                                .build();
                    }
                };
            }
        })
        .build());

Однако сервер по-прежнему получает только фактический IP-адрес хоста, на котором я работаю. Я предполагаю, что есть перехватчики, примененные позже, чем мой перехватчик, и это переопределяет атрибут remote-addr.

Но как я мог этого достичь? Это что-то сломает?

Я не хочу делать никаких исключений или специальных решений на стороне сервера, я бы хотел, чтобы это не затрагивалось, если это возможно.

1 Ответ

1 голос
/ 26 марта 2020

Attributes не передаются между клиентом и сервером. Библиотека gRP C не вызывает ClientCall.getAttributes(); это реализует это. Таким образом, ваш перехватчик меняет значение, но только ваше приложение может увидеть другое значение.

Но на самом деле это в основном то, что вы хотите! Единственная проблема заключается в том, что вы должны использовать ServerInterceptor вместо ClientInterceptor! Вам также следует убедиться, что этот новый перехватчик выполняется до вашего существующего ServerInterceptor, который копирует удаленный IP-адрес в контекстный ключ ORIGIN_IP.

class FakeAddressInterceptor implements ServerInterceptor {
    @Override
    public <ReqT, RespT> ServerCall<ReqT, RespT> interceptCall(
            MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
        return new ForwardingServerCall.SimpleForwardingServerCall<>(next.newCall(method, callOptions)) {
            @Override
            public Attributes getAttributes() {
                return super.getAttributes().toBuilder()
                        .set(Grpc.TRANSPORT_ATTR_REMOTE_ADDR, new InetSocketAddress("fakeip", 1337))
                        .set(Grpc.TRANSPORT_ATTR_LOCAL_ADDR, new InetSocketAddress("fakeip", 1337))
                        .build();
            }
        };
    }
}
...
// Your existing interceptor
serverBuilder.interceptor(new OriginIpContextInterceptor());
// Later interceptors are "nearer" the network, as they wrap your
// service, not the library
serverBuilder.interceptor(new FakeAddressInterceptor());
...