SlideShare a Scribd company logo
Разработка высоконагруженного
сервера на Java
Андрей Паньгин
Одноклассники, ведущий инженер
План доклада
• Архитектура ОК
• Работа с сетью
• Удалённые вызовы и сериализация
• Кеширование
• Паузы JVM, оптимизация GC
Факты об ОК
• 8000 серверов
• 48 млн. уникальных пользователей в день
• 8 млн. пользователей онлайн
• 300 000 web запросов в секунду
• 4 ПБ данных (без учёта дублирования)
Экстремальные нагрузки
• На что способен один сервер
– 50,000 вызовов/с в сек (push delivery)
– 40 Гбит/с (video download)
– 100,000 пользователей онлайн (xmpp)
– 384 ГБ в памяти (cache)
• Это всё Java!
Архитектура ОК
Web
Web
Mobile
Mobile
API
API
Business
logic
Business
logic
Business
logic
Business
logic
Business
logic
Business
logic
GraphGraphGraph
GraphGraphMessaging
GraphGraphPhoto
GraphGraphFeed
BLOB
storage
SQL
servers
Cassandra
Services
Business layerFront-end
Storages
HTTP
RPC
RPC
Внутренняя коммуникация
• Удалённый вызов методов (RPC)
Business logic
server
Graph cluster
User service
cluster
long[] friendIds = getConnections (userId)
List<User> friends = getUsers (friendIds)
План доклада
• Архитектура ОК
• Работа с сетью
• Удалённые вызовы и сериализация
• Кеширование
• Паузы JVM, оптимизация GC
java.net.Socket I/O
• Поток на каждое соединение
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
while (true) {
int bytesRead = in.read(...); // blocking call
if (bytesRead > 0) {
byte[] response = processRequest(...);
out.write(response); // blocking call
}
}
Проблемы Socket I/O
• 10 тыс. соединений = 10 тыс. потоков
• Finalizers => утечка памяти
• byte[] массивы, копирование
NIO
while (true) {
if (selector.select() > 0) { // blocking call
for (SelectionKey key : selector.selectedKeys()) {
if (key.isReadable()) {
doRead(key);
} else if (key.isWritable()) {
doWrite(key);
}
}
selector.selectedKeys().clear();
}
}
• Selector + неблокирующие read/write
NIO frameworks
• Apache MINA
– http://mina.apache.org
• Netty
– http://netty.io
• Основаны на NIO
• Event-driven модель
Проблемы NIO
• Selector глючный, не потокобезопасный
• Нельзя делать select() на blocking сокетах
• Не работает setSoTimeout()
• Ограниченная поддержка SSL/TLS
• Не поддерживаются все возможности ОС
– TCP опции: TCP_DEFER_ACCEPT, TCP_CORK
– Флаги send/recv: MSG_MORE, MSG_PEEK
Решение
• JNI библиотека
– Tomcat Native (APR connector)
– one-nio
• Управление сокетами вручную
• Поддержка OpenSSL
Архитектура сервера
Acceptor thread
Selector 1
Selector N
Worker thread pool
NCPU
read
read
process write
process write
Пример сервера
public class MyHttpServer extends HttpServer {
public MyHttpServer() throws IOException {
super(new ConnectionString("https://0.0.0.0"));
}
@Path("/hello")
public Response hello() {
return Response.ok("Hello world");
}
public static void main(String[] args) throws Exception {
new MyHttpServer().start();
}
}
Пример клиента
public class MyHttpClient {
public static void main(String[] args) throws Exception {
HttpClient client = new HttpClient("https://localhost");
Response response = client.get("/hello");
System.out.println("Status: " + response.getStatus());
System.out.println(response.toString());
client.close();
}
}
План доклада
• Архитектура ОК
• Работа с сетью
• Удалённые вызовы и сериализация
• Кеширование
• Паузы JVM, оптимизация GC
RPC сценарий
Method m, Object[] args
Object result
long[] friendIds = graph.getFriends(userId);
Method m, Object[] args
byte[] request
Method m, Object[] args
Object result
byte[] response
Object result
Исполнение
Десериализация
Десериализация
Сериализация
Сериализация
Клиент Сервер
 0.4 мс
Сериализация
• Быстрая, компактная
• Минимум ручной работы
• Поддержка эволюции
– Java Serialization
– JBoss
– Thrift, Avro, Protobuf
– Kryo
one.nio.serial
• Массивы и коллекции
– count obj1 … objN
• Мапы
– count key1 value1 … keyN valueN
• Enum
– short ordinal()
• Externalizable
– readExternal / writeExternal
• Остальные Serializable
– non-static non-transient fields
Схема сериализации
• Serializer
– Long UID – хеш от имён, типов и порядка полей
• Repository
– Map<Class, Serializer> для сериализации
– Map<Long, Serializer> для десериализации
class Person {
String name = "Victor";
int yearOfBirth = 1980;
boolean married = true;
}
UID 19806 V i c t o r 1-18
String UID
Обмен схемами
1. Client  Server: request
2. Server throws SerializerNotFoundException ?
– Client  Server: provideSerializer(serializer)
– Goto 1
3. Deserialize response
4. Client throws SerializerNotFoundException ?
– Client  Server: requestSerializer(uid)
– Add to repository
– Goto 3
Особенности реализации на Java
• Чтение и запись private полей
– Reflection (медленно!)
– sun.misc.Unsafe
• Создание экземпляров класса
– sun.misc.Unsafe.allocateInstance()
– Генерация байткода: http://asm.ow2.org
• Обход Java верификатора
– Наследование sun.reflect.MagicAccessorImpl
План доклада
• Архитектура ОК
• Работа с сетью
• Удалённые вызовы и сериализация
• Кеширование
• Паузы JVM, оптимизация GC
Числа, которые нужно знать
L1 cache reference 0.5 ns
Main memory reference 100 ns
Compress 1K bytes w/ cheap algorithm 3,000 ns
Send 2K bytes over 1 Gbps network 20,000 ns
Read 1 MB sequentially from memory 250,000 ns
Round trip within same datacenter 500,000 ns
Read 1 MB sequentially from network 10,000,000 ns
Read 1 MB sequentially from disk 30,000,000 ns
Send packet CA->Netherlands->CA 150,000,000 ns
Кеширование
• Что кешировать?
– Данные из медленного хранилища (БД)
– Результаты вычислений
• Где кешировать?
– Java Heap (не подходит для объемов > 10 GB)
– Off-heap memory
Как выйти за пределы Heap
• Native код (JNI обертки над malloc / free)
– Платформозавимый
• ByteBuffer.allocateDirect
– Размер буфера ≤ 2 GB
– Освобождается автоматически при GC
– Освобождение вручную:
((sun.nio.ch.DirectBuffer) buf).cleaner().clean();
• Unsafe.allocateMemory / freeMemory
Решения для off-heap кешей
• JSR 107: javax.cache
– Ehcache, Coherence
• Apache DirectMemory
• MapDB
• Chronicle Map
• one-nio
Требования к кешам
• Ключи и значения произвольных типов
– Long, String, byte[], сериализованные объекты
• Быстродействие
• Атомарные операции: read-modify-write
• До 384 GB RAM, до 100 млн. объектов
• Экспирация по времени
• Вытеснение LRU
• Персистентность
Персистентность
• Решает проблему холодного старта
• 2 уровня
– Сохранение между перезапусками приложения
– Снимки на диске (snapshots)
• Создание снимков
– Stop-the-world
– По сегментам
– Copy-on-write (fork trick)
Shared Memory
• Механизм IPC
– Linux: /dev/shm
– Поддерживается sendfile()
• Создание объекта Shared Memory в Java
– new RandomAccessFile("/dev/shm/cache", "rw");
• Отображение в адресное пространство:
– FileChannel.map()  MappedByteBuffer
– 2GB, no unmapping
Mapping > 2GB
// Mapping
Method map0 = FileChannelImpl.class.getDeclaredMethod(
"map0", int.class, long.class, long.class);
map0.setAccessible(true);
long addr = (Long) map0.invoke(f.getChannel(), 1, 0L, f.length());
// Unmapping
Method unmap0 = FileChannelImpl.class.getDeclaredMethod(
"unmap0", long.class, long.class);
unmap0.setAccessible(true);
unmap0.invoke(null, addr, length);
Проблема абсолютных адресов
• Только относительная адресация
– Хранение смещений вместо адресов
• Relocation
– Сдвиг всех абсолютных адресов на старте
Распределение памяти
• Doug Lea’s malloc
• one.nio.mem.Malloc, MallocMT
16 24 32 48 … 256 384 … 1G
sz sz sz sz sz sz
Кеши в one-nio
SharedMemoryLongMap
Long  V
SharedMemoryStringMap
String  V
SharedMemoryBlobMap
Long  byte[]
OffheapBlobMap
byte[]  byte[]
OffheapMap
K  V
SharedMemoryMap
K  V
Устройство кеша
0 addr 0addr…
hashCode(key) % capacity
hash time next
key (?)
value
hash time 0
key (?)
value
0
hash time 0
key (?)
value
entry
Возможности кеша
• Потокобезопасность
– get, put, remove, lockRecordForRead/Write
• Прямой доступ к off-heap, сериализация
• Поддержка shared memory
• Стратегии очистки
– BasicCleanup (TTL), SamplingCleanup (LRU)
План доклада
• Архитектура ОК
• Работа с сетью
• Удалённые вызовы и сериализация
• Кеширование
• Паузы JVM, оптимизация GC
Паузы JVM
• Требования к latency
– хорошо: 100 мс
– плохо: 1 с
• GC
– ParNew
– CMS (initial mark, remark)
• G1 GC
– -XX:MaxGCPauseMillis=200
– Много улучшений в 8u40
Тюнинг GC
-XX:+PrintGCDetails
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintClassHistogramBeforeFullGC
-XX:+PrintClassHistogramAfterFullGC
-XX:+PrintPromotionFailure
Тюнинг GC
-XX:+UseConcMarkSweepGC
-XX:+ExplicitGCInvokesConcurrent
-XX:+CMSClassUnloadingEnabled (default in 8)
-XX:+UnlockDiagnosticVMOptions
-XX:ParGCCardsPerStrideChunk=32768
Тюнинг GC
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=75
-XX:CMSWaitDuration=10000
-XX:+CMSScavengeBeforeRemark
-XX:+ParallelRefProcEnabled
-XX:+CMSParallelInitialMarkEnabled (default in 8)
Паузы JVM
• VM operations
– Thread dump, heap dump, debugging
– Biased lock revocation (-XX:-UseBiasedLocking)
– Deoptimization
-XX:+PrintSafepointStatistics
-XX:PrintSafepointStatisticsCount=1
Safepoint sync
• Непрерываемые операции
– System.arraycopy(), clone(), ByteBuffer.get()
– MappedByteBuffer I/O
-XX:+SafepointTimeout
-XX:SafepointTimeoutDelay=1000
GC-friendly структуры
class Entry {
long key;
Object value;
}
Entry[] entries;
long[] keys;
Object[] values;
class Blob {
long offset;
int length;
byte[] sha1_hash;
}
class Blob {
long offset;
int length;
int hash0, hash1, hash2,
hash3, hash4;
}
GC-friendly структуры
class Props {
Map<String, String> map;
}
class Props extends HashMap<String, String>
• String  char[] или byte[]
• ByteBuffer wrappers
GC-friendly структуры
• LinkedList  ArrayList
• HashMap  open-address hash table
• Коллекции примитивов (Trove)
• BitSet(100 000)  100 x BitSet(1000)
Спасибо!
• Наш Open Source
– https://github.com/odnoklassniki
• Блог
– http://habrahabr.ru/company/odnoklassniki/blog/
• Контакты
– andrey.pangin@corp.mail.ru
• Работа в ОК
– http://v.ok.ru

More Related Content

PDF
Caching data outside Java Heap and using Shared Memory in Java
PDF
Java tricks for high-load server programming
PDF
Выжимаем из сервера максимум (Андрей Паньгин)
PDF
Незаурядная Java как инструмент разработки высоконагруженного сервера
PDF
Распределенные системы в Одноклассниках
PDF
Unsafe: to be or to be removed?
PDF
Очередной скучный доклад про логгирование
PPTX
Multithreading in java past and actual
Caching data outside Java Heap and using Shared Memory in Java
Java tricks for high-load server programming
Выжимаем из сервера максимум (Андрей Паньгин)
Незаурядная Java как инструмент разработки высоконагруженного сервера
Распределенные системы в Одноклассниках
Unsafe: to be or to be removed?
Очередной скучный доклад про логгирование
Multithreading in java past and actual

What's hot (20)

PPTX
Bytecode
PDF
PPT
Проект «Одноклассники» Mail.Ru Group, Андрей Паньгин
PDF
Использование юнит-тестов для повышения качества разработки
PDF
Как сделать ваш JavaScript быстрее
PPTX
Java threads - part 2
PPTX
PDF
Мониторинг ожиданий в PostgreSQL / Курбангалиев Ильдус (Postgres Professional)
PPTX
Java 8. Thread pools
PDF
Борис Сазонов, RAII потоки и CancellationToken в C++
PPTX
Java threads - part 3
PPTX
Михаил Щербаков "WinDbg сотоварищи"
PDF
Zagursky
PDF
Web осень 2013 лекция 1
PDF
Парсим CSS: performance tips & tricks
PDF
Инструменты для з̶а̶х̶в̶а̶т̶а̶ ̶м̶и̶р̶а̶ отладки в Tarantool
PDF
JavaDay'14
PDF
Практика Lock-free. RealTime-сервер
PPTX
WinDbg со товарищи
PDF
Павел Довгалюк, Обратная отладка
Bytecode
Проект «Одноклассники» Mail.Ru Group, Андрей Паньгин
Использование юнит-тестов для повышения качества разработки
Как сделать ваш JavaScript быстрее
Java threads - part 2
Мониторинг ожиданий в PostgreSQL / Курбангалиев Ильдус (Postgres Professional)
Java 8. Thread pools
Борис Сазонов, RAII потоки и CancellationToken в C++
Java threads - part 3
Михаил Щербаков "WinDbg сотоварищи"
Zagursky
Web осень 2013 лекция 1
Парсим CSS: performance tips & tricks
Инструменты для з̶а̶х̶в̶а̶т̶а̶ ̶м̶и̶р̶а̶ отладки в Tarantool
JavaDay'14
Практика Lock-free. RealTime-сервер
WinDbg со товарищи
Павел Довгалюк, Обратная отладка
Ad

Similar to Developing highload servers with Java (20)

PDF
андрей паньгин
PDF
BigMemory - работа с сотнями миллионов бизнес-объектов / Дмитрий Хмаладзе (Ag...
PDF
CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...
PDF
Как мы храним 75 млн пользователей (Денис Бирюков)
PDF
Олег Анастасьев "Ближе к Cassandra". Выступление на Cassandra Conf 2013
PDF
"Optimizing Memory Footprint in Java" @ JEEConf 2013, Kiev, Ukraine
PPT
Как построить высокопроизводительный Front-end сервер (Александр Крижановский)
PDF
Новые возможности распределенной обработки данных в памяти (Coherence)
PDF
Анатомия веб-сервиса, Андрей Смирнов
PDF
Анатомия веб-сервиса (РИТ-2014)
PDF
Там, где Rails не справляются
PPT
An internal look at HotSpot JVM
PPTX
Акулов Егор, Mail.ru Group
PPTX
Dz Java Hi Load 0.4
PPTX
Everything you wanted to know about writing async, high-concurrency HTTP apps...
PDF
12 - Java. Разработка сетевых приложений на Java
PPTX
Industrial Programming Java - Lection Pack 02 - Distributed applications - La...
PPT
phpConf 2010 Классификация систем хранения
PPTX
Проблемы производительности open source библиотек
PPTX
Производительность open source решений
андрей паньгин
BigMemory - работа с сотнями миллионов бизнес-объектов / Дмитрий Хмаладзе (Ag...
CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...
Как мы храним 75 млн пользователей (Денис Бирюков)
Олег Анастасьев "Ближе к Cassandra". Выступление на Cassandra Conf 2013
"Optimizing Memory Footprint in Java" @ JEEConf 2013, Kiev, Ukraine
Как построить высокопроизводительный Front-end сервер (Александр Крижановский)
Новые возможности распределенной обработки данных в памяти (Coherence)
Анатомия веб-сервиса, Андрей Смирнов
Анатомия веб-сервиса (РИТ-2014)
Там, где Rails не справляются
An internal look at HotSpot JVM
Акулов Егор, Mail.ru Group
Dz Java Hi Load 0.4
Everything you wanted to know about writing async, high-concurrency HTTP apps...
12 - Java. Разработка сетевых приложений на Java
Industrial Programming Java - Lection Pack 02 - Distributed applications - La...
phpConf 2010 Классификация систем хранения
Проблемы производительности open source библиотек
Производительность open source решений
Ad

Developing highload servers with Java