SlideShare a Scribd company logo
Реактивный раздатчик
ok.ru/music
Вадим Цесько
Одноклассники
• 71M пользователей (MAU)
• 7000 машин в 4 ДЦ
• 2 Тб/с1
• До 100К запросов/с на ноду (4 ядра)
• 99% < 100 мс
• Java
1
Без учёта CDN
1
ok.ru/music
2
Раздатчик ok.ru/music
3
Раздатчик ok.ru/music
• Раздаёт музыку с 2010
• ≤ 100 Гб/с
• ≤ 500K соединений
• Кеширующий фронтенд перед
one-blob-storage2
+ one-cold-storage3
2
http://profyclub.ru/docs/174
3
http://2017.jokerconf.com/2017/talks/4fasygftomyekgaqaaiauo/
4
Длинный хвост
5
Must have
• До 100K «медленных» клиентов на ноду
• Масштабируемость
• Отказоустойчивость
6
Масштабировать
Что:
• Пропускную способность кластера
• Суммарную ёмкость кеша кластера
Как:
• Горизонтально: ДЦ и машины
• Вертикально: диски и RAM
7
Эффект масштаба
DC1
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4
DC2
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4
DC3
Node 2disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4 DC4
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4
8
Отказ диска
DC1
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4
DC2
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
XXX
disk4
DC3
Node 2disk1
disk2
disk3
disk4
Node 1
XXX
disk2
disk3
disk4 DC4
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4
9
Отказ машины
DC1
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4
DC2
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4
DC3
XXXXXX
XXX
XXX
XXX
Node 1
disk1
disk2
disk3
disk4 DC4
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4
10
Отказ ДЦ
DC1
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4
DC2
Node 2
disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4
DC3
Node 2disk1
disk2
disk3
disk4
Node 1
disk1
disk2
disk3
disk4 XXX
XXX
XXX
XXX
XXX
XXX
XXX
XXX
XXX
XXX
XXX
11
Всё (с)ломается4
• Прорабатываем сценарии отказов
• ДЦ
• Машины
• Диски
• Резервируем
• Реплицируем данные
• Запас по пропускной способности
4
https://techtrain.ru/talks/1pqtojnosesumeo00ayccm/
12
Балансировка запросов
• По ДЦ
• Манёвры
• Аварии
• По нодам внутри ДЦ
• С весами
• Плавный ввод в ротацию
• Нагрузочное тестирование
13
Путь запроса
Frontend
DC1
Node 1
Node 2
Node 3
Balancer
w=100
w=1
w=100
DC2
Balancer
Node 3
Node 2
Node 1
GSLB
DNS
w=100
w=1
w=100
14
https://ok.ru/music
Frontend
DC1
Node 1
Node 2
Node 3
Balancer
w=100
w=1
w=100
DC2
Balancer
Node 3
Node 2
Node 1
GSLB
DNS
w=100
w=1
w=100
15
musicd.mycdn.me/v0/stream?id=...
Frontend
DC1
Node 1
Node 2
Node 3
Balancer
w=100
w=1
w=100
DC2
Balancer
Node 3
Node 2
Node 1
GSLB
DNS
w=100
w=1
w=100
16
5.61.23.6/v0/stream?id=...
Frontend
DC1
Node 1
Node 2
Node 3
Balancer
w=100
w=1
w=100
DC2
Balancer
Node 3
Node 2
Node 1
GSLB
DNS
w=100
w=1
w=100
17
Соединение с нодой5
Frontend
DC1
Node 1
Node 2
Node 3
Balancer
w=100
w=1
w=100
DC2
Balancer
Node 3
Node 2
Node 1
GSLB
DNS
w=100
w=1
w=100
5
http://www.highload.ru/2017/abstracts/2858.html
18
Direct Server Return
Frontend
DC1
Node 1
Node 2
Node 3
Balancer
w=100
w=1
w=100
DC2
Balancer
Node 3
Node 2
Node 1
GSLB
DNS
w=100
w=1
w=100
19
Сбой ДЦ
Frontend
DC1
Node 1
Node 2
Node 3
Balancer
w=100
w=1
w=100
XXX
XXX
XXX
XXX
XXX
GSLB
DNS
DISABLE
20
Сбой ноды
Frontend
DC1
Node 1
Node 2
Node 3
Balancer
w=100
w=1
w=100
DC2
Balancer
XXX
Node 2
Node 1
GSLB
DNS
w=0
w=1
w=100
21
Балансировка треков по нодам
• Независимые ДЦ
• Равномерно по машинам
• Репликация треков на случай отказов
• Перераспределение нагрузки при отказах
• Consistent hashing6
6
https://medium.com/@dgryski/
consistent-hashing-algorithmic-tradeoffs-ef6b8e2fcae8
22
Consistent hashing
23
Строим кольцо хешей
0
±∞
Track
hash(ID)
24
Делим интервалы между нодами
N0
N1
N2
N3
N4
N5
N6
N7
Track
25
Определяем реплики
N0
N1
N2
N3
N4
N5
N6
N7
Track
26
Отказ ноды
N0
N1
X
N3
x2
N4
N5
N6
N7
Track
27
Каскадный отказ
N0
N1
X
X
N4
x2
N5
N6
N7
Track
28
На практике vnodes ≫ nodes
Track
N0
N2
N4
N6
N0
N4
N1
N7
N1N5
N7N2
N6 N5
N3 N3
29
N1
Track
N0
N2
N4
N6
N0
N4
N1
N7
N1N5
N7N2
N6 N5
N3 N3
30
N2
Track
N0
N2
N4
N6
N0
N4
N1
N7
N1N5
N7N2
N6 N5
N3 N3
31
N3
Track
N0
N2
N4
N6
N0
N4
N1
N7
N1N5
N7N2
N6 N5
N3 N3
32
Так же определяем реплики
N0
N2
N4
N6
N0
N4
N1
N7
Track
N1N5
N7N2
N6 N5
N3 N3
33
N4 + N5
N0
N2
N4
N6
N0
N4
N1
N7
Track
N1N5
N7N2
N6 N5
N3 N3
34
Отказ ноды
N0
N2
X
N6
N0
X
N1
N7
Track
N1N5
N7N2
N6 N5
N3 N3
35
Отдача трека
Datacenter
Balancer N3
N0
N1
N2
Storage
36
Cлучайная нода
Datacenter
Balancer N3
N0
N1
N2
Storage
37
Проксируем
Datacenter
Balancer Proxy
R0
R1
Storage
38
Ищем локально
Datacenter
Balancer Proxy
R0
R1
Storage
39
Подтягиваем данные
Datacenter
Balancer Proxy
R0
R1
Storage
40
Сохраняем
Datacenter
Balancer Proxy
R0
R1
Storage
41
Отдаём с диска
Datacenter
Balancer Proxy
R0
R1
Storage
42
Сбой диска
Datacenter
Balancer Proxy
R0
R1
XXX Storage
43
Сбой реплики
Datacenter
Balancer Proxy
XXX
R1
Storage
44
Нода изнутри
External
API
45
Проверка подписи
Security
check
External
API
46
Добавление IDv3
IDv3
tagging
Security
check
External
API
47
Определение реплик
IDv3
tagging
Security
check
Router
External
API
48
Проксируем с соседа
Proxy
client
IDv3
tagging
Security
check
Router
External
API
Internal
API
49
Отдаём локально
Caching
storage
Proxy
client
IDv3
tagging
Security
check
Router
External
API
Internal
API
50
Hit
Disk N
Caching
storage
Disk ...
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
51
Miss
Disk N
Caching
storage
Disk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
52
Пусть 120 Гб/с...
DC 1
Node Node
Node Node
40 Gbps
DC 2
Node Node
Node Node
40 Gbps
DC 3
Node Node
Node Node
40 Gbps
53
-1 ДЦ
DC 1
Node Node
Node Node
60 Gbps
DC 2
DC 3
Node Node
Node Node
60 Gbps
54
Ещё и релиз
DC 1
Node Node
Node
60 Gbps
DC 2
DC 3
Node Node
Node
60 Gbps
55
С ноды
DC 2
DC 1
Node Node
Node
20 Gbps
20 Gbps
20Gbps
DC 3
Node
Node
Node
20 Gbps
20Gbps
20 Gbps
56
RF = 2 ⇒ 50% проксируется
DC 2
DC 1
Node Node
Node
20 Gbps
20 Gbps
20Gbps
DC 3
Node
Node Node
20Gbps
20 Gbps
20 Gbps
57
Итого одна нода
• Отдаёт пользователям 20 Гб/с
• Из них 10 Гб/с проксирует
• И отдаёт соседям-прокси 10 Гб/с
• В итоге наружу 30 Гб/с, из них 20 Гб/с с дисков
• 512 ГБ RAM вместит ≈ 50K горячих треков
• ≈ 30-40% хвоста провалится в диски
• ≈ 8 Гб/с с дисков
58
Как хранить данные?
• Трек = файл?
• Десятки ТБ
• Миллионы файлов
• Накладные расходы на метаданные
• Тянуть треки только сначала
• Хранить треки только целиком
• Так мы не делаем
59
Трек = N x 256 КБ блоков (SSD)
Block 0
256 KB
Block 1
256 KB ... Block n-1
256 KB 256 KB x 4 M blocks = 1 TB
• Каждый диск — независимое хранилище
• hash(track, block_num) чтобы размазать блоки
• Page cache ОС
60
Как хранить блоки?
• Один файл на XFS размером с диск
• xfs_io -c resvsp 0 ...
• Сырое блочное устройство
• new RandomAccessFile("/dev/sdc", "rw")
Блочное устройство vs файл на XFS:
• LA в 2 раза ниже
• Запись в 1.5 раза быстрее
• Время ответа в 2-3 раза ниже
61
Индекс
Track ID Offset Block ID Total track
size
• 29 байт на блок (≈ 1 ГБ на 10 ТБ блоков)
62
Total track size
Track ID Offset Block ID Total track
size
• 29 байт на блок (≈ 1 ГБ на 10 ТБ блоков)
63
Total track size
64
Как хранить?
• In-memory
• Компактно
• Персистентно
• Вытеснение LRU7
• Thread-safe
• SharedMemoryFixedMap8
на tmpfs
7
https://github.com/ben-manes/caffeine/wiki/Efficiency
8
https://github.com/odnoklassniki/one-nio
65
Durability
• Рестарт машины — теряем tmpfs
• Падение процесса — неконсистентность
• Snapshot
• WAL
66
Порядок операций
Track ID Offset Block ID Block
generation
Total track
size
67
Snapshot + WAL
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
1.mp3 1 7 18 10 MB
Snapshot 42
WAL 42
2.mp3 0 9 21 15 MB
68
Пишем в snapshot
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
1.mp3 1 7 18 10 MB
Snapshot 42
1.mp3,0 → 3,17,10MB*
WAL 42
2.mp3 0 9 21 15 MB
69
Пишем в snapshot
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
1.mp3 1 7 18 10 MB
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB*
WAL 42
2.mp3 0 9 21 15 MB
70
Вытеснение в WAL
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
7 18
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB
WAL 42
7,18 dirty*
2.mp3 0 9 21 15 MB
71
Вытеснение в WAL
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
7 18
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB
WAL 42
7,18 dirty
9,21 dirty*
9 21
72
Переиспользование блока
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
7 18
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB
WAL 42
7,18 dirty
9,21 dirty
3.mp3 0 9 22 8 MB
73
Заканчиваем snapshot
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
7 18
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB
3.mp3,0 → 9,22,8MB*
WAL 42
7,18 dirty
9,21 dirty
3.mp3 0 9 22 8 MB
74
В итоге
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB
3.mp3,0 → 9,22,8MB
WAL 42
7,18 dirty
9,21 dirty
3.mp3 0 9 22 8 MB
75
Восстанавливаем
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB
3.mp3,0 → 9,22,8MB
WAL 42
7,18 dirty
9,21 dirty
3.mp3 0 9 22 8 MB
Track ID Offset Block ID Generation Track size
76
Сканируем WAL
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB
3.mp3,0 → 9,22,8MB
Dirty
3.mp3 0 9 22 8 MB
Block ID Generation
7 18
9 21
Track ID Offset Block ID Generation Track size
77
Обычная запись
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
Snapshot 42
1.mp3,0 → 3,17,10MB*
1.mp3,1 → 7,18,10MB
3.mp3,0 → 9,22,8MB
3.mp3 0 9 22 8 MB
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
Dirty
Block ID Generation
7 18
9 21
78
Вытесненная запись
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB*
3.mp3,0 → 9,22,8MB
3.mp3 0 9 22 8 MB
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
Dirty
Block ID Generation
7 18
9 21
79
Переиспользованный блок
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB
3.mp3,0 → 9,22,8MB*
3.mp3 0 9 22 8 MB
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
3.mp3 0 9 22 8 MB
Dirty
Block ID Generation
7 18
9 21
80
Успех
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
Snapshot 42
1.mp3,0 → 3,17,10MB
1.mp3,1 → 7,18,10MB
3.mp3,0 → 9,22,8MB
3.mp3 0 9 22 8 MB
Track ID Offset Block ID Generation Track size
1.mp3 0 3 17 10 MB
3.mp3 0 9 22 8 MB
Dirty
Block ID Generation
7 18
9 21
81
Уберите детей от экранов
Disclaimer
Your mileage will vary.
82
Page cache
• < 20% попаданий9
• Read ahead?
Mem.posix_fadvise(..., POSIX_FADV_RANDOM)10
:
• > 70% попаданий
• В 2 раза меньше чтений с диска
• HTTP latency на 20% ниже
9
fs/cachestat from https://github.com/brendangregg/perf-tools
10
https://github.com/odnoklassniki/one-nio
83
-XX:+UseHugeTLBFS
• -Xmx24g
• GC Time/Safepoint Total Time на 20-30% ниже
• Более равномерная загрузка ядер
• Но нет эффекта на HTTP latency
84
Инцидент
1 В саппорте жалобы
2 Сузили круг поиска до одной машины
3 Машину недавно перезапускали...
85
До перезагрузки
/dev/sddsdd.index
/dev/sdcsdc.index
Track Offset Block Content
GY!BE 5 0 GY!BE
Múm 3 1 Múm
Daft Punk 4 2 Daft Punk
... ... ... ...
Track Offset Block Content
Стас Михайлов 0 0 Стас Михайлов
Звери 11 1 Звери
Грибы 7 2 Грибы
... ... ... ...
86
До перезагрузки
/dev/sddsdd.index
/dev/sdcsdc.index
Track Offset Block Content
GY!BE 5 0 GY!BE
Múm 3 1 Múm
... ... ... ...
Track Offset Block Content
Стас Михайлов 0 0 Стас Михайлов
Звери 11 1 Звери
Грибы 7 2 Грибы
... ... ... ...
Daft Punk 4 2 Daft Punk
87
До перезагрузки
/dev/sddsdd.index
/dev/sdcsdc.index
Track Offset Block Content
GY!BE 5 0 GY!BE
Múm 3 1 Múm
Daft Punk 4 2 Daft Punk
... ... ... ...
Track Offset Block Content
Звери 11 1 Звери
Грибы 7 2 Грибы
... ... ... ...
Стас Михайлов 0 0 Стас Михайлов
88
После перезагрузки11
sdd.index
sdc.index
Track Offset
Block Content
GY!BE 5
0 GY!BE
Múm 3
1 Múm
Daft Punk 4
2 Daft Punk
... ...
... ...
/dev/sdd
Track Offset
Block Content
Стас Михайлов 0
0 Стас Михайлов
Звери 11
1 Звери
Грибы 7
2 Грибы
... ...
... ...
/dev/sdc
11
https://wiki.archlinux.org/index.php/Persistent_block_device_naming 89
Party mode
/dev/sdc
sdd.index /dev/sdd
sdc.index
Track Offset
Block Content
0 GY!BE
Múm 3
1 Múm
Daft Punk 4
2 Daft Punk
... ...
... ...
Track Offset
Block Content
Стас Михайлов 0
Звери 11
1 Звери
Грибы 7
2 Грибы
... ...
... ...
GY!BE 5 0 Стас Михайлов
90
Party mode
/dev/sdc
sdd.index /dev/sdd
sdc.index
Track Offset
Block Content
1 Múm
2 Daft Punk
... ...
Track Offset
Block Content
Звери 11
Грибы 7
... ...
GY!BE 5 0 Стас Михайлов
Múm 3
Daft Punk 4
... ...
1 Звери
2 Грибы
... ...
0 GY!BEСтас Михайлов 0
91
Fix
• Персистентный World Wide Name12
• /dev/disk/by-id/wwn-* в качестве ID
• Индексов
• Snapshot
• WAL
12
https://en.wikipedia.org/wiki/World_Wide_Name
92
Распределённая отладка
Disk N
Caching
storage
Disk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
93
TraceID13-метка в запросах
1 GET /v0/stream?id=v0_10000051227 HTTP/1.1
2 Range: bytes=10878976-11141119
3 X-OK-Trace-ID: 570752372832:bec:v0_10000051227
13
See OpenTracing/Zipkin
94
При отладке TraceID в логах
1 2018-09-13 17:40:40,147 DEBUG
2 [cache-provider-4] CachingDataProvider:
3 -> [570752372832:bec:v0_10000051227]
4 Serving chunk from cache:
5 Chunk[10878976-11010047/16346382]
95
Как отправлять данные?
1 ByteBuffer buffer = ByteBuffer.allocate(size);
2 int count = fileChannel.read(buffer, position);
3 if (count <= 0) {
4 // ...
5 }
6 buffer.flip();
7 socketChannel.write(buffer);
96
97
sendfile()
1 final RandomAccessFile blocks;
2
3 int write(Socket socket) {
4 if (socket.getSslContext() == null) {
5 socket.sendFile(blocks, offset, size);
6 }
• Zero-copy, но только не SSL
98
В случае SSL
1 ByteBuffer buffer = ByteBuffer.allocate(size);
2 int count = fileChannel.read(buffer, position);
3 if (count <= 0) {
4 // ...
5 }
6 buffer.flip();
7 socketChannel.write(buffer);
99
IOUtil
1 ByteBuffer bb =
Util.getTemporaryDirectBuffer(dst.remaining());
2 try {
3 int n = readIntoNativeBuffer(fd, bb, position, nd);
4 bb.flip();
5 if (n > 0)
6 dst.put(bb);
7 return n;
8 } finally {
9 Util.offerFirstTemporaryDirectBuffer(bb);
10 }
100
one-nio: DirectMemory и друзья
1 final Allocator allocator =
2 new MallocMT(size, concurrency);
3
4
5
6
7
8
9
10 ...
101
Если SSL...
1 final Allocator allocator =
2 new MallocMT(size, concurrency);
3
4 int write(Socket socket) {
5 if (socket.getSslContext() != null) {
6
7
8
9
10 ...
102
Выделяем нативный буфер
1 final Allocator allocator =
2 new MallocMT(size, concurrency);
3
4 int write(Socket socket) {
5 if (socket.getSslContext() != null) {
6 long address = allocator.malloc(size);
7
8
9
10 ...
103
Оборачиваем в ByteBuffer
1 final Allocator allocator =
2 new MallocMT(size, concurrency);
3
4 int write(Socket socket) {
5 if (socket.getSslContext() != null) {
6 long address = allocator.malloc(size);
7 ByteBuffer buf =
8 DirectMemory.wrap(address, size);
9
10 ...
104
Читаем
1 final Allocator allocator =
2 new MallocMT(size, concurrency);
3
4 int write(Socket socket) {
5 if (socket.getSslContext() != null) {
6 long address = allocator.malloc(size);
7 ByteBuffer buf =
8 DirectMemory.wrap(address, size);
9 int available = channel.read(buf, offset);
10 ...
105
Пишем
1 final Allocator allocator =
2 new MallocMT(size, concurrency);
3
4 int write(Socket socket) {
5 if (socket.getSslContext() != null) {
6 long address = allocator.malloc(size);
7 ByteBuffer buf =
8 DirectMemory.wrap(address, size);
9 int available = channel.read(buf, offset);
10 socket.writeRaw(address, available, flags);
106
One more thing...
Disk N
Caching
storage
Disk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
107
Очень много клиентов
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Disk NDisk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
Caching
storage
108
Варианты14
Клиент = Thread:
• Синхронно
• 100K потоков?!
• Нежизнеспособно
Клиент = конвейер:
• Асинхронно
• Стадия — пул потоков
• Push данных клиенту
14
https://thestrangeloop.com/2017/zuuls-journey-to-non-blocking.html
109
Асинхронный push
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Disk NDisk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
Caching
storage
110
Бекенды гораздо быстрее
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Disk NDisk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
Caching
storage
111
Если неограниченные очереди
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Internal
API
External
API
Router
Security
check
IDv3
tagging
Proxy
client
Caching
storage
Disk NDisk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
RouterOOM
Internal
API
Caching
storage
112
Reactive streams15 to the rescue
Subscriber Publisher
demand
data
• Subscriber управляет скоростью
• Память ограничена demand
• Subscriber быстрее — push
• Publisher быстрее — pull
15
http://www.reactive-streams.org
113
Конвейер
Disk N
Caching
storage
Disk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
114
Reactive Stream
Disk N
Caching storage
Disk ...
Storage
Proxy client
IDv3 taggingSecurity check
Disk 0
Router
External
API
Internal
API
Pub Sub Pub Sub
Publisher
Pub Sub
115
1 interface Publisher<T> {
2 void subscribe(Subscriber<? super T> s);
3 }
4 interface Subscriber<T> {
5 void onSubscribe(Subscription s);
6 void onNext(T t);
7 void onError(Throwable t);
8 void onComplete();
9 }
10 interface Subscription {
11 void request(long n);
12 void cancel();
116
Поток Chunkов
1 interface Chunk {
2 int read(ByteBuffer dst);
3 int write(Socket socket);
4 void write(FileChannel channel, long offset);
5 }
• Ссылка на данные
• Ограниченный интерфейс
• Множество реализаций
117
Chunk over RandomAccessFile
Disk N
Caching
storage
Disk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
RandomAccessFile file;
long offset;
int limit;
118
Chunk over Socket
Disk N
Caching
storage
Disk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
Socket socket;
int position;
int size;
119
Chunk over ByteBuffer
Disk N
Caching
storage
Disk ...
Storage
Proxy
client
IDv3
tagging
Security
check
Disk 0
Router
External
API
Internal
API
ByteBuffer buf;
120
Неблокирующий API16
1 interface Subscriber<T> {
2 void onSubscribe(Subscription s);
3 void onNext(T t);
4 void onError(Throwable t);
5 void onComplete();
6 }
7 interface Subscription {
8 void request(long n);
9 void cancel();
16
https://jokerconf.com/2018/talks/6wmp33pmjgism04u4wckgy/
121
Чтение на ночь
122
В духе Typed Actor Model17
• Вызов метода → сообщение
• Сообщение — в Queue
• Шедулимся на Executor
• Обрабатываем последовательно
17
https://github.com/reactive-streams/reactive-streams-jvm/tree/master/examples
123
Reactive Stream
Disk N
Caching storage
Disk ...
Storage
Proxy client
IDv3 taggingSecurity check
Disk 0
Router
External
API
Internal
API
Pub Sub Sub
Publisher
Pub Sub
Pub
124
Stage A
executor
Stage B
executor
Sub Pub
125
Stage A
executor
Stage B
executor
PubSub
126
Stage A
executor
Stage B
executor
PubSub
request()
127
Stage A
executor
Stage B
executor
Sub Pub
request()
128
Stage A
executor
Stage B
executor
Sub Pub
request()
129
Stage A
executor
Stage B
executor
PubSub
request()
130
Stage A
executor
Stage B
executor
Sub Pub
request()
131
Stage A
executor
Stage B
executor
Sub Pub
132
Stage A
executor
Stage B
executor
Sub Pub
133
Stage A
executor
Stage B
executor
Sub Pub
134
Stage A
executor
Stage B
executor
Sub Pub
onNext()
135
Stage A
executor
Stage B
executor
PubSub
onNext()
136
Stage A
executor
Stage B
executor
PubSub
onNext()
137
Stage A
executor
Stage B
executor
PubSub
138
Состояние
1 // Incoming messages
2 final Queue<M> mailbox;
3
4 // Message processing works here
5 final Executor executor;
6
7 // To ensure HB relationship between runs
8 final AtomicBoolean on = new AtomicBoolean();
139
Асинхронизация
1 @Override
2 void request(final long n) {
3 enqueue(new Request(n));
4 }
5
6 void enqueue(M message) {
7 mailbox.offer(message);
8 tryScheduleToExecute();
9 }
140
tryScheduleToExecute()
1 if (on.compareAndSet(false, true)) {
2 try {
3 executor.execute(this);
4 } catch (Exception e) {
5 ...
6 }
7 }
141
run()
1 if (on.get())
2 try {
3 dequeueAndProcess();
4 } finally {
5 on.set(false);
6 if (!messages.isEmpty()) {
7 tryScheduleToExecute();
8 }
9 }
10 }
142
dequeueAndProcess()
1 M message;
2 while ((message = mailbox.poll()) != null) {
3 // Pattern match
4 if (message instanceof Request) {
5 doRequest(((Request) message).n);
6 } else {
7 ...
8 }
9 }
143
В итоге
• Неблокирующая реализация
• Простой последовательный код
• Никакого contention
• Ограниченное количество потоков
144
Production
• 12 машин (2x запас)
• До 20 Гб/с с машины через 100К соединений
• Масштабируемость
• Пропускная способность
• Ёмкость
• Отказоустойчивость
• ДЦ
• Машины
• Диски
• Java + one-nio
145
99%, мс
146
99%, мс (upstream)
147
75%, мс (с дисков)
148
High Load
+
Reactive Streams
=
149
Вопросы?
Вадим Цесько
Одноклассники
https://v.ok.ru
https://incubos.org
150
CDN cache hit
1
Backlog
• Адаптивный фактор репликации
• Read repair
• Touch/prefetch
• Hash ring поверх дисков
• Rendezvous hashing18
• Асинхронный HTTP клиент
• Open-source one-download
18
https://en.wikipedia.org/wiki/Rendezvous_hashing
2

More Related Content

PDF
Базы данных. MongoDB
Vadim Tsesko
 
PDF
Базы данных. Введение
Vadim Tsesko
 
PDF
Введение. Key-value.
Vadim Tsesko
 
PDF
2014.09.24 история небольшого успеха с PostgreSQL (Yandex)
Nikolay Samokhvalov
 
PDF
История успеха Яндекс.Почты
dev1ant
 
PDF
5 способов деплоя PHP-кода в условиях хайлоада / Юрий Насретдинов (Badoo)
Ontico
 
PPTX
Татьяна Новикова (Казахстан), ЦАРКА. Как мы мониторим Казнет с помощью WebTotem
KazHackStan
 
PDF
Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт...
Ontico
 
Базы данных. MongoDB
Vadim Tsesko
 
Базы данных. Введение
Vadim Tsesko
 
Введение. Key-value.
Vadim Tsesko
 
2014.09.24 история небольшого успеха с PostgreSQL (Yandex)
Nikolay Samokhvalov
 
История успеха Яндекс.Почты
dev1ant
 
5 способов деплоя PHP-кода в условиях хайлоада / Юрий Насретдинов (Badoo)
Ontico
 
Татьяна Новикова (Казахстан), ЦАРКА. Как мы мониторим Казнет с помощью WebTotem
KazHackStan
 
Архитектура растущего проекта на примере ВКонтакте / Алексей Акулович (ВКонт...
Ontico
 

What's hot (20)

PPTX
Иван Чалыкин (Россия), Digital Security. Легальный SOP Bypass. Проблемы внедр...
KazHackStan
 
PDF
Базы данных. Lucene
Vadim Tsesko
 
PDF
Cassandra
Vadim Tsesko
 
PDF
Technopolis.NoSQL 03 Haystack
Vadim Tsesko
 
PDF
Андрей Абакумов (Россия). Yandex.ru. Соавтор: Эльдар Заитов. Автоматизация ск...
KazHackStan
 
PPTX
Системный администратор Vkontakte. Как? / Антон Кирюшкин (Vkontakte)
Ontico
 
PDF
Оптимизация high-contention write в PostgreSQL / Александр Коротков, Олег Бар...
Ontico
 
PDF
Базы данных. Haystack
Vadim Tsesko
 
PPTX
Эволюция программно-аппаратного обеспечения хранения фотографий в Badoo / Дми...
Ontico
 
PPTX
Flashcache в mamba.ru / Яковлев Александр Юрьевич (ЗАО Мамба)
Ontico
 
PDF
Technopolis.NoSQL 01
Vadim Tsesko
 
PDF
Haystack
Vadim Tsesko
 
PPTX
Алексей Морозов (Россия), Rambler.ru. ASP.NET в помощь хакеру и не только....
KazHackStan
 
PDF
PostgreSQL worst practices / Илья Космодемьянский (Data Egret)
Ontico
 
PDF
Базы данных. Hash & Cache
Vadim Tsesko
 
PDF
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Ontico
 
PDF
Архитектура хранилища бинарных данных на Одноклассниках (Александр Христофоро...
Ontico
 
PDF
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
Ontico
 
PPTX
Шамбулов У. К. (Казахстан), ГТС. Анализ и исследование инцидентов информацион...
KazHackStan
 
PDF
Олег Анастасьев "Ближе к Cassandra". Выступление на Cassandra Conf 2013
it-people
 
Иван Чалыкин (Россия), Digital Security. Легальный SOP Bypass. Проблемы внедр...
KazHackStan
 
Базы данных. Lucene
Vadim Tsesko
 
Cassandra
Vadim Tsesko
 
Technopolis.NoSQL 03 Haystack
Vadim Tsesko
 
Андрей Абакумов (Россия). Yandex.ru. Соавтор: Эльдар Заитов. Автоматизация ск...
KazHackStan
 
Системный администратор Vkontakte. Как? / Антон Кирюшкин (Vkontakte)
Ontico
 
Оптимизация high-contention write в PostgreSQL / Александр Коротков, Олег Бар...
Ontico
 
Базы данных. Haystack
Vadim Tsesko
 
Эволюция программно-аппаратного обеспечения хранения фотографий в Badoo / Дми...
Ontico
 
Flashcache в mamba.ru / Яковлев Александр Юрьевич (ЗАО Мамба)
Ontico
 
Technopolis.NoSQL 01
Vadim Tsesko
 
Haystack
Vadim Tsesko
 
Алексей Морозов (Россия), Rambler.ru. ASP.NET в помощь хакеру и не только....
KazHackStan
 
PostgreSQL worst practices / Илья Космодемьянский (Data Egret)
Ontico
 
Базы данных. Hash & Cache
Vadim Tsesko
 
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Ontico
 
Архитектура хранилища бинарных данных на Одноклассниках (Александр Христофоро...
Ontico
 
noBackend, или Как выжить в эпоху толстеющих клиентов / Самохвалов Николай
Ontico
 
Шамбулов У. К. (Казахстан), ГТС. Анализ и исследование инцидентов информацион...
KazHackStan
 
Олег Анастасьев "Ближе к Cassandra". Выступление на Cassandra Conf 2013
it-people
 
Ad

Similar to Реактивный раздатчик ok.ru/music (20)

PDF
Extreme Cloud Storage on FreeBSD, Андрей Пантюхин
Fuenteovejuna
 
PDF
Extreme cloud storage on free bsd (Андрей Пантюхин)
Ontico
 
PDF
Isilapp — Extreme Cloud Storage on FreeBSD
Andrew Pantyukhin
 
ODP
распределенное файловое хранилище (Nginx, zfs, perl). перепелица мамонтов. зал 2
rit2011
 
PPTX
Проектирование высоконагруженного масштабируемого веб-сервиса в облаке на при...
Ontico
 
PDF
Ускоряем и разгружаем веб-сервер, прозрачно кэшируя на SSD, Станислав Николов...
Ontico
 
PDF
Александр Киров — Acronis — ICBDA 2015
rusbase
 
PDF
Как мы храним 75 млн пользователей (Денис Бирюков)
Ontico
 
PDF
Олег Царев, Кирилл Коринский Сравнительный анализ хранилищ данных
Siel01
 
PPTX
02 1c-bitrix-cloud-storage
Alexander Demidov
 
PDF
9 vinogradov
leonid-mt-mt
 
PDF
Net Аpp. Лучший фундамент для облака
Yulia Sedova
 
PPTX
Проектируем облачный веб-сервис "по-взрослому" (Сергей Рыжиков)
Ontico
 
PDF
Software Defined Storage
Cisco Russia
 
PPTX
Cassandra
Ilya Medvedev
 
PDF
ekbpy'2012 - Данила Штань - Распределенное хранилище
it-people
 
PPTX
Как превратить Openstack Swift в хранилище для высоких нагрузок разных типов,...
Ontico
 
PPT
Git in Sky presentation @ HighLoad++ 2013
Serguei Gitinsky
 
PPT
SmartOS/Solaris app tuning tools/technologies on HL++ 2013
Alex Chistyakov
 
PPT
phpConf 2010 Классификация систем хранения
Slach
 
Extreme Cloud Storage on FreeBSD, Андрей Пантюхин
Fuenteovejuna
 
Extreme cloud storage on free bsd (Андрей Пантюхин)
Ontico
 
Isilapp — Extreme Cloud Storage on FreeBSD
Andrew Pantyukhin
 
распределенное файловое хранилище (Nginx, zfs, perl). перепелица мамонтов. зал 2
rit2011
 
Проектирование высоконагруженного масштабируемого веб-сервиса в облаке на при...
Ontico
 
Ускоряем и разгружаем веб-сервер, прозрачно кэшируя на SSD, Станислав Николов...
Ontico
 
Александр Киров — Acronis — ICBDA 2015
rusbase
 
Как мы храним 75 млн пользователей (Денис Бирюков)
Ontico
 
Олег Царев, Кирилл Коринский Сравнительный анализ хранилищ данных
Siel01
 
02 1c-bitrix-cloud-storage
Alexander Demidov
 
9 vinogradov
leonid-mt-mt
 
Net Аpp. Лучший фундамент для облака
Yulia Sedova
 
Проектируем облачный веб-сервис "по-взрослому" (Сергей Рыжиков)
Ontico
 
Software Defined Storage
Cisco Russia
 
Cassandra
Ilya Medvedev
 
ekbpy'2012 - Данила Штань - Распределенное хранилище
it-people
 
Как превратить Openstack Swift в хранилище для высоких нагрузок разных типов,...
Ontico
 
Git in Sky presentation @ HighLoad++ 2013
Serguei Gitinsky
 
SmartOS/Solaris app tuning tools/technologies on HL++ 2013
Alex Chistyakov
 
phpConf 2010 Классификация систем хранения
Slach
 
Ad

Реактивный раздатчик ok.ru/music