Незаурядная Java как инструмент разработки...

21
Незаурядная Java как инструмент разработки высоконагруженного сервера Андрей Паньгин ведущий разработчик проекта Одноклассники

description

Андрей Паньгин рассказывает о трюках, которые позволяют нам делать высоконагруженные сетевые серверы на Java

Transcript of Незаурядная Java как инструмент разработки...

Page 1: Незаурядная Java как инструмент разработки высоконагруженного сервера

Незаурядная Java как инструмент разработки высоконагруженного сервера

Андрей Паньгинведущий разработчикпроекта Одноклассники

Page 2: Незаурядная Java как инструмент разработки высоконагруженного сервера

Серверы Одноклассников

1

• Всего >3000 серверов– Web, Business logic, Download, Storage,

Remote Service…– Все ПО написано на Java

• Высоконагруженный сервер– 20 тыс. одновременных подключений– 30 тыс. запросов в секунду– Трафик до 1 Gb/s

Page 3: Незаурядная Java как инструмент разработки высоконагруженного сервера

Типичный Java Server

2

• java.net I/O (Sockets)– Поток на каждое соединение– Максимум 10 тыс. потоков

• NIO (SocketChannels)– Direct buffers– Selector– Неблокирующий ввод-вывод

• Event-driven NIO frameworks– Apache MINA– Netty

Page 4: Незаурядная Java как инструмент разработки высоконагруженного сервера

Remote Service

3

• Компоненты портала как отдельные сервисы– Система сообщений, граф дружб, поиск, лента и др.

• Внутренняя коммуникация между сервисами• RPC сценарий

Read Request

Deserialize arguments

Invoke method

Serialize result

Send response

Object result = method.invoke(args);

byte[] request = connection.read(…);

request � Method method, Object[] args

result � byte[] response

connection.write(response);

Page 5: Незаурядная Java как инструмент разработки высоконагруженного сервера

Socket I/O � Netty

4

• Конструирование запроса по частям• Влияние на GC• Снижение производительности

– Среднее время запроса +20%

Page 6: Незаурядная Java как инструмент разработки высоконагруженного сервера

Blocking socket selector (BLOS)

5

• Сочетает преимущества Selector + Blocking I/O• Возможно в OS, но не поддерживается в Java

• Реализуется посредством JNI– Простые Java-обертки над системными вызовами

Linux epoll

Solaris /dev/poll

BSD kqueue

Windows I/O completion ports

Page 7: Незаурядная Java как инструмент разработки высоконагруженного сервера

Java Socket � Native

6

• java.net.Socketjava.net.SocketImpl impl

java.io.FileDescriptor fdint fd

Object getField(Object holder, Class cls, String name) {

Field f = cls.getDeclaredField(name);

f.setAccessible(true);

return f.get(holder);

}

Page 8: Незаурядная Java как инструмент разработки высоконагруженного сервера

Архитектура BLOS сервера

7

• 1 acceptor thread• N selector threads (обычно N = кол-во CPU)• Динамический пул потоков-исполнителей• Запрос исполняется непрерывно до конца

Acceptor thread

Selector 1

Selector 2

read deserialize invoke serialize send

read deserialize invoke serialize send

Worker thread pool

Page 9: Незаурядная Java как инструмент разработки высоконагруженного сервера

Проблемы работы с сетью в Java

8

• java.net.Socket– Нет поддержки Direct Buffers– Finalizers => GC impact

• NIO не спасает– Не срабатывают I/O timeouts– Возможна утечка нативной памяти

Page 10: Незаурядная Java как инструмент разработки высоконагруженного сервера

Решение

9

• И снова JNI– Нет finalize(), нет утечки памяти– Время GC до 10 раз меньше– Необходимость закрывать сокеты вручную

• В Tomcat используется похожий подход– APR (Apache Portable Runtime)

Page 11: Незаурядная Java как инструмент разработки высоконагруженного сервера

Remote Service

10

• RPC сценарий

• Эффективность сериализации –ключ к производительности RPC– Затрачиваемое на сериализацию время– Размер передаваемых по сети данных

Read Request

Deserialize arguments

Invoke method

Serialize result

Send response

Page 12: Незаурядная Java как инструмент разработки высоконагруженного сервера

Сериализация

11

• Built-in Java Serialization– Слишком медленная– Большой объем получаемых данных

• JBoss Serialization– Не поддерживает модификацию классов

• Ручная сериализация– Не вариант (тысячи классов!)

Page 13: Незаурядная Java как инструмент разработки высоконагруженного сервера

Требования к сериализации

12

• Быстрая• Компактная• Обрабатывает простые изменениявнутри класса– Добавление поля– Удаление поля– Изменение порядка полей– Изменение типа поля (int � long)

Page 14: Незаурядная Java как инструмент разработки высоконагруженного сервера

Архитектура сериализации (1/2)

13

• Типы сериализаторов– Встроенные (примитивные типы, обертки, массивы)– Collection и Map– Сериализация произвольных классов по полям– Самосериализуемые классы (readObject / writeObject)

• Каждому сериализуемому классу сопоставляется уникальный 64-битный ID –хеш от имен, типов и порядка полей

Page 15: Незаурядная Java как инструмент разработки высоконагруженного сервера

Архитектура сериализации (2/2)

14

• Запись объекта:1. Serializer serializer = Repository.getByClass(obj.getClass());2. writeLong(serializer.uid);3. Serializer.write(obj, this);

• Чтение объекта:1. long uid = readLong();2. Serializer serializer = Repository.getById(uid);

� may throw SerializerNotFoundException

3. Object obj = serializer.read(this);

Page 16: Незаурядная Java как инструмент разработки высоконагруженного сервера

Трудности реализации

15

• Чтение/запись private полей чужих объектов– Reflection (медленно!)– sun.misc.Unsafe

• Создание объектов без вызова конструктора– sun.misc.Unsafe.allocateInstance()– ReflectionFactory.newConstructorForSerialization()– Динамическая генерация байткода

Page 17: Незаурядная Java как инструмент разработки высоконагруженного сервера

Unsafe

16

import sun.misc.Unsafe;

private static Unsafe getUnsafe() throws Exception {

Field f = Unsafe.class.getDeclaredField("theUnsafe ");

f.setAccessible(true);

return (Unsafe) f.get(null);

}

// Instantiate class X without calling X's construc tor

Object x = unsafe.allocateInstance(X.class);

// Read private field f of object x

long offset = unsafe.objectFieldOffset(f);

Object result = unsafe.getObject(x, offset);

Page 18: Незаурядная Java как инструмент разработки высоконагруженного сервера

Генерация байткода

17

1. Создать свой ClassLoader2. Построить массив byte[] с бинарным представлением класса

3. Вызвать ClassLoader.defineClass()

• ASM framework (http://asm.ow2.org)– Построить представление класса с помощью

org.objectweb.asm.ClassWriter– Преобразовать его в массив byte[]:

ClassWriter.toByteArray()

Page 19: Незаурядная Java как инструмент разработки высоконагруженного сервера

А как же private поля?

18

• JVM при загрузке нового класса верифицирует байткод

• Если класс унаследован от sun.reflect.MagicAccessorImpl,верификатор не будет проверять права доступа для байткодов getfield и putfield

Page 20: Незаурядная Java как инструмент разработки высоконагруженного сервера

Производительность

19

• Среднее время запроса: -20%• Сетевой трафик: -50%• Продолжительность GC: -30%• Количество потоков: 4000 � 200

Page 21: Незаурядная Java как инструмент разработки высоконагруженного сервера

Спасибо!

20

• Примеры– https://github.com/odnoklassniki/rmi-samples.git

• Контакты– [email protected]– www.odnoklassniki.ru/ap