ObjectOutputStream writeObject зависает, когда два клиента отправляют объекты на сервер

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

Я использую ObjectOutputStream.writeObject на клиенте и ObjectInputStream.readObject на сервере.

Серверное приложение принимает подключение клиентов на один порт с помощью serverSocket.accept() и передает Socket новому потоку для чтения объектов.

Когда один клиент подключается и отправляет около 25 тыс. объектов/с - все работает нормально. Как только я запускаю второго клиента, через короткий промежуток времени один или оба клиента зависают на ObjectOutputStream.writeObject для одного из серверов, а соответствующий сервер зависает на ObjectInputStream.readObject. Никаких исключений с обеих сторон.

Если скорость очень низкая, скажем 10-20/с суммарно - зависать не будет, а вот при 100-1000/с будет.

Используя netstat -an на клиентской машине, я вижу, что send-Q соответствующей ссылки составляет около 30 КБ. На стороне сервера receive-Q также составляет ~ 30 КБ.

При запуске клиента/сервера на локальной винде наблюдаю нечто похожее - клиент зависает, но сервер продолжает обрабатывать входящие объекты и как только догоняет, клиент разблокируется и продолжает отправлять объекты.

Локально в Windows сервер работает медленнее, чем клиент, но в Linux количество экземпляров сервера, работающих на разных машинах, более чем достаточно для скорости, которую производят клиенты.

Любая подсказка, что происходит?

фрагмент кода клиента:

Socket socket = new Socket(address, port);
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
while(true)
{
     IMessage msg = createMsg();
     outputStream.writeObject(msg);
     outputStream.flush();
     outputStream.reset();
}

код сервера, принимающий соединения:

while(active)
{
    Socket socket = serverSocket.accept();
    SocketThread socketThread = new SocketThread(socket);
    socketThread.setDaemon(true);
    socketThread.start();
}

объекты чтения кода сервера:

public class SocketThread extends Thread 
    {
        Socket socket;
        public SocketThread(Socket socket)
        {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream());
                while(true)
                {
                    IMessage msg = (IMessage)inStream.readObject();
                    if(msg == null){
                        continue;
                    }
                    List<IMessageHandler> handlers = handlersMap.get(msg.getClass());
                    for(IMessageHandler handler : handlers){
                        handler.onMessage(msg);
                    }
                }
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

person Andrey    schedule 16.06.2016    source источник
comment
NB readObject() не вернет значение null, если вы не отправите значение null. Если вы не планируете этого делать, нулевой тест не имеет смысла.   -  person user207421    schedule 17.06.2016


Ответы (2)


Вы только что описали работу TCP, когда отправитель опережает получателя. Получатель говорит отправителю прекратить отправку, поэтому отправитель прекращает отправку. Поскольку вы используете блокирующий ввод-вывод, клиент блокирует send() внутренне.

Здесь нет проблемы, которую нужно решить.

person user207421    schedule 16.06.2016
comment
Нет. Серверы успешно обрабатывают 25К/с с одним клиентом, но зависают на скорости 1К/с с двумя. - person Andrey; 17.06.2016
comment
Итак, у вас есть проблема параллелизма на сервере. - person user207421; 17.06.2016

Проблема заключалась в том, что обработчики на стороне сервера использовали некоторые не потокобезопасные ресурсы (например, соединение Jedis), поэтому все это было стекировано на стороне сервера.

Выполнение этого безопасного потока решило проблему.

person Andrey    schedule 08.03.2018
comment
Итак, у вас возникла проблема параллелизма на сервере, как я и говорил 21 месяц назад. - person user207421; 08.03.2018
comment
Так почему ты рассказываешь нам то, что я уже говорил тебе 21 месяц назад? - person user207421; 09.03.2018
comment
Нашел для вас форум, где вы можете отказаться от этой социальной поддержки. com/forum/f24/human-behaviour-2122330/#/ - person Andrey; 10.03.2018