developing highload servers with java
TRANSCRIPT
![Page 1: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/1.jpg)
Разработка высоконагруженного сервера на Java
Андрей ПаньгинОдноклассники, ведущий инженер
![Page 2: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/2.jpg)
План доклада• Архитектура ОК• Работа с сетью• Удалённые вызовы и сериализация• Кеширование• Паузы JVM, оптимизация GC
![Page 3: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/3.jpg)
Факты об ОК• 8000 серверов• 48 млн. уникальных пользователей в день• 8 млн. пользователей онлайн• 300 000 web запросов в секунду• 4 ПБ данных (без учёта дублирования)
![Page 4: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/4.jpg)
Экстремальные нагрузки• На что способен один сервер – 50,000 вызовов/с в сек (push delivery)– 40 Гбит/с (video download)– 100,000 пользователей онлайн (xmpp)– 384 ГБ в памяти (cache)
• Это всё Java!
![Page 5: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/5.jpg)
Архитектура ОК
Web
Web
Mobile
Mobile
API
API
Business logic
Business logic
Business logic
Business logic
Business logic
Business logic
GraphGraphGraph
GraphGraphMessagingGraphGraphPhoto
GraphGraphFeed
BLOBstorage
SQL servers
Cassandra
ServicesBusiness layerFront-end
Storages
HTTP
RPC
RPC
![Page 6: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/6.jpg)
Внутренняя коммуникация• Удалённый вызов методов (RPC)
Business logicserver
Graph cluster
User servicecluster
long[] friendIds = getConnections (userId)
List<User> friends = getUsers (friendIds)
![Page 7: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/7.jpg)
План доклада• Архитектура ОК• Работа с сетью• Удалённые вызовы и сериализация• Кеширование• Паузы JVM, оптимизация GC
![Page 8: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/8.jpg)
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 }}
![Page 9: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/9.jpg)
Проблемы Socket I/O• 10 тыс. соединений = 10 тыс. потоков• Finalizers => утечка памяти• byte[] массивы, копирование
![Page 10: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/10.jpg)
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
![Page 11: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/11.jpg)
NIO frameworks• Apache MINA– http://mina.apache.org
• Netty– http://netty.io
• Основаны на NIO• Event-driven модель
![Page 12: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/12.jpg)
Проблемы NIO• Selector глючный, не потокобезопасный• Нельзя делать select() на blocking сокетах• Не работает setSoTimeout()• Ограниченная поддержка SSL/TLS
• Не поддерживаются все возможности ОС– TCP опции: TCP_DEFER_ACCEPT, TCP_CORK– Флаги send/recv: MSG_MORE, MSG_PEEK
![Page 13: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/13.jpg)
Решение• JNI библиотека– Tomcat Native (APR connector)– one-nio
• Управление сокетами вручную• Поддержка OpenSSL
![Page 14: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/14.jpg)
Архитектура сервера
Acceptor thread
Selector 1
Selector N
Worker thread pool
NCPU
read
read
process write
process write
![Page 15: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/15.jpg)
Пример сервера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(); }}
![Page 16: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/16.jpg)
Пример клиента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(); }}
![Page 17: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/17.jpg)
План доклада• Архитектура ОК• Работа с сетью• Удалённые вызовы и сериализация• Кеширование• Паузы JVM, оптимизация GC
![Page 18: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/18.jpg)
RPC сценарийMethod m, Object[] args
Object result
long[] friendIds = graph.getFriends(userId);
![Page 19: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/19.jpg)
Method m, Object[] args
byte[] request
Method m, Object[] args
Object result
byte[] response
Object result
Исполнение
Десериализация
Десериализация
Сериализация
Сериализация
Клиент Сервер
0.4 мс
![Page 20: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/20.jpg)
Сериализация
• Быстрая, компактная• Минимум ручной работы• Поддержка эволюции– Java Serialization– JBoss– Thrift, Avro, Protobuf– Kryo
![Page 21: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/21.jpg)
one.nio.serial• Массивы и коллекции– count obj1 … objN
• Мапы– count key1 value1 … keyN valueN
• Enum– short ordinal()
• Externalizable– readExternal / writeExternal
• Остальные Serializable– non-static non-transient fields
![Page 22: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/22.jpg)
Схема сериализации• 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
![Page 23: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/23.jpg)
Обмен схемами1. Client Server: request2. Server throws SerializerNotFoundException ?– Client Server: provideSerializer(serializer)– Goto 1
3. Deserialize response4. Client throws SerializerNotFoundException ?– Client Server: requestSerializer(uid)– Add to repository– Goto 3
![Page 24: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/24.jpg)
Особенности реализации на Java• Чтение и запись private полей– Reflection (медленно!)– sun.misc.Unsafe
• Создание экземпляров класса– sun.misc.Unsafe.allocateInstance()– Генерация байткода: http://asm.ow2.org
• Обход Java верификатора– Наследование sun.reflect.MagicAccessorImpl
![Page 25: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/25.jpg)
План доклада• Архитектура ОК• Работа с сетью• Удалённые вызовы и сериализация• Кеширование• Паузы JVM, оптимизация GC
![Page 26: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/26.jpg)
Числа, которые нужно знать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
![Page 27: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/27.jpg)
Кеширование• Что кешировать?– Данные из медленного хранилища (БД)– Результаты вычислений
• Где кешировать?– Java Heap (не подходит для объемов > 10 GB)– Off-heap memory
![Page 28: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/28.jpg)
Как выйти за пределы Heap• Native код (JNI обертки над malloc / free)– Платформозавимый
• ByteBuffer.allocateDirect– Размер буфера ≤ 2 GB– Освобождается автоматически при GC– Освобождение вручную:
((sun.nio.ch.DirectBuffer) buf).cleaner().clean();• Unsafe.allocateMemory / freeMemory
![Page 29: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/29.jpg)
Решения для off-heap кешей• JSR 107: javax.cache– Ehcache, Coherence
• Apache DirectMemory• MapDB• Chronicle Map• one-nio
![Page 30: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/30.jpg)
Требования к кешам• Ключи и значения произвольных типов– Long, String, byte[], сериализованные объекты
• Быстродействие• Атомарные операции: read-modify-write• До 384 GB RAM, до 100 млн. объектов• Экспирация по времени• Вытеснение LRU• Персистентность
![Page 31: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/31.jpg)
Персистентность• Решает проблему холодного старта• 2 уровня– Сохранение между перезапусками приложения– Снимки на диске (snapshots)
• Создание снимков– Stop-the-world– По сегментам– Copy-on-write (fork trick)
![Page 32: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/32.jpg)
Shared Memory• Механизм IPC– Linux: /dev/shm– Поддерживается sendfile()
• Создание объекта Shared Memory в Java– new RandomAccessFile("/dev/shm/cache", "rw");
• Отображение в адресное пространство:– FileChannel.map() MappedByteBuffer– 2GB, no unmapping
![Page 33: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/33.jpg)
Mapping > 2GB
// MappingMethod 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());
// UnmappingMethod unmap0 = FileChannelImpl.class.getDeclaredMethod( "unmap0", long.class, long.class);unmap0.setAccessible(true);unmap0.invoke(null, addr, length);
![Page 34: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/34.jpg)
Проблема абсолютных адресов• Только относительная адресация– Хранение смещений вместо адресов
• Relocation– Сдвиг всех абсолютных адресов на старте
![Page 35: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/35.jpg)
Распределение памяти• Doug Lea’s malloc• one.nio.mem.Malloc, MallocMT
16 24 32 48 … 256 384 … 1G
sz sz sz sz sz sz
![Page 36: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/36.jpg)
Кеши в one-nio
SharedMemoryLongMapLong V
SharedMemoryStringMapString V
SharedMemoryBlobMapLong byte[]
OffheapBlobMapbyte[] byte[]
OffheapMapK V
SharedMemoryMapK V
![Page 37: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/37.jpg)
Устройство кеша
0 addr 0addr…
hashCode(key) % capacity
hash time nextkey (?)
value
hash time 0key (?)
value
0
hash time 0key (?)
value
entry
![Page 38: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/38.jpg)
Возможности кеша• Потокобезопасность– get, put, remove, lockRecordForRead/Write
• Прямой доступ к off-heap, сериализация• Поддержка shared memory• Стратегии очистки– BasicCleanup (TTL), SamplingCleanup (LRU)
![Page 39: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/39.jpg)
План доклада• Архитектура ОК• Работа с сетью• Удалённые вызовы и сериализация• Кеширование• Паузы JVM, оптимизация GC
![Page 40: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/40.jpg)
Паузы JVM• Требования к latency– хорошо: 100 мс– плохо: 1 с
• GC– ParNew– CMS (initial mark, remark)
• G1 GC– -XX:MaxGCPauseMillis=200– Много улучшений в 8u40
![Page 41: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/41.jpg)
Тюнинг GC
-XX:+PrintGCDetails-XX:+PrintGCApplicationStoppedTime
-XX:+PrintClassHistogramBeforeFullGC-XX:+PrintClassHistogramAfterFullGC-XX:+PrintPromotionFailure
![Page 42: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/42.jpg)
Тюнинг GC
-XX:+UseConcMarkSweepGC-XX:+ExplicitGCInvokesConcurrent-XX:+CMSClassUnloadingEnabled (default in 8)
-XX:+UnlockDiagnosticVMOptions-XX:ParGCCardsPerStrideChunk=32768
![Page 43: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/43.jpg)
Тюнинг GC
-XX:+UseCMSInitiatingOccupancyOnly-XX:CMSInitiatingOccupancyFraction=75
-XX:CMSWaitDuration=10000-XX:+CMSScavengeBeforeRemark
-XX:+ParallelRefProcEnabled-XX:+CMSParallelInitialMarkEnabled (default in 8)
![Page 44: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/44.jpg)
Паузы JVM• VM operations– Thread dump, heap dump, debugging– Biased lock revocation (-XX:-UseBiasedLocking)– Deoptimization
-XX:+PrintSafepointStatistics-XX:PrintSafepointStatisticsCount=1
![Page 45: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/45.jpg)
Safepoint sync• Непрерываемые операции– System.arraycopy(), clone(), ByteBuffer.get()– MappedByteBuffer I/O
-XX:+SafepointTimeout-XX:SafepointTimeoutDelay=1000
![Page 46: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/46.jpg)
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;}
![Page 47: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/47.jpg)
GC-friendly структуры
class Props { Map<String, String> map;}
class Props extends HashMap<String, String>
• String char[] или byte[]• ByteBuffer wrappers
![Page 48: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/48.jpg)
GC-friendly структуры• LinkedList ArrayList• HashMap open-address hash table• Коллекции примитивов (Trove)
• BitSet(100 000) 100 x BitSet(1000)
![Page 49: Developing highload servers with Java](https://reader030.vdocuments.net/reader030/viewer/2022012406/55b63550bb61ebfe568b471a/html5/thumbnails/49.jpg)
Спасибо!• Наш Open Source– https://github.com/odnoklassniki
• Блог– http://habrahabr.ru/company/odnoklassniki/blog/
• Контакты– [email protected]
• Работа в ОК– http://v.ok.ru