Булат Столяров. Итоговая презентация дискуссионной группы «Защита прав гражд...
Дмитрий Еманов — Под капотом серверного ПО
1. ПодПод капотом серверного ПО:капотом серверного ПО:
нюансы разработкинюансы разработки
Дмитрий Еманов
dimitr@firebirdsql.org
FirebirdSQL Project
http://www.firebirdsql.org/
2. 2
Что прячется за определением «серверное»
Сложность
Количественная или качественная?
Цена неудачного решения
Производительность
Баланс между скоростью выполнения и красотой кода
Важность каждой мелочи
Оглядка на железо
Кроссплатформенность
Борьба против стандартов или все своими руками
QA, QA и еще раз QA
3. 3
Программная архитектура
OSRI/DSRI
Единый API для всех компонентов
Объекты и обмен сообщениями
Диспетчер и провайдеры (подсистемы)
Каждый компонент архитектуры понимает ее механику,
но не семантику
Диспетчер (Y-valve)
Шлюз между клиентом и провайдером
Опрос подсистем
Поддержка абстрактных дескрипторов
Двухфазная фиксация транзакций (2PC)
13. 13
Программная архитектура
Эволюция
Новый OO API, замена macros hell
на виртуальную диспетчеризацию
Переход от статической компоновки провайдеров
к динамической
Конфигурирование списка доступных провайдеров
Вынос авторизации из ядра на уровень remote server
Proof of concept
30 лет не требовала значительных изменений
и не мешала разработке новых идей на ее основе
Пережила несколько ОС и два сетевых протокола
14. 14
Библиотека классов
Изначальные проблемы
Boost существовал скорее теоретически
STD++ был убог и слабо стандартизирован
Невозможность жесткого управления памятью
Недружелюбность к пулам памяти
Универсальность против производительности
Решения
Своя библиотека под существующую архитектуру
работы с памятью
Алгоритмы, заточенные под собственные потребности
Свои велосипеды — самые лучшие!
15. 15
Синхронизация
Очевидное и не совсем
Лучше жить вообще без конкуренции, но не получается
Внимательно смотрим на реализацию
и прикладываем ее к своей специфике
RW-lock и с чем его едят
Честность обслуживания против производительности,
что такое lock starvation
Размещение примитивов синхронизации
16. 16
Синхронизация
Очевидное и не совсем
Лучше жить вообще без конкуренции, но не получается
Внимательно смотрим на реализацию
и прикладываем ее к своей специфике
RW-lock и с чем его едят
Честность обслуживания против производительности,
что такое lock starvation
Размещение примитивов синхронизации
THD1 THD2 THD3 THD1 THD2 THD3
SYN
OBJ
SYN1
OBJ
SYN2 SYN3
17. 17
Синхронизация
Level Up
Кросспроцессная синхронизация и IPC
Множественные состояния локов (SR, PR, SW, PR, EX)
Гарантированно честное обслуживание
Кеширование локов, механизм BAST
Обнаружение и решение дедлоков
Мониторинг графов ожидания и т. п.
Распределенный менеджер блокировок
18. 18
Архитектура работы с памятью
Общие принципы
Минимизация обращений к менеджеру памяти
Внутренние структуры (по возможности) не должны
требовать динамического расширения
Каждый поток (по возможности) должен работать
со своим менеджером памяти
Пулы памяти
Предварительная аллокация
Изоляция данных различных объектов друг от друга
Раздельный учет памяти
Возможность «delete by pool»
19. 19
Архитектура работы с памятью
Иерархические пространства памяти
Каждый пул порождается родительским пулом
Каждый значимый рантайм объект имеет
свой собственный пул
Существует иерархия типов рантайм объектов,
связанных принципами порождения и времени жизни
Каждая аллокация «внизу» приводит к рекурсивному
пересчету статистики родительских пулов
Существует возможность получать и отображать статистику
всех рантайм объектов
20. 20
Архитектура работы с памятью
Иерархические пространства памяти
База данныхБаза данных
Сессия 1Сессия 1 Сессия 2Сессия 2
Тр-ция 1Тр-ция 1 Тр-ция 2Тр-ция 2 Тр-ция 3Тр-ция 3 Тр-ция 4Тр-ция 4
Запрос 2Запрос 2
Запрос 1Запрос 1 Запрос 3Запрос 3
Запрос 4Запрос 4 Запрос 6Запрос 6
Запрос 5Запрос 5 Запрос 7Запрос 7
Запрос 8Запрос 8
21. 21
Архитектура работы с памятью
Чем мы за это платим?
RecordBuffer::RecordBuffer(MemoryPool& pool, const Format* format)
: length(format->fmt_length), count(0)
{
space = FB_NEW(pool) TempSpace(pool, SCRATCH);
record = FB_NEW(pool) Record(pool, length);
record->rec_length = length;
}
template <typename T, typename InternalTypes = BitmapTypes_64>
class SparseBitmap : public AutoStorage
{
public:
// Default constructor, stack placement
SparseBitmap()
: tree(&getPool()), defaultAccessor(this)
{}
// Pooled constructor
explicit SparseBitmap(MemoryPool& p)
: AutoStorage(p), tree(&getPool()), defaultAccessor(this)
{}
24. 24
Эволюция менеджера памяти
1-е поколение
Список свободных блоков + алгоритм «best fit» + mutex
Аллокация больших блоков через ОС
25. 25
Эволюция менеджера памяти
1-е поколение
Список свободных блоков + алгоритм «best fit» + mutex
Аллокация больших блоков через ОС
2-е поколение (200% - 150x)
Бинарное дерево свободных блоков + mutex
Аллокация больших блоков через ОС + кеш больших блоков
26. 26
Эволюция менеджера памяти
1-е поколение
Список свободных блоков + алгоритм «best fit» + mutex
Аллокация больших блоков через ОС
2-е поколение (200% - 150x)
Бинарное дерево свободных блоков + mutex
Аллокация больших блоков через ОС + кеш больших блоков
3-е поколение (50% - 10x)
Хеш-таблица малых блоков + CAS
Список средних блоков + алгоритм «first fit» + mutex
Аллокация больших блоков через ОС + кеш больших блоков
27. 27
Работа с диском
Что мы все знаем
Дисковый I/O был и остается узким местом
Блочное выделение места в файле и I/O операции
Кеширование блоков, FIFO/LIFO
Файловый кеш и синхронная запись
Фрагментация и raw partitions
Нюансы
HDD против SSD
Компрессия как способ уменьшения дискового I/O
SYNC/FLUSH — доверяй, но проверяй!
28. 28
Работа с диском
Компрессия
Баланс между скоростью и степенью сжатия
Формат данных в памяти
Компактификация, RLE и иже с ними
Префиксная компрессия
Индексация внутри блоков
Второй уровень кеширования
Распакованные данные
Структуры поиска
Затраты на синхронизацию
29. 29
ACID и архитектура I/O
Журнал транзакций (WAL)
Изменения пишутся в журнал синхронно и последовательно
Фоновый перенос из журнала в основной файл
Чекпойнты
Обратное проигрывание журнала при восстановлении
30. 30
ACID и архитектура I/O
Журнал транзакций (WAL)
Изменения пишутся в журнал синхронно и последовательно
Фоновый перенос из журнала в основной файл
Чекпойнты
Обратное проигрывание журнала при восстановлении
Принцип careful writes
Журнала нет
Дисциплина зависимости блоков друг от друга
Запись выполняется в соответствии с графом зависимостей
Мгновенное восстановление, отложенный reuse
31. 31
ACID и архитектура I/O
Сравнение WAL против CW
Синхронная последовательная запись быстрее синхронной
случайной записи (иногда есть возможность
асимптотического приведения второй к первой)
Одинарная запись теоретически быстрее двойной, но не
надо забывать про SYNC vs ASYNC
Что меняется в случае SSD?
32. 32
Теневая копия
Принцип
Физическая копия файла, аналог RAID 1
Читаем из основного файла, пишем в оба
Переключение на тень при сбое I/O операции
Режим SYNC одинаков для обоих файлов
33. 33
Теневая копия
Принцип
Физическая копия файла, аналог RAID 1
Читаем из основного файла, пишем в оба
Переключение на тень при сбое I/O операции
Режим SYNC одинаков для обоих файлов
Нестандартные применения
Синхронный standby — основной файл локальный,
тень удаленная (через NFS)
34. 34
Теневая копия
Принцип
Физическая копия файла, аналог RAID 1
Читаем из основного файла, пишем в оба
Переключение на тень при сбое I/O операции
Режим SYNC одинаков для обоих файлов
Нестандартные применения
Синхронный standby — основной файл локальный,
тень удаленная (через NFS)
Кеширование чтения — основной файл на RAM-диске,
тень на физическом диске
35. 35
Теневая копия
Принцип
Физическая копия файла, аналог RAID 1
Читаем из основного файла, пишем в оба
Переключение на тень при сбое I/O операции
Режим SYNC одинаков для обоих файлов
Нестандартные применения
Синхронный standby — основной файл локальный,
тень удаленная (через NFS)
Кеширование чтения — основной файл на RAM-диске,
тень на физическом диске
Оптимизация чтения — основной файл на SSD, тень на HDD