Недавно я начал разработку приложения, интенсивно использующего сети. Первая попытка была сделана с использованием RMI, и по нескольким причинам мы переключились на чистые сокеты. Однако при тестировании сокетов по сети или даже на локальном хостинге мы опустились до 25 запросов в секунду. При использовании RMI он был на два порядка выше.Узкое место в производительности сокетов Java: где?
С немного больше испытаний, мы получили следующее (для локального хоста):
- Отправка всегда один и тот же объект: 31628 запросов/сек
- Отправка всегда новый объект: 25 запросов/сек
- только скорость создания объекта: 3-4 миллионов раз в секунду (так что не является узким местом)
Вот код клиента: (на стороне сервера просто отвечает в «ACK»)
public static void main(String[] args) throws IOException, ClassNotFoundException
{
Socket kkSocket = null;
ObjectOutputStream out = null;
ObjectInputStream in = null;
kkSocket = new Socket("barium", 4444);
out = new ObjectOutputStream(kkSocket.getOutputStream());
in = new ObjectInputStream(kkSocket.getInputStream());
long throughput;
long millis;
TcpRequest hello = null;
throughput = 0;
millis = System.currentTimeMillis();
while (System.currentTimeMillis() < millis + 1000)
{
hello = new TcpRequest();
hello.service = "hello";
hello.payload = Math.random();
throughput++;
}
System.out.println("-------------------------------------------------------");
System.out.println("| Objects created: " + (throughput) + " requests/sec.");
System.out.println("-------------------------------------------------------");
throughput = 0;
millis = System.currentTimeMillis();
while (System.currentTimeMillis() < millis + 1000)
{
out.writeObject(hello);
Object res = in.readObject();
throughput++;
}
System.out.println("-------------------------------------------------------");
System.out.println("| Same object throughput: " + (throughput) + " requests/sec.");
System.out.println("-------------------------------------------------------");
throughput = 0;
millis = System.currentTimeMillis();
while (System.currentTimeMillis() < millis + 1000)
{
hello = new TcpRequest();
out.writeObject(hello);
Object res = in.readObject();
throughput++;
}
System.out.println("-------------------------------------------------------");
System.out.println("| New objetcs throughput: " + (throughput) + " requests/sec.");
System.out.println("-------------------------------------------------------");
out.close();
in.close();
kkSocket.close();
}
Класс TcpRequest - это только фиктивный класс без особого внимания.
Итак, если создание объекта происходит быстро, если его по сети быстро ... почему на самом деле посылает новый объект по сети так медленно?!?!
И если вы сохраняете тот же объект и изменять его содержимое перед отправкой, вы также будете иметь высокую скорость передачи ... но попадают в неприятную западню:
При работе с сериализации объекта оно важно иметь в виду, что ObjectOutputStream поддерживает хэш-таблицу , отображающую объекты, написанные , в поток для дескриптора. Когда объект записывается в поток для в первый раз, его содержимое будет , скопированное в поток. Последующее сообщение приводит к тому, что дескриптор записывается в поток .
... который произошел с нами и вызвал несколько часов отладки, прежде чем вычислять его.
Итак, в основном ... как вы достигаете высокой пропускной способности с помощью сокетов? (... Я имею в виду, что с RMI, являющимся оберткой вокруг него, мы уже были на два порядка выше!)
РЕШИТЬ:
Заменив:
out = new ObjectOutputStream(kkSocket.getOutputStream());
С:
out = new ObjectOutputStream(new BufferedOutputStream(kkSocket.getOutputStream()))
Представления являются нормальными снова (почти такой же высокой пропускной способностью, как и с тем же объектом случае)
же, как этот вопрос: http://stackoverflow.com/questions/2251051/ performance-issue-use-javas-object-streams-with-socket ... нет ответов. – dagnelies 2010-12-15 15:13:32
Если ваши объекты не ссылаются друг на друга, вы можете вызвать ObjectOutputStream.reset() после записи, чтобы предотвратить запоминание потока всеми объектами, которые он написал. Хотя это обычно вызывает проблемы с памятью на стороне чтения, а не производительность на стороне сервера. Пробовали ли вы профилировать свое приложение, чтобы узнать, где он проводит больше времени? – 2010-12-15 15:19:22