1. Выжимаем из сервера максимум!
Приёмы кеширования и передачи данных на Java
Андрей Паньгин
Одноклассники, ведущий инженер
2. Выжимаем из сервера максимум
• Архитектура Одноклассников
• Сокеты в Java: проблемы и решения
• Механизм сериализации
• Кеширование и разделяемая память
3. Серверы Одноклассников
• 4000 серверов
– Web, Business logic, Download, Storage
– Все ПО написано на Java
• Высоконагруженный сервер
– 20 тыс. одновременных подключений
– 30 тыс. запросов в секунду
– Трафик до 1 Gb/s
4. Remote Service
• Компоненты портала как отдельные сервисы:
– система сообщений, граф дружб, поиск, лента…
• Внутренняя коммуникация между сервисами
long[] friendIds = getConnections (userId)
Graph cluster
Business logic
server
List<User> friends = getUsers (friendIds)
User service
cluster
6. Выжимаем из сервера максимум
• Архитектура Одноклассников
• Сокеты в Java: проблемы и решения
• Механизм сериализации
• Кеширование и разделяемая память
7. Разработка сервера на Java
• java.net (Socket I/O)
– Поток на каждое соединение
– Максимум 10 тыс. потоков
• NIO
– Неблокирующие операции read / write
– Selector
• NIO frameworks
– Apache MINA: http://mina.apache.org
– Netty: http://netty.io
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
10. Проблемы работы с сетью в Java
• Socket
– Finalizers => утечка памяти, влияние на GC
– Не поддерживается прямой доступ к памяти
• SocketChannel (NIO)
– Не срабатывают таймауты на I/O операциях
– Возможна утечка нативной памяти
• Решение: JNI библиотека
– Такой подход используется в Tomcat (APR connector)
– Управление сокетами вручную
11. Выжимаем из сервера максимум
• Архитектура Одноклассников
• Сокеты в Java: проблемы и решения
• Механизм сериализации
• Кеширование и разделяемая память
12. Важность сериализации в RPC
• Затрачиваемое время на преобразование
• Объем передаваемых по сети данных
Read Request
Deserialize arguments
Invoke method
Serialize result
Send response
13. Способы сериализации в Java
• Стандартная Java сериализация
– Медленная
– Большой объем получаемых данных
• JBoss serialization
– Не поддерживает изменения внутри класса:
добавление поля, удаление, изменение типа
или порядка полей
• Avro, Thrift, Protocol Buffers
• Ручная сериализация – Externalizable
– Не вариант (тысячи классов!)
14. Архитектура сериализации
• Типы сериализаторов
– Встроенные (примитивные типы, массивы, коллекции)
– Генерируемые по полям класса
• Сериализатор имеет уникальный ID –
64-битный хеш от имен, типов и порядка полей
class Event {
String name = “HighLoad++”;
int year = 2012; UID 10 H i g h L o a d + + 2012 1
boolean started = true;
}
16. Особенности реализации на Java
• Чтение и запись private полей чужих классов
– Reflection (медленно!)
– sun.misc.Unsafe
• Создание экземпляров класса
– sun.misc.Unsafe.allocateInstance()
– Динамическая генерация байткода
ASM framework: http://asm.ow2.org
• Обход Java верификатора
– Наследование “магического” класса
sun.reflect.MagicAccessorImpl
18. Выжимаем из сервера максимум
• Архитектура Одноклассников
• Сокеты в Java: проблемы и решения
• Механизм сериализации
• Кеширование и разделяемая память
19. Кеширование
• Что кешировать?
– Данные из медленного хранилища (БД)
– Результаты вычислений
• Где кешировать?
– В оперативной памяти
• Java Heap (не подходит для объемов > 10 GB)
• Off-heap memory
– На диске или флеш-накопителе
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
21. Снимки (shapshots)
• Решают проблему холодного старта
• Должны быть целостными
• Способы создания снимков
– “Stop-the-world”
– Запись по сегментам
– Memory-mapped files (MappedByteBuffer.force)
– Copy-on-write (fork trick)
– Shared memory objects
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
23. Реализация off-heap кеша в Java
• Непрерывная область памяти
• Собственный аллокатор
• FIFO (проще, чем LRU)
• sun.misc.Unsafe (для быстрого доступа)
• Shared Memory (/dev/shm)
• Сегментирование ключей по хеш-коду
• Блокировка сегмента через ReadWriteLock
или Semaphore