«Одноклассники» состоят из тысяч серверов, большая часть которых участвует в онлайн-обработке запросов пользователей. Каждый из этих серверов владеет только частью данных или логики. Эти части в социальной сети изолировать друг от друга невозможно, поэтому между серверами происходит много сетевого взаимодействия — разнообразного и большого по объему. Таким образом, Одноклассники — это одна из самых больших, сложных и нагруженных распределенных систем в мире.
В этом докладе Олег расскажет об опыте построения отказоустойчивых распределенных систем на Java, основных ошибках и отказах, приемах их тестирования и диагностики. Также речь пойдет об авариях в распределенных системах и методах их предупреждения.
2. 1. Абсолютно надежная сеть
2. Мизерная сетевая задержка
3. Практически безлимитная пропускная способность
4. Полностью однородна
5. Изменения топологии сети незаметны
6. Полностью защищена
7. Управляется одним администратором
8. Транспортировка данных почти ничего не стоит
2
В Одноклассниках
3. 1. Абсолютно надежная сеть
2. Мизерная сетевая задержка
3. Практически безлимитная пропускная способность
4. Полностью однородна
5. Изменение топологии сети незаметны
6. Полностью защищена
7. Управляется одним администратором
8. Транспортировка данных почти ничего не стоит
3
Заблуждения разработчиков распределенных систем
https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing
[Peter Deutsch, 1994; James Gosling 1997]
6. 6
Страница друзей
1. Получить список друзей
2. Применить фильтр
3. Подавить ЧС
4. Получить профили
5. Отсортировать
6. Получить наклейки
7. Посчитать счетчики
7. 7
Простой способ
SELECT * FROM friendlist f, users u
JOIN ON f.vertexId=u.userId
WHERE u.userId=? AND f.kind=?
AND NOT EXISTS( SELECT * FROM blacklist …)
…
8. • Дружбы
• 12 млрд. связей, 300GB
• 500 000 запросов в сек.
8
Простой способ не работает
• Профили пользователей
• > 350 млн. штук,
• 3 500 000 запросов в сек.
• 50 Gbit
11. 11
Анатомия (микро) сервиса
Ремотный интерфейс
https://github.com/odnoklassniki/one-nio
interface GraphService extends RemoteService {
@RemoteMethod
long[] getFriendsByFilter(@Partition long vertexId, long relationMask);
}
interface UserCache {
@RemoteMethod
User getUserById(long id);
}
12. 12
App Server code
https://github.com/odnoklassniki/one-nio
long []friendsIds = graphService.getFriendsByFilter(userId, mask);
List<User> users = new ArrayList<>(friendsIds.length);
for (long id : friendsIds) {
if(blackList.isAllowed(userId,id)) {
users.add(userCache.getUserById(id));
}
}
…
return users;
13. • По таким значениям партиционируем
• У сервиса есть стратегия
• long id -> int partitionId(id) -> node1,node2,…
• Стратегии разные
• Cassandra ring, Voldemort partitions
• или…
13
interface GraphService extends RemoteService {
@RemoteMethod
long[] getFriendsByFilter(@Partition long vertexId, long relationMask);
}
14. 14
Взвешенный квадрат
p = id % 16
p = 0
p = 15
p = 1
N01 N02 N03 . . . 019 020
W=1
W=100
N11
node = wrr(p)
SET
15. 15
Проблема в коде
https://github.com/odnoklassniki/one-nio
long []friendsIds = graphService.getFriendsByFilter(userId, mask);
List<User> users = new ArrayList<>(friendsIds.length);
for (long id : friendsIds) {
if(blackList.isAllowed(userId,id)) {
users.add(userCache.getUserById(id));
}
}
…
return users;
16. 16
Цена сетевого запроса
0.1-0.3 ms
0.7-1.0 ms
Другой ЦОД
* цена сильно зависит от конкретной инфраструктуры и фреймворков.
задержка
= 1.0ms * 2 reqs * 200 друзей
= 400 ms
10k друзей задержка = 20 seconds
18. 18
split & merge
split ( ids by p )
-> ids0, ids1
p = 0
p = 1
N01 N02 N03 . . .
N11
ids0
ids1
users = merge (users0, users1)
19. 19
1. Пропажа клиента
2. Пропажа сервера
3. Потеря исходящего сообщения
4. Потеря входящего сообщения
5. Таймаут сервера
6. Неправильный ответ
7. Произвольный отказ
Что может пойти не так ?
21. • Отказы невозможно предотвратить, только скрыть
• Отказ произойдет обязательно.
• Ключ к скрытию отказов — избыточность:
• Информации (коды защиты от ошибок)
• Железа (резервирование, реплики, дублирующие схемы)
• Времени (транзакции, retries)
21
Что делать с отказами ?
22. 22
Что сервер сделал ?
Сдаваться
нельзя ,
повторить !
Сдаваться ,
нельзя
повторить !
? ?
Добавить друга
23. • Со стороны клиента — неизвестно
• Что клиент может сделать ?
• Не давать никаких гарантий
• Никогда не повторять запрос. Максимум 1 раз. At Most Once.
• Всегда повторять запрос. По меньшей мере 1 раз. At Least Once.
23
Был ли друг добавлен ?
24. 1. Транзакция в ACID хранилище
• есть мастер, успех однозначен (или проходит, или нет)
• возможен атомарный откат
2. Обновление информации в кэшах
• много реплик, мастера нет
• атомарного отката нет: возможны частичные отказы
24
Добавляем друга
25. • Операция применима повторно с тем же результатом
• напр: чтение, Set.add(), Math.max(x,y)
• Упорядоченное Атомарное изменение с контролем дубликата
25
Идемпотентность
Только для Идемпотентных операций
можно применять стратегию
“всегда повторять попытку”
https://ru.wikipedia.org/wiki/Идемпотентность
26. 26
Идемпотентность в ACID хранилище
Подружиться
ждем; timeout
Подружиться
Подружились!
Уже друзья ?
Нет, делаем изменения!
Уже друзья ?
Да, ничего не делаем !
28. 1. Транзакция в ACID хранилище
• есть мастер, успех однозначен (или проходит, или нет)
• возможен атомарный откат
2. Обновление информации в кэшах
• много реплик, мастера нет
• атомарного отката нет: возможны частичные отказы
28
Добавляем друга
30. • Процесс синхронизации данных
• Непрерывно читает изменения из транзакционного хранилища
SELECT * FROM users WHERE modified > ?
• Применяет их в память кэша
• Загружает изменения при старте ноды
• Повтор — не нужен
30
Синхронизируем кэш через БД
32. 1. Клиенты перестают обращаться к серверу
После Х непрерывных отказов за последнюю секунду
2. Клиенты мониторят доступность сервера
В фоне, раз в минуту
3. И возвращают его в ротацию
32
Вывод из ротации
34. 34
Смерть через торможение
Avg = 1.5ms
Max = 1.5c
24 cpu cores
Cap = 24,000 ops
Cтавить таймаут = 2.4ms ?
Выводить из ротации если среднее > 2.4ms ?
Avg = 24ms
Max = 1.5c
24 cpu cores
Cap = 1,000 ops
10,000 ops
36. 36
Спекулятивный повтор: что лучше
• Задержки 99p, средние
• Стабильность системы
Классы, задержка 99p, наносекунды.
без спекулятивного повтора (желтый)
и с ним (красный)
^^^ пики до 1 сек ^^^
37. • Идемпотентные операции
• “Дополнительная” нагрузка
• Дополнительный трафик
• Балансируем спекуляцию:
• всегда, >99p, >50p
37
Спекулятивный повтор: применим не всегда
Классы, задержка 99p, наносекунды.
без спекулятивного повтора (желтый)
и с ним (красный)
^^^ пики до 1 сек ^^^
44. • Что делает:
• Определяет соединения с фронта на сервис
• Отрубает соединения (iptables drop)
• Запускает авто тесты
• Что проверяем
• Что ничего не валится, показываются красивые заглушки
• Сервер стартует
44
Свой продукт: “Горилла”
45. • Тестовый стенд с синтетический нагрузкой ?
- Топология сети не неизменна
- Сложно воспроизвести профиль нагрузки
• На продакшене!
• Но чтобы никто не заметил
• Проверяем сценарии отказов и восстановления
45
Как тестировать стандартные решения ?
57. • Возможности отказов в распределенных системах безграничны
• Отказы маскируются за счет информации, времени, железа
• При немаскируемых отказах — деградируем !
• Отказы надо тестировать наравне с функционалом
• Отказы нужно диагностировать и предупреждать на проде
57
Краткое содержание предыдущих слайдов
58. 58 Распределенные системы в Одноклассниках
slideshare.net/m0nstermind
https://v.ok.ru/publishing.html
http://www.cs.yale.edu/homes/aspnes/classes/465/notes.pdf
Notes on Theory of Distributed Systems CS 465/565:
Spring 2014
James Aspnes
Тут можно узнать больше: