3

I have a RMI Server that needs to be tested with thousands of requests per second sent by a Traffic Generator simulating multiple clients.

What I want to do is something similar with this but with RMI.

Basically, stop accepting/processing requests if the saturation of the server is reached so it can keep processing the current ones.

Is this possible or I really need to use sockets to achieve this?

Thanks in advance.

EDIT: I also need to know how many requests have been rejected somewhere (might be client side or server side)

Community
  • 1
  • 1
André Mantas
  • 482
  • 4
  • 13
  • TCP will already do this if the backlog queue fills up. You don't need to take any special action. – user207421 Nov 25 '14 at 20:16
  • But I need to know how many requests have been rejected by the server. If that is the case, can monitor or check if that backlog queue is full in the "client" side? – André Mantas Nov 26 '14 at 10:35
  • You need to know that why? And of course if the server rejects requests you can't know *anything* further about the server from the client end. – user207421 Nov 26 '14 at 10:56
  • To test and know what is the saturation of my server implementation. Do you think there is any way of doing this? For example, to keep a good (the same all the time) performance I need to reject requests while the server is already processing 2000 requests. EDIT: one way i'll try is something like see what is the average time of processing a request and when some request takes more time than that, i know its better to reject the next requests so the performance doesn't get worse. But i guess there should be some other (better) way of doing the same thing... – André Mantas Nov 26 '14 at 12:58
  • There is no way of doing this in standard RMI. – user207421 Nov 26 '14 at 21:39

1 Answers1

0

RMI offers you a way to control the server socket creation, if you control the creation of client-server socket, you can decide whether to serve the incoming request or not, and of cause you can monitor rejections of service. here you need to extend ServerSocket. And if you want to reject "method invoke request", you can use a proxy object.

public class T {

    public static void main(String[] a) throws IOException {
        Queue<Socket> socks = new ConcurrentLinkedQueue<>();

        Registry registry = LocateRegistry.createRegistry(1099);
        IserverImpl roImpl = new IserverImpl();
        IService ro = Proxy.newProxyInstance(registry.getClass().getClassLoader(),
                        new Class[]{IService.class},
                        (proxy, method, args) -> {
                            if (isServerSaturationReached()) {
                                logRejection(method);
                                throw ReqRejectedByServerException();
                            }
                            return method.invoke(roImpl, args);
                        });

        Remote expRO = UnicastRemoteObject.exportObject(ro, 1100, null,
                        new RMIServerSocketFactory() {
                            @Override
                            public ServerSocket createServerSocket(int port) throws IOException {
                                return new MyServerSocket(port, socks);
                            }
                        });
        registry.bind("ro", expRO);

        Thread socksMgr = new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(30000);
                        int sSize = socks.size();
                        for (int i = 0; i < sSize; i++) {
                            final Socket s = socks.remove();
                            try {
                                // server side RMI socket will be closed if client close socket
                                if (!s.isClosed())
                                    socks.offer(s);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        sSize = socks.size();
                        if (isServerSaturationReached(sSize))
                            for (int i = 0; i < sSize / 10; i++) {
                                try {
                                    final Socket sockToReject = socks.remove();
                                    reject(sockToReject); // sockToReject.close();
                                    logRejection(sockToReject);
                                } catch (IOException e) {
                                }
                            }
                    } catch (InterruptedException e) {
                        return;
                    }
                }
            }
        };
        socksMgr.setPriority(Thread.MAX_PRIORITY);
        socksMgr.setDaemon(true);
        socksMgr.start();
    }

    public static class MyServerSocket extends ServerSocket {

        private Queue<Socket> socks;

        public MyServerSocket(int port, Queue<Socket> socks) throws IOException {
            super(port);
            this.socks = socks;
        }

        @Override
        public Socket accept() throws IOException {
            while (!super.isClosed()) {
                Socket a = super.accept();
                if (isServerSaturationReached(socks.size())) {
                    reject(a); // a.close();
                    logRejection(a);
                    //...
                } else {
                    socks.offer(a);
                    return a;
                }
            }
            throw new SocketException("Socket is closed");
        }
    }
}
mysh
  • 383
  • 2
  • 10
  • This is not adequate. Because of client-side connection pooling, by no means every new request comes in on a new connection. The server can still saturate. – user207421 Nov 27 '14 at 07:04
  • @EJP this is a way to control client-side connections, if your "saturation of the server" is cpu resource or memory resource, it's easy to control(thread pool or sth else), and it's nothing to do with RMI. here in my view, "saturation of the server" means too much RMI-client-connection-request. – mysh Nov 27 '14 at 08:29
  • No, it isn't a 'way to control client-side connections'. It is a way to control *new,* *incoming* connections, *at the server-side.* Client-side connections that already exist are not controlled by this mechanism, and the OP's objective of denying service when the sever is saturated is not met. Specifically, to use your own meaningless wording, it does not control 'too much RMI client-connection-request', as this is not a unitary concept. A single connection can service multiple requests, via connection-pooling at the client. Your answer and comment exhibit zero comprehension of that. – user207421 Nov 27 '14 at 08:49
  • whatever rpc you use, you meet the problem of "saturation of the server", but pay attention to the question "Rejecting requests when saturation is reached", if 1-billion client request coming to a RMI server in a second, you say there's no way but let the server hold all of the connections, I say there's a way to reject many of them, that's all my answer. your comment exhibit zero comprehension of the question. – mysh Nov 27 '14 at 10:30
  • as to "client-side connection pooling", pls note that one RMI connection servers one request at a time, client can reuse connection, so what? if I maintain the client sockets, can't I just close some of them randomly when server is saturate? – mysh Nov 27 '14 at 11:45
  • So the server code you posted only knows about new connections, not re-use of existing ones, that's what. Re your 2nd comment, how exactly is your client going to *know* to close some connections because the server has saturated? The server can't tell it anything, *because it is saturated.* And where does this magical feature appear in your answer? – user207421 Nov 28 '14 at 09:19
  • is saturation a natural state that you reach it you can do nothing? come on, it's a man defined state. I've updated the answer, server doesn't tell client anything, just close the socket, now what? – mysh Nov 30 '14 at 05:21
  • Your edit is no improvement. `isClosed()` doesn't tell you whether the peer closed the connection. It tells you whether you have closed this socket yourself. And now you're trying to layer another level of connection pooling on top of what RMI is already doing. And the fundamental flaw remains that it cannot possibly address existing connections being reused by the client. You have paid zero attention to this point despit it being raised three times, now four. – user207421 Nov 30 '14 at 06:37
  • 1) `isClosed()` does tell me the peer closed the connection, at least in Java 8. The socket is also handled by RMI server, not only me, you can test it yourself. 2) What I have done is to reject "connection request", if you mean "method invoke request", of cause that can't be rejected with RMI APIs. – mysh Nov 30 '14 at 07:19
  • to reject the "method invoke request", you can use proxy object, but that's nothing to do with RMI. I've update the answer. – mysh Nov 30 '14 at 07:40
  • (1) `isClosed()`doesn't, and can't, tell you any such thing, in any possible version of Java, or of anything else, because there is no underlying TCP API that can provide that information. The only way you can detect EOS in TCP is via a read. (2) A client that is reusing a connection doesn't go through the `accept()` method, and therefore any code based on an ’RMIServerSocketFactory`, including yours, at all, and therefore bypasses all your code. – user207421 Nov 30 '14 at 08:51
  • 1) there is a "read" when RMI server waiting for request, `isClosed()` doesn't tell me "client close thing" in common use of Socket, but it does in this RMI situation. 2) a client reusing a connection doesn't go through `accept()`, but it does go through the `InvocationHandler` of the proxy object(see my updated answer). – mysh Nov 30 '14 at 09:38
  • The semantics of `Socket.isClosed()` don't change just because of RMI. They can't. The socket doesn't know it's in an 'RMI situation'. A much simpler approach to your initial, partial solution would be to just sleep while `isSaturated()`, and then call `accept()`. – user207421 Dec 03 '14 at 21:57
  • I don't need any more of your code to know what's wrong with your post. – user207421 Sep 15 '16 at 03:03