Upload
ontico
View
2.112
Download
1
Embed Size (px)
Citation preview
Выжимаем из сервера максимум!
Андрей Паньгин Одноклассники, ведущий инженер
Приёмы кеширования и передачи данных на Java
Выжимаем из сервера максимум
• Архитектура Одноклассников
• Сокеты в Java: проблемы и решения
• Механизм сериализации
• Кеширование и разделяемая память
Серверы Одноклассников
• 4000 серверов
– Web, Business logic, Download, Storage
– Все ПО написано на Java
• Высоконагруженный сервер
– 20 тыс. одновременных подключений
– 30 тыс. запросов в секунду
– Трафик до 1 Gb/s
Remote Service
• Компоненты портала как отдельные сервисы:
– система сообщений, граф дружб, поиск, лента…
• Внутренняя коммуникация между сервисами
Business logic server
Graph cluster
User service cluster
long[] friendIds = getConnections (userId)
List<User> friends = getUsers (friendIds)
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);
Выжимаем из сервера максимум
• Архитектура Одноклассников
• Сокеты в Java: проблемы и решения
• Механизм сериализации
• Кеширование и разделяемая память
Разработка сервера на Java
• java.net (Socket I/O) – Поток на каждое соединение
– Максимум 10 тыс. потоков
• NIO – Неблокирующие операции read / write
– Selector
• NIO frameworks – Apache MINA: http://mina.apache.org
– Netty: http://netty.io
Blocking Socket Selector (BLOS)
• Сочетает преимущества Selector + Blocking I/O
• Поддерживается на уровне ОС, но не в Java
• JNI обертки над системными вызовами
Linux BSD Solaris Windows
epoll kqueue /dev/poll Completion ports
Socket → SocketImpl impl → FileDescriptor fd → int fd
Архитектура BLOS сервера
Acceptor thread
Selector 1
Selector 2
read deserialize invoke serialize send
read deserialize invoke serialize send
Worker thread pool
Проблемы работы с сетью в Java
• Socket
– Finalizers => утечка памяти, влияние на GC
– Не поддерживается прямой доступ к памяти
• SocketChannel (NIO)
– Не срабатывают таймауты на I/O операциях
– Возможна утечка нативной памяти
• Решение: JNI библиотека
– Такой подход используется в Tomcat (APR connector)
– Управление сокетами вручную
Выжимаем из сервера максимум
• Архитектура Одноклассников
• Сокеты в Java: проблемы и решения
• Механизм сериализации
• Кеширование и разделяемая память
Важность сериализации в RPC
• Затрачиваемое время на преобразование
• Объем передаваемых по сети данных
Read Request
Deserialize arguments
Invoke method
Serialize result
Send response
Способы сериализации в Java
• Стандартная Java сериализация – Медленная
– Большой объем получаемых данных
• JBoss serialization – Не поддерживает изменения внутри класса:
добавление поля, удаление, изменение типа или порядка полей
• Avro, Thrift, Protocol Buffers
• Ручная сериализация – Externalizable – Не вариант (тысячи классов!)
Архитектура сериализации
• Типы сериализаторов
– Встроенные (примитивные типы, массивы, коллекции)
– Генерируемые по полям класса
• Сериализатор имеет уникальный ID – 64-битный хеш от имен, типов и порядка полей
class Event { String name = “HighLoad++”; int year = 2012; boolean started = true; }
UID 2012 10 H i g h L o a 1 d + +
Процедура сериализации
• Запись объекта: 1. Serializer serializer = Repository.getByClass(obj.getClass());
2. outputStream.writeLong(serializer.uid);
3. serializer.write(obj, outputStream);
• Чтение объекта: 1. long uid = inputStream.readLong();
2. Serializer serializer = Repository.getById(uid); » may throw SerializerNotFoundException
3. Object obj = serializer.read(inputStream);
Особенности реализации на Java
• Чтение и запись private полей чужих классов – Reflection (медленно!)
– sun.misc.Unsafe
• Создание экземпляров класса – sun.misc.Unsafe.allocateInstance()
– Динамическая генерация байткода ASM framework: http://asm.ow2.org
• Обход Java верификатора – Наследование “магического” класса
sun.reflect.MagicAccessorImpl
Производительность
• Среднее время запроса: -20%
• Сетевой трафик: -50%
Выжимаем из сервера максимум
• Архитектура Одноклассников
• Сокеты в Java: проблемы и решения
• Механизм сериализации
• Кеширование и разделяемая память
Кеширование
• Что кешировать?
– Данные из медленного хранилища (БД)
– Результаты вычислений
• Где кешировать?
– В оперативной памяти
• Java Heap (не подходит для объемов > 10 GB)
• Off-heap memory
– На диске или флеш-накопителе
Доступ к off-heap памяти в Java
• Native код (JNI обертки над malloc / free) – Платформозавимый
• ByteBuffer.allocateDirect – Размер буфера ≤ 2 GB
– Освобождается автоматически при GC
– Освобождение вручную: ((sun.nio.ch.DirectBuffer) buf).cleaner().clean();
• MappedByteBuffer (FileChannel.map)
• Unsafe.allocateMemory
Снимки (shapshots)
• Решают проблему холодного старта
• Должны быть целостными
• Способы создания снимков
– “Stop-the-world”
– Запись по сегментам
– Memory-mapped files (MappedByteBuffer.force)
– Copy-on-write (fork trick)
– Shared memory objects
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
Реализация off-heap кеша в Java
• Непрерывная область памяти
• Собственный аллокатор
• FIFO (проще, чем LRU)
• sun.misc.Unsafe (для быстрого доступа)
• Shared Memory (/dev/shm)
• Сегментирование ключей по хеш-коду
• Блокировка сегмента через ReadWriteLock или Semaphore
Структура кеша
Сравнение производительности
• Условия
– Linux JDK7u4 64-bit
– 1 млн. операций
– Значения от 0 до 8 KB
Спасибо!
• Примеры – https://github.com/odnoklassniki/shared-memory-cache.git
– https://github.com/odnoklassniki/rmi-samples.git
• Блог – http://habrahabr.ru/company/odnoklassniki/blog/
• Контакты – [email protected]
• Работа в Одноклассниках – http://v.ok.ru