DocumentDB - Разделение
Когда ваша база данных начинает превышать 10 ГБ, вы можете масштабироваться, просто создавая новые коллекции, а затем распределяя или разделяя ваши данные по все большему количеству коллекций.
Рано или поздно одной коллекции размером 10 ГБ будет недостаточно для размещения вашей базы данных. 10 ГБ может показаться не очень большим числом, но помните, что мы храним документы JSON, которые представляют собой простой текст, и вы можете уместить множество текстовых документов в 10 ГБ, даже если учесть накладные расходы на хранилище для индексов.
Когда речь идет о масштабируемости, проблема не только в хранилище. Максимальная пропускная способность, доступная для коллекции, составляет две с половиной тысячи единиц запросов в секунду, которые вы получаете с коллекцией S3. Следовательно, если вам нужна более высокая пропускная способность, вам также потребуется горизонтальное масштабирование путем разделения на несколько коллекций. Масштабируемое секционирование также называютhorizontal partitioning.
Существует множество подходов, которые можно использовать для разделения данных с помощью Azure DocumentDB. Ниже приведены наиболее распространенные стратегии -
- Дополнительное разбиение
- Разделение диапазона
- Разбиение на разделы поиска
- Разбиение хэша
Дополнительное разбиение
Дополнительное разделение - это простейшая стратегия, поскольку нет ключа раздела. Часто это хороший выбор для начала, когда вы во многих вещах не уверены. Вы можете не знать, потребуется ли вам когда-либо масштабироваться за пределы одной коллекции, или сколько коллекций вам может понадобиться добавить, или как быстро вам может потребоваться их добавить.
Дополнительное разделение начинается с единственной коллекции, и ключа раздела нет.
Коллекция начинает расти, а затем увеличивается еще немного, а затем еще немного, пока вы не приблизитесь к пределу в 10 ГБ.
Когда вы достигнете 90-процентной емкости, вы перейдете в новую коллекцию и начнете использовать ее для новых документов.
Как только ваша база данных масштабируется до большего количества коллекций, вы, вероятно, захотите перейти к стратегии, основанной на ключе раздела.
Когда вы это сделаете, вам потребуется перебалансировать данные, переместив документы в разные коллекции в зависимости от стратегии, к которой вы переходите.
Разделение диапазона
Одна из наиболее распространенных стратегий - разделение по диапазонам. При таком подходе вы определяете диапазон значений, в который может попасть ключ раздела документа, и направляете документ в коллекцию, соответствующую этому диапазону.
Даты очень часто используются с этой стратегией, когда вы создаете коллекцию для хранения документов, которые попадают в определенный диапазон дат. Когда вы определяете достаточно маленькие диапазоны, когда вы уверены, что ни одна коллекция никогда не превысит свой предел в 10 ГБ. Например, может быть сценарий, когда одна коллекция может разумно обрабатывать документы в течение всего месяца.
Также может случиться так, что большинство пользователей запрашивают текущие данные, которые могут быть данными за этот или, возможно, последний месяц, но пользователи редко ищут гораздо более старые данные. Итак, вы начинаете в июне с коллекции S3, которая является самой дорогой коллекцией, которую вы можете купить, и обеспечивает лучшую пропускную способность, которую вы можете получить.
В июле вы покупаете еще одну коллекцию S3 для хранения июльских данных, а также масштабируете июньские данные до менее дорогой коллекции S2. Затем в августе вы получаете еще одну коллекцию S3 и масштабируете июль до S2, а июнь - до S1. Это происходит месяц за месяцем, когда вы всегда сохраняете доступность текущих данных для высокой пропускной способности, а более старые данные - при более низкой пропускной способности.
Пока запрос предоставляет ключ раздела, будет запрашиваться только коллекция, которую нужно запросить, а не все коллекции в базе данных, как это происходит с дополнительным разделением.
Разбиение на разделы поиска
С помощью разделения поиска вы можете определить карту разделов, которая направляет документы в определенные коллекции на основе их ключа раздела. Например, вы можете разделить по регионам.
Храните все документы США в одной коллекции, все европейские документы в другой коллекции и все документы из любого другого региона в третьей коллекции.
Используйте эту карту разделов, и преобразователь разделов поиска сможет определить, в какой коллекции создать документ и какие коллекции запрашивать, на основе ключа раздела, который является свойством региона, содержащимся в каждом документе.
Разбиение хэша
При разделении по хешу разделы назначаются на основе значения хеш-функции, что позволяет равномерно распределять запросы и данные по нескольким разделам.
Это обычно используется для разделения данных, созданных или потребляемых большим количеством отдельных клиентов, и полезно для хранения профилей пользователей, элементов каталога и т. Д.
Давайте посмотрим на простой пример разделения по диапазонам с использованием RangePartitionResolver, поставляемого .NET SDK.
Step 1- Создайте новый DocumentClient, и мы создадим две коллекции в задаче CreateCollections. Один будет содержать документы для пользователей, идентификаторы которых начинаются с A по M, а другой - для идентификаторов пользователей с N по Z.
private static async Task CreateCollections(DocumentClient client) {
await client.CreateDocumentCollectionAsync(“dbs/myfirstdb”, new DocumentCollection {
Id = “CollectionAM” });
await client.CreateDocumentCollectionAsync(“dbs/myfirstdb”, new DocumentCollection {
Id = “CollectionNZ” });
}
Step 2 - Зарегистрируйте преобразователь диапазона для базы данных.
Step 3- Создайте новый RangePartitionResolver <string>, который является типом данных нашего ключа раздела. Конструктор принимает два параметра: имя свойства ключа раздела и словарь, который представляет собой карту сегментов или карту разделов, которая представляет собой просто список диапазонов и соответствующих коллекций, которые мы предварительно определяем для преобразователя.
private static void RegisterRangeResolver(DocumentClient client) {
//Note: \uffff is the largest UTF8 value, so M\ufff includes all strings that start with M.
var resolver = new RangePartitionResolver<string>(
"userId", new Dictionary<Range<string>, string>() {
{ new Range<string>("A", "M\uffff"), "dbs/myfirstdb/colls/CollectionAM" },
{ new Range<string>("N", "Z\uffff"), "dbs/myfirstdb/colls/CollectionNZ" },
});
client.PartitionResolvers["dbs/myfirstdb"] = resolver;
}
Здесь необходимо закодировать максимально возможное значение UTF-8. В противном случае первый диапазон не совпадет ни с одним M, кроме одного M, а также для Z во втором диапазоне. Итак, вы можете думать об этом закодированном значении здесь как о подстановочном знаке для сопоставления ключа раздела.
Step 4- После создания преобразователя зарегистрируйте его для базы данных с текущим DocumentClient. Для этого просто назначьте его свойству словаря PartitionResolver.
Мы будем создавать и запрашивать документы в базе данных, а не в коллекции, как вы обычно делаете, преобразователь будет использовать эту карту для маршрутизации запросов в соответствующие коллекции.
Теперь создадим несколько документов. Сначала мы создадим один для пользователя Kirk, а затем один для Спока.
private static async Task CreateDocumentsAcrossPartitions(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Create Documents Across Partitions ****");
var kirkDocument = await client.CreateDocumentAsync("dbs/myfirstdb", new { userId =
"Kirk", title = "Captain" });
Console.WriteLine("Document 1: {0}", kirkDocument.Resource.SelfLink);
var spockDocument = await client.CreateDocumentAsync("dbs/myfirstdb", new { userId =
"Spock", title = "Science Officer" });
Console.WriteLine("Document 2: {0}", spockDocument.Resource.SelfLink);
}
Первый параметр здесь - это самостоятельная ссылка на базу данных, а не на конкретную коллекцию. Это невозможно без преобразователя разделов, но с ним он работает без проблем.
Оба документа были сохранены в базе данных myfirstdb, но мы знаем, что Кирк хранится в коллекции от A до M, а Спок сохраняется в коллекции от N до Z, если наш RangePartitionResolver работает правильно.
Давайте вызовем их из задачи CreateDocumentClient, как показано в следующем коде.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
await CreateCollections(client);
RegisterRangeResolver(client);
await CreateDocumentsAcrossPartitions(client);
}
}
Когда приведенный выше код будет выполнен, вы получите следующий вывод.
**** Create Documents Across Partitions ****
Document 1: dbs/Ic8LAA==/colls/Ic8LAO2DxAA=/docs/Ic8LAO2DxAABAAAAAAAAAA==/
Document 2: dbs/Ic8LAA==/colls/Ic8LAP12QAE=/docs/Ic8LAP12QAEBAAAAAAAAAA==/
Как видно, ссылки на себя в двух документах имеют разные идентификаторы ресурсов, поскольку они существуют в двух отдельных коллекциях.