26
Выжимаем из сервера максимум! Андрей Паньгин Одноклассники, ведущий инженер Приёмы кеширования и передачи данных на Java

Выжимаем из сервера максимум (Андрей Паньгин)

  • Upload
    ontico

  • View
    2.112

  • Download
    1

Embed Size (px)

Citation preview

Page 1: Выжимаем из сервера максимум (Андрей Паньгин)

Выжимаем из сервера максимум!

Андрей Паньгин Одноклассники, ведущий инженер

Приёмы кеширования и передачи данных на Java

Page 2: Выжимаем из сервера максимум (Андрей Паньгин)

Выжимаем из сервера максимум

• Архитектура Одноклассников

• Сокеты в Java: проблемы и решения

• Механизм сериализации

• Кеширование и разделяемая память

Page 3: Выжимаем из сервера максимум (Андрей Паньгин)

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

• 4000 серверов

– Web, Business logic, Download, Storage

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

• Высоконагруженный сервер

– 20 тыс. одновременных подключений

– 30 тыс. запросов в секунду

– Трафик до 1 Gb/s

Page 4: Выжимаем из сервера максимум (Андрей Паньгин)

Remote Service

• Компоненты портала как отдельные сервисы:

– система сообщений, граф дружб, поиск, лента…

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

Business logic server

Graph cluster

User service cluster

long[] friendIds = getConnections (userId)

List<User> friends = getUsers (friendIds)

Page 5: Выжимаем из сервера максимум (Андрей Паньгин)

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 6: Выжимаем из сервера максимум (Андрей Паньгин)

Выжимаем из сервера максимум

• Архитектура Одноклассников

• Сокеты в Java: проблемы и решения

• Механизм сериализации

• Кеширование и разделяемая память

Page 7: Выжимаем из сервера максимум (Андрей Паньгин)

Разработка сервера на Java

• java.net (Socket I/O) – Поток на каждое соединение

– Максимум 10 тыс. потоков

• NIO – Неблокирующие операции read / write

– Selector

• NIO frameworks – Apache MINA: http://mina.apache.org

– Netty: http://netty.io

Page 8: Выжимаем из сервера максимум (Андрей Паньгин)

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

Page 9: Выжимаем из сервера максимум (Андрей Паньгин)

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

Acceptor thread

Selector 1

Selector 2

read deserialize invoke serialize send

read deserialize invoke serialize send

Worker thread pool

Page 10: Выжимаем из сервера максимум (Андрей Паньгин)

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

• Socket

– Finalizers => утечка памяти, влияние на GC

– Не поддерживается прямой доступ к памяти

• SocketChannel (NIO)

– Не срабатывают таймауты на I/O операциях

– Возможна утечка нативной памяти

• Решение: JNI библиотека

– Такой подход используется в Tomcat (APR connector)

– Управление сокетами вручную

Page 11: Выжимаем из сервера максимум (Андрей Паньгин)

Выжимаем из сервера максимум

• Архитектура Одноклассников

• Сокеты в Java: проблемы и решения

• Механизм сериализации

• Кеширование и разделяемая память

Page 12: Выжимаем из сервера максимум (Андрей Паньгин)

Важность сериализации в RPC

• Затрачиваемое время на преобразование

• Объем передаваемых по сети данных

Read Request

Deserialize arguments

Invoke method

Serialize result

Send response

Page 13: Выжимаем из сервера максимум (Андрей Паньгин)

Способы сериализации в Java

• Стандартная Java сериализация – Медленная

– Большой объем получаемых данных

• JBoss serialization – Не поддерживает изменения внутри класса:

добавление поля, удаление, изменение типа или порядка полей

• Avro, Thrift, Protocol Buffers

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

Page 14: Выжимаем из сервера максимум (Андрей Паньгин)

Архитектура сериализации

• Типы сериализаторов

– Встроенные (примитивные типы, массивы, коллекции)

– Генерируемые по полям класса

• Сериализатор имеет уникальный 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 + +

Page 15: Выжимаем из сервера максимум (Андрей Паньгин)

Процедура сериализации

• Запись объекта: 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);

Page 16: Выжимаем из сервера максимум (Андрей Паньгин)

Особенности реализации на Java

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

– sun.misc.Unsafe

• Создание экземпляров класса – sun.misc.Unsafe.allocateInstance()

– Динамическая генерация байткода ASM framework: http://asm.ow2.org

• Обход Java верификатора – Наследование “магического” класса

sun.reflect.MagicAccessorImpl

Page 17: Выжимаем из сервера максимум (Андрей Паньгин)

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

• Среднее время запроса: -20%

• Сетевой трафик: -50%

Page 18: Выжимаем из сервера максимум (Андрей Паньгин)

Выжимаем из сервера максимум

• Архитектура Одноклассников

• Сокеты в Java: проблемы и решения

• Механизм сериализации

• Кеширование и разделяемая память

Page 19: Выжимаем из сервера максимум (Андрей Паньгин)

Кеширование

• Что кешировать?

– Данные из медленного хранилища (БД)

– Результаты вычислений

• Где кешировать?

– В оперативной памяти

• Java Heap (не подходит для объемов > 10 GB)

• Off-heap memory

– На диске или флеш-накопителе

Page 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

Page 21: Выжимаем из сервера максимум (Андрей Паньгин)

Снимки (shapshots)

• Решают проблему холодного старта

• Должны быть целостными

• Способы создания снимков

– “Stop-the-world”

– Запись по сегментам

– Memory-mapped files (MappedByteBuffer.force)

– Copy-on-write (fork trick)

– Shared memory objects

Page 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

Page 23: Выжимаем из сервера максимум (Андрей Паньгин)

Реализация off-heap кеша в Java

• Непрерывная область памяти

• Собственный аллокатор

• FIFO (проще, чем LRU)

• sun.misc.Unsafe (для быстрого доступа)

• Shared Memory (/dev/shm)

• Сегментирование ключей по хеш-коду

• Блокировка сегмента через ReadWriteLock или Semaphore

Page 24: Выжимаем из сервера максимум (Андрей Паньгин)

Структура кеша

Page 25: Выжимаем из сервера максимум (Андрей Паньгин)

Сравнение производительности

• Условия

– Linux JDK7u4 64-bit

– 1 млн. операций

– Значения от 0 до 8 KB

Page 26: Выжимаем из сервера максимум (Андрей Паньгин)

Спасибо!

• Примеры – 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