2. Особенности разработки сервера на Java
Архитектура Одноклассников
Сокеты в Java: проблемы и решения
Альтернативный механизм сериализации
Кеширование данных и разделяемая память
2
3. Серверы Одноклассников
• 4000 серверов
• Web, Business logic, Download, Storage, Remote Services
• Все ПО написано на Java
Высоконагруженный сервер
• 20 тыс. одновременных подключений
• 30 тыс. запросов в секунду
• Трафик до 1 Gb/s
3
4. Remote Service
• Компоненты портала как отдельные сервисы:
система сообщений, граф дружб, поиск, лента и т. д.
• Внутренняя коммуникация между сервисами
long[] friendIds = getConnections (userId)
Graph cluster
Business logic
server
List<User> friends = getUsers (friendIds)
User service
cluster
4
6. Особенности разработки сервера на Java
Архитектура Одноклассников
Сокеты в Java: проблемы и решения
Альтернативный механизм сериализации
Кеширование данных и разделяемая память
6
7. Разработка сервера на Java
• java.net (Socket I/O)
– Поток на каждое соединение
– Максимум 10 тыс. потоков
• NIO
– Неблокирующие операции read / write
– Selector
• NIO frameworks
– Apache MINA: http://mina.apache.org
– Netty: http://netty.io
7
8. Blocking Socket Selector (BLOS)
• Сочетает преимущества Selector + Blocking I/O
• Поддерживается на уровне ОС, но не в Java
Linux BSD Solaris Windows
epoll kqueue /dev/poll Completion ports
• JNI обертки над системными вызовами
– Socket → SocketImpl impl → FileDescriptor fd → int fd
8
10. Проблемы работы с сетью в Java
• Socket
– Finalizers => утечка памяти, влияние на GC
– Не поддерживается прямой доступ к памяти (Direct ByteBuffers)
• SocketChannel (NIO)
– Не срабатывают таймауты на I/O операциях
– Возможна утечка нативной памяти
• Решение: JNI библиотека
– Такой подход используется в Tomcat (APR + Tomcat native)
– Управление сокетами вручную
10
11. Особенности разработки сервера на Java
Архитектура Одноклассников
Сокеты в Java: проблемы и решения
Альтернативный механизм сериализации
Кеширование данных и разделяемая память
11
12. Важность сериализации в RPC
• Затрачиваемое время на кодирование и декодирование
• Объем передаваемых по сети данных
Read Request
Deserialize arguments
Invoke method
Serialize result
Send response
12
13. Способы сериализации в Java
• Стандартная Java сериализация
– Медленная
– Большой объем получаемых данных
• JBoss serialization
– Не поддерживает простые изменения внутри класса:
добавление поля, удаление, изменение типа или порядка полей
• Avro, Thrift, Protocol Buffers
• Ручная сериализация – Externalizable
– Не вариант (тысячи классов!)
13
14. Архитектура сериализации
• Типы сериализаторов
– Встроенные (примитивные типы, массивы, коллекции)
– Сериализатор класса по полям
• Каждому сериализатору сопоставляется уникальный
64-битный ID – хеш от имен, типов и порядка полей
class Event {
String site = “mail.ru”;
int year = 2012; UID 7 m a i l . r u 2012 1
boolean started = true;
}
14
16. Особенности реализации в Java
• Чтение и запись private полей чужих классов
– Reflection (медленно!)
– sun.misc.Unsafe
• Создание экземпляров класса
– sun.misc.Unsafe.allocateInstance()
– Динамическая генерация байткода
ASM framework: http://asm.ow2.org
• Обход Java верификатора
– Наследование “магического” класса sun.reflect.MagicAccessorImpl
16
18. Особенности разработки сервера на Java
Архитектура Одноклассников
Сокеты в Java: проблемы и решения
Альтернативный механизм сериализации
Кеширование данных и разделяемая память
18
19. Что кешировть?
• Данные из медленного хранилища (БД)
• Результаты вычислений
Где кешировть?
• В оперативной памяти
– Java Heap (не подходит для объемов > 10 GB)
– Off-heap memory
• На диске или флеш-накопителе
19
20. Доступ к off-heap памяти в Java
• Native код (JNI обертки над malloc / free)
– Платформозавимый
• ByteBuffer.allocateDirect
– Размер буфера ≤ 2 GB
– Освобождается автоматически при GC
– Освобождение вручную: ((sun.nio.ch.DirectBuffer) buf).cleaner().clean();
• MappedByteBuffer (FileChannel.map)
• Unsafe.allocateMemory
20
21. Снимки (shapshots)
• Решают проблему холодного старта
• Должны быть целостными
• Способы создания снимков
– “Stop-the-world”
– Запись по сегментам
– Memory-mapped files (MappedByteBuffer.force)
– Copy-on-write (fork trick)
– Shared memory objects
21
22. Shared Memory
• Механизм IPC
– POSIX: shm_open + mmap
– Windows: CreateFileMapping + MapViewOfFile
– Linux: /dev/shm
• Создание объекта Shared Memory в Java
– new RandomAccessFile("/dev/shm/cache", "rw");
• Отображение в адресное пространство процесса
– легальный способ: FileChannel.map
– хитрый способ: sun.nio.ch.FileChannelImpl, методы map0 и unmap0
22
23. Реализация off-heap кеша в Java
на примере download сервера
• Непрерывная область памяти с собственным аллокатором
• FIFO (проще, чем LRU)
• sun.misc.Unsafe (самый быстрый способ доступа)
• Shared Memory (/dev/shm)
• Сегментирование ключей по хеш-коду
• Блокировка сегмента через ReadWriteLock / Semaphore
23