В предыдущем разделе мы кратко представили движок Innodb.Buffer PoolАрхитектура, краткий обзор:Архитектура движка Innodb разделена на "структуру памяти" и "структуру диска", а взаимодействие данных между ними осуществляется в "страничных" блоках. Во избежание частой загрузки страниц данных с диска в память, Buffer Pool спроектированflush list,free list,lru listСтруктуры данных и т. д. кэшируются в памяти и управляют страницами данных.Давайте посмотрим на схему архитектуры движка Innodb:
Видим структуру памяти движка InnodbBuffer Pool, также содержитChange Bufferобласть, соответствующая дискуSystem TablespaceВ структуре он также содержит соответствующийChange Bufferплощадь. У читателей могут возникнуть вопросы: для чего разработан движок InnodbChange Buffer? Как это работает? К каким бизнес-сценариям он применим? В этом разделе мы ответим на эти вопросы.
1. Для чего разработан двигатель Innodb?Change Buffer?
мы знаемМеханизм Innodb использует дерево B+ для организации табличных данных и управления ими., следующий рисунок представляет собой диаграмму структуры дерева B+:
в двигателе InnodbДанные — это индекс, индекс — это данные, что означает, что сама таблица данных являетсякластеризованный индекс, индекс, который мы определяем при создании структуры таблицы, называетсяВторичный индекс,иливторичный индекс, разница между кластерным индексом и вспомогательным индексом здесь обсуждаться не будет, читатели могут сами найти информацию и изучить. Читатели, знакомые со структурой индексов движка Innodb, должны понимать:Чем больше индексов, тем лучше, хотя индекс может значительно повысить скорость запроса данных в соответствии с полем индекса, его также необходимо поддерживать при обновлении поля индекса.Когда данные индекса часто обновляются, стоимость все еще очень велика. .
Одна из проблем проектирования механизма хранения заключается в том, как уменьшить количество случайных операций ввода-вывода во время операций чтения и записи данных. Для запросов на чтениепоказательОн специально разработан для этого.Данные располагаются в листовых узлах дерева B+ по порядку через поля первичного ключа и индекса.При поиске данных будет максимально использоваться последовательный ввод/вывод.Помните, что мы говорили в предыдущем разделеBuffer Pool? Если страницу данных можно кэшировать вBuffer PoolВ случае , тогда дисковый ввод-вывод (будь то последовательный ввод-вывод или произвольный ввод-вывод) может быть опущен при чтении данных, и то же верно для операций записи, а страница кэша в памяти может обновляться напрямую (данные читатели проблемы согласованности). Не беспокойтесь на данный момент, это может быть гарантировано журналом повторов, и мы продолжим изучение связанного контента позже). Конечно, идеально, чтобы данные находились на странице кеша. Что, если страница данных операции записи не находится в кеше? Согласно нашим текущим знаниям, процесс обработки движка Innodb выглядит следующим образом:
- В соответствии с условиями операции записи механизм Innodb должен будет использовать страницу данных «кластеризованного индекса» таблицы данных для загрузки в
Buffer Pool(этот процесс поиска представляет собой последовательный ввод-вывод), а затем вставлять, обновлять или удалять записи данных. - Если таблица данных создана с вторичным индексом, вам необходимо загрузить соответствующую страницу данных вторичного индекса в
Buffer Pool(этот процесс поиска представляет собой произвольный ввод-вывод), а затем вставлять, обновлять или удалять записи данных. Конечно, если во время этого процесса происходит «разрыв страницы» или «пустая страница», B+-дерево вторичного индекса также нуждается в корректировке.
Видно, что при поиске записей вторичного индекса мы столкнулись с большим количеством случайных операций ввода-вывода, что не допускается разработчиками движка Innodb, поэтому дизайнChange BufferЭта специальная структура данных решает эту проблему. Краткое содержание одной фразы:Буфер изменений — это специальная структура данных, предназначенная для облегчения случайного ввода-вывода, генерируемого механизмом Innodb во время запросов на чтение..
Change BufferКитайское название — «буфер изменений», и в других статьях и исходном коде читатели увидят, что ibuf и IBUF используются под разными внутренними именами. В предыдущих версиях только данныеinsertЕго можно использовать, когдаInsert Buffer, поддерживается в последующих версияхinsert,updateа такжеdelete, было изменено на это более общее имя.
2. Change BufferКак это работает?
В этом разделе мы сначала наметимChange BufferПринцип реализации, а затем изучить дополнительные детали реализации, что очень полезно для полного понимания механизма Innodb.
2.1 Change BufferПринцип реализации
Ниже приведена рабочая схема, приведенная в официальном документе:
Change Bufferофициальная документация
похоже на военный兵马未到,粮草先行, когда страница вторичного индекса неBuffer Pool, механизм Innodb кэширует эти изменения при поступлении запроса на запись. После загрузки этой страницы другими операциями чтения вBuffer PoolБуферизованные изменения, которые могут быть результатом операций INSERT, UPDATE или DELETE (DML), позже объединяются в кэшированную страницу.
2.2 Change Bufferструктура данных
Change BufferФизически это B-дерево, в котором могут храниться записи любого вторичного индекса. Также известно как универсальное дерево в исходном коде. В InnoDB есть только один буфер изменений, который всегда хранится в системном табличном пространстве. Корневая страница этого дерева буфера изменений закреплена на FSP_IBUF_TREE_ROOT_PAGE_NO (равно 4) в системном табличном пространстве (идентификатор пространства 0). Когда сервер будет запущен, он будет загружен с этим фиксированным номером страницы. Запись ibuf выглядит так:
ibuf btreeИспользуя {space_id, page_no, count} в качестве первичного ключа для уникальной идентификации записи, counter представляет собой инкрементное значение, где count помогает поддерживать порядок буферизации изменений на этой конкретной странице, а формат строки самой записи буфера всегда ИЗБЫТОЧНЫЙ.
2.3 Change BufferНеобходимые условия для использования
Буферизация изменений применяется только к неуникальным вторичным индексам (NUSI). InnoDB буферизует 3 типа операций в NUSI: вставка, удаление, отметка и удаление. Эти операции перечисляются внутри исходного кода движка InnoDB ibuf_op_t:
//代码路径:storage/innobase/include/ibuf0ibuf.h
/* Possible operations buffered in the insert/whatever buffer. See
ibuf_insert(). DO NOT CHANGE THE VALUES OF THESE, THEY ARE STORED ON DISK. */
typedef enum {
IBUF_OP_INSERT = 0,
IBUF_OP_DELETE_MARK = 1,
IBUF_OP_DELETE = 2,
/* Number of different operation types. */
IBUF_OP_COUNT = 3
} ibuf_op_t;
Пользователь может управлять работой кеша через параметр innodb_change_buffering, значения перечисления в коде задаются следующим образом:
//代码路径:storage/innobase/include/ibuf0ibuf.h
enum ibuf_use_t {
IBUF_USE_NONE = 0,
IBUF_USE_INSERT, /* insert */
IBUF_USE_DELETE_MARK, /* delete */
IBUF_USE_INSERT_DELETE_MARK, /* insert+delete */
IBUF_USE_DELETE, /* delete+purge */
IBUF_USE_ALL /* insert+delete+purge */
};
могуinnodb_change_bufferingУстановите следующие значения параметров для кэширования соответствующих операций:
--all: 默认值。开启buffer inserts、delete-marking operations、purges
--none: 不开启change buffer
--inserts: 只是开启buffer insert操作
--deletes: 只是开delete-marking操作
--changes: 开启buffer insert操作和delete-marking操作
--purges: 对只是在后台执行的物理删除操作开启buffer功能
Значение innodb_change_buffering по умолчанию — all, что означает, что все операции кэшируются. Обратите внимание, что, поскольку операция обновления вторичного индекса всегда сначала удаляет метку, а затем вставляет новую запись, обновление создаст две записи ibuf.
Ниже перечислены кэшированные данные механизма Innodb дляchange bufferНекоторые из необходимых условий (возможность кэширования операций обновления в буфере изменений зависит от многих факторов):
- Пользователь должен установить опцию innodb_change_buffering
- Только конечные узлы будут рассматривать возможность использования ibuf.
- Для кластеризованных индексов нельзя кэшировать операции.
- Для уникального вторичного индекса (уникальный ключ), поскольку записи индекса уникальны, операции вставки нельзя кэшировать, но можно кэшировать операции удаления;
- Операция сброса таблицы не выполняется, например, когда выполняется сброс таблицы для экспорта, кэширование ibuf для таблицы не разрешено.
2.4 Change Bufferрастровая страница
Все операции кэша ibuf предназначены для определенных подстраниц NUSI, что делает необходимым отслеживать свободное место на страницах NUSI, потому чтоChange BufferСлияние этих операций буферизации на листовых страницах NUSI не должно приводить к слиянию страниц B-дерева или разделению страниц B-дерева.
Для слияния страниц B-дерева ключ к проблеме заключается в том, как избежать пустых страниц, в основном для потока очистки, поскольку только поток очистки может фактически удалить физические записи во вторичном индексе. Поэтому при подготовке к вставке кэша операции IBUF_OP_DELETE механизм Innodb оценит, сколько записей осталось после применения всех записей ibuf на странице.Если осталась только одна запись, он отклонит кэш операции очистки и переключится на обычный ● Логика считывания физической страницы.
Чтобы узнать, как предотвратить разбиение страниц B-дерева, движок Innodbibuf bitmap pageСпециальная страница используется для поддержания размера свободного пространства каждой страницы данных NUSI.Эта страница существует в каждом файле idb и имеет фиксированный номер страницы.Структура файла следующая:
Страницы растрового изображения буфера изменений используют 4 бита (IBUF_BITS_PER_PAGE) для описания каждой страницы. Он содержит массив из 4 битов, описывающих каждую страницу. Весь массив называется "растровое изображение ibuf" (растровое изображение буфера вставки/изменения). В следующей таблице приведены сведения об этих 4 битах:
| кусочек | Значение (число цифр индекса) | описывать |
|---|---|---|
| IBUF_BITMAP_FREE | 0 | Первые два бита используются для указания свободного места на листовых страницах NUSI. |
| IBUF_BITMAP_BUFFERED | 2 | Если установлен третий бит, это означает, что конечная страница имеет буферизованную запись в буфере изменений. |
| IBUF_BITMAP_IBUF | 3 | Если установлен четвертый бит, это означает, что страница является частью буфера изменений. |
Этот массив начинается со смещения, равного IBUF_BITMAP (равно 94) после заголовка. Учитывая номер страницы, растровая страница ibuf, содержащая 4 бита информации на данной странице, может быть рассчитана как (справочная функция: ibuf_bitmap_page_no_calc):
//代码路径:mysql-8.0.20/storage/innobase/ibuf/ibuf0ibuf.cc
/** Calculates the bitmap page number for a given page number.
@param[in] page_id page id
@param[in] page_size page size
@return the bitmap page id where the file page is mapped */
UNIV_INLINE
const page_id_t ibuf_bitmap_page_no_calc(const page_id_t &page_id,
const page_size_t &page_size) {
page_no_t bitmap_page_no;
bitmap_page_no = FSP_IBUF_BITMAP_OFFSET +
(page_id.page_no() & ~(page_size.physical() - 1));
return (page_id_t(page_id.space(), bitmap_page_no));
}
отibuf bitmap pageПо дизайну мы знаем, что только 2 бита могут использоваться для хранения информации о свободном пространстве страницы. То есть всего четыре возможных значения 0, 1, 2 и 3. Используя эти 2 бита, мы пытаемся закодировать информацию о свободном пространстве страницы. Правила следующие: UNIV_PAGE_SIZE/IBUF_PAGE_SIZE_PER_FREE_SPACE, использующие буфер изменений, должны иметь не менее байт свободного места:
//代码路径:mysql-8.0.20/storage/innobase/include/ibuf0ibuf.ic
/** An index page must contain at least UNIV_PAGE_SIZE /
IBUF_PAGE_SIZE_PER_FREE_SPACE bytes of free space for ibuf to try to
buffer inserts to this page. If there is this much of free space, the
corresponding bits are set in the ibuf bitmap. */
#define IBUF_PAGE_SIZE_PER_FREE_SPACE 32
имеютibuf bitmap page, двигатель Innodb находится вIBUF_OP_INSERTПеред буферизацией операции вставки используйте информацию, доступную на странице растрового изображения буфера изменений, чтобы приблизить свободное пространство на конечной странице NUSI. Метод расчета отражен в ibuf_index_page_calc_free_from_bits():
//代码路径:mysql-8.0.20/storage/innobase/include/ibuf0ibuf.ic
/** Translates the ibuf free bits to the free space on a page in bytes.
@param[in] page_size page_size
@param[in] bits value for ibuf bitmap bits
@return maximum insert size after reorganize for the page */
UNIV_INLINE
ulint ibuf_index_page_calc_free_from_bits(const page_size_t &page_size,
ulint bits) {
ut_ad(bits < 4);
ut_ad(!page_size.is_compressed() ||
page_size.physical() > IBUF_PAGE_SIZE_PER_FREE_SPACE);
if (bits == 3) {
return (4 * page_size.physical() / IBUF_PAGE_SIZE_PER_FREE_SPACE);
}
return (bits * (page_size.physical() / IBUF_PAGE_SIZE_PER_FREE_SPACE));
}
Примерение размера страницы 16 КБ в качестве примера, свободное пространство, которое можно представить, равно 0 (0 байт), 1 (512 байт), 2 (1024 байта) и 3 (2048 байтов):
| Информация о свободном пространстве (IBUF_CODE) на растровой странице IBUF | Свободное место для листовых страниц NUSI (приблизительно) |
|---|---|
| 0 | 0 байт |
| 1 | 512 байт |
| 2 | 1024 байта |
| 3 | 2048 байт |
Используя эту информацию, мы можем определить, поместится ли запись, подлежащая буферизации, на странице. Вставки будут буферизованы, если есть достаточно места. Используя этот подход, мы гарантируем, что слияние этих записей с целевым NUSI не приведет к разбиению страниц.
После буферизованной операции вставки или удаления информация о свободном пространстве на странице растрового изображения буфера изменения должна быть соответствующим образом обновлена (операции удаления пометки не изменяют информацию о свободном пространстве). Чтобы обновить информацию о свободном пространстве, нам нужно преобразовать свободное пространство в байтах обратно в значение, закодированное IBUF. Эта работа выполняется в функции ibuf_index_page_calc_free_bits():
//代码路径:mysql-8.0.20/storage/innobase/include/ibuf0ibuf.ic
/** Translates the free space on a page to a value in the ibuf bitmap.
@param[in] page_size page size in bytes
@param[in] max_ins_size maximum insert size after reorganize for
the page
@return value for ibuf bitmap bits */
UNIV_INLINE
ulint ibuf_index_page_calc_free_bits(ulint page_size, ulint max_ins_size) {
ulint n;
ut_ad(ut_is_2pow(page_size));
ut_ad(page_size > IBUF_PAGE_SIZE_PER_FREE_SPACE);
n = max_ins_size / (page_size / IBUF_PAGE_SIZE_PER_FREE_SPACE);
if (n == 3) {
n = 2;
}
if (n > 3) {
n = 3;
}
return (n);
}
В приведенном выше расчете max_ins_size — это максимальный размер вставки (максимальное свободное пространство), доступный на странице после реорганизации страницы.
2.5 Change BufferСлияние с целевой страницей MUSI
Изменения конечной страницы NUSI сохраняются в буфере изменений, если конечная страница NUSI еще не находится в пуле буферов. В различных случаях эти буферизованные операции объединяются обратно в фактические конечные страницы NUSI:
-
Поток пользователя выбирает вторичный индекс для запроса данных.В это время страница вторичного индекса должна быть прочитана, и соответствующая запись ibuf должна быть объединена со страницей.
-
Слияние буферов вызовом ibuf_merge_in_background(), когда основной поток InnoDB периодически выполняет изменения.
-
Когда слишком много операций буферизуется для конкретной листовой страницы NUSI.
-
Когда дерево буфера изменений достигает максимально допустимого размера.
Операция слияния буфера изменений инициируется вызовом функций ibuf_merge_in_background() или ibuf_contract(). Слияние буфера изменений выполняется на переднем плане или в фоновом режиме. Слияние буфера изменений переднего плана является частью операции DML и, следовательно, влияет на производительность для конечного пользователя. Вместо этого слияние буфера фоновых изменений происходит периодически, когда на сервере меньше активности.
Мы гарантируем, что изменение слияния буферов не приведет к разбиению страниц B-дерева или операциям слияния страниц. Это также не должно привести к тому, что конечная страница будет пустой. Буферизованные изменения были применены к целевым конечным страницам NUSI, прежде чем они будут помещены в буферный пул. После объединения буферизованных изменений для страницы соответствующая 4-битная информация на странице растрового изображения буфера изменений также обновляется.
2.6 Change Bufferконфигурация параметров
Пара двигателей InnodbChange BufferЕсть две основные конфигурации параметров: innodb_change_buffer_max_size, innodb_change_buffering;
-
INODB_CHANGE_BUFFER_MAX_SIZE соотношение распределения общего размера буфера записи в пул буфера, по умолчанию составляет 25%, максимум составляет 50%; причина этой конструкции - предотвратить
Change Bufferбрать слишком многоBuffer Poolпространство. -
Как упоминалось ранее, innodb_change_buffering используется для настройки того, какие операции записи включают буферизацию записи, которая может быть установлена на все/нет/вставки/удаления и т. д.
3. Change BufferК каким бизнес-сценариям он применим?
В большинстве бизнес-баз данных используется механизм Innodb, который очень удобен для включения, когда большинство определений таблиц данных являются неуникальными индексами и в бизнес-сценариях с большим количеством операций записи и меньшим количеством операций чтения.Change Buffer(например, услуги по выставлению счетов в нашем бизнесе). Наоборот, когда в базе много неуникальных индексов, многие операции записи не используются.Change BufferВ другом случае, когда страница читается сразу после операции записи, или когда вторичный индекс читается и записывается одновременно,Change BufferВместо этого он станет бременем, как мы сказали выше.Change BufferСлияние с целевой страницей MUSI также требует много времени.
4. Резюме и предварительный просмотр
Эта статья начинается с трех основных вопросов и знакомит с движком Innodb.Change BufferДизайн и реализация считывателя захватываетПрежде чем прибудут войска и лошади, в первую очередь идут еда и трава.Прочитав эту статью, вы обязательно что-то почерпнете, а потом сможете попробовать ответить на эти 3 вопроса: Почему дизайнChange Buffer? Как это работает? К каким бизнес-сценариям он применим? .
СвязанныйChange BufferМногие детали рабочего процесса в этой статье не раскрываются, но иногда идеи важнее выводов и реализации, эта часть анализа исходного кода будет изучена позже, когда будет время. Я хочу сказать оПрежде чем прибудут войска и лошади, в первую очередь идут еда и трава.Военная идея innodb, в движке Innodb также есть часть конструкции, позволяющая полностью реализовать ее, например, краеугольный камень обеспечения согласованности и надежности данных:Redo Log! , Технология WAL (Write Ahead Log), я думаю, читатели слышали о ней, это убийца высокопроизводительной реализации движка Innodb, следующее краткое резюме, давайте представимRedo Log, на сегодня все, спасибо!