Ласкаво просимо до dev.net.ua Увійти | Приєднатися | Допомога | Увійти Live ID
в Пошук

Anton Vidishchev

NoSQL хранилища данных и их использование в .NET

Большинство .NET разработчиков очень редко задаются вопросом где и как хранить данные приложения. Прекрасная интеграция SQL Server с .NET делает его универсальным и удобным хранилищем, которое мы, не задумываясь, используем в любых задачах.

Современные СУБД – это замечательный пример слияния прекрасных инженерных решений и десятков лет опыта в создании надежных, оптимизированных хранилищ данных. Однако все больше программистов выбирают NoSQL хранилища данных, что последнее время считается модным и прогрессивным.

Недавно я решил изучить возможности NoSQL и удобство работы с ними в .NET, и в этой статье поделюсь с вами своим опытом и впечатлениями.

Если немного вернуться в прошлое, 2009 год я бы назвал годом ORM систем. Такие движки как Linq to SQL, Entity Framework, NHibernate стали обязательными инструментами в боекомплекте любого .NET разработчика.

В году нынешнем все чаще можно услышать восторженные отзывы о MongoDb, CouchDB, Cassandra и других хранилищах, а «select fun, profit from real_world where relational=false;» - новый лозунг веб-программистов на динамических языках. NoSQL-хранилища, или document-oriented storages, плотно закрепились на рынке и завоевывают все большую популярность.

К тому же, пример подают такие гиганты как Amazon (Dynamo), Google (BigTable), Twitter (Cassandra) и многие другие.

Чем же не устраивают реляционные СУБД?

Многие проекты имеют высокую динамичность данных. Сущности системы часто меняют структуру, похожие сущности могут немного отличаться набором данных, а некоторые из уже существующих могут со временем «обрастать» новыми свойствами. Из-за строгой структуры данных в базе любые изменения схемы сущностей нужно отражать в структуре таблиц, постоянно усложняя модель (например, в случае наследования) и готовя migration-скрипты. При этих изменениях необходимо менять SQL-запросы или маппинг объектов, к тому же скорость доступа к данным может существенно пострадать (вспомним запросы, генерируемые Entity Framework при Table-per-Type наследовании). В итоге – нам необходимо поддерживать две разнородные модели – реляционную в базе и объектную в коде, и зачастую страдать от потерь производительности.

Также, многие проекты не требуют строгой поддержки ACID-принципов. Намного важнее представляется быстрая обработка данных с минимальным временем отклика, а также быстрая и простая горизонтальная масштабируемость. Кроме того, иногда объем обрабатываемых данных настолько велик, что единственным возможным путем работы является параллельное её решение на кластере.

Концепция NoSQL-хранилищ

Попробую перечислить наиболее характерные, на мой взгляд, особенности:

Schema-less данные. Вместо строго структурированных таблиц мы и имеем коллекции документов, а в некоторых системах и просто наборы ключ-значение. Структура каждого документа может быть индивидуальной, фактически он сам себя описывает. Поддержка документов разной структуры ложится на плечи логики приложения.

Data Sharding. Очень простая горизонтальная масштабируемость. Добавьте сервер в кластер и получите более производительное хранилище. Большинство NoSQL-систем мультиплатформенны, что позволяет собрать распределенное хранилище из практически любого набора серверов. Некоторые хранилища ограничены одним сервером для чтения и записи, остальные серверы read-only (MongoDB), другие (CouchDB) позволяют чтение и запись на всех шардах.

Быстрый поиск по индексу. Это первоочередная задача любой NoSQL системы. Использование B-trees позволяет очень быстрый поиск при низкой стоимости модификации данных.

MapReduce. Механизм параллельной обработки больших объемов данных на кластерах. На шаге Map один из компьютеров (master node) делит задачу на части, распределяя их между остальными компьютерами (worker nodes). На шаге Reduce master node получает предварительные результаты, и формирует из них конечный результат. Это существенно повышает эффективность распределенной обработки данных. Например, реализация MapReduce компанией Google позволяет отсортировать петабайт данных за несколько часов.

MongoDB

Для тестов я остановился на MongoDB. Это одна из самых популярных документно-ориентированных систем работающих на Windows, с массой хороших отзывов и радужными перспективами развития.

Итак, качаем MongoDB для Windows, ставить ничего нужно, все из консоли (снова здравствуй, мир мультиплатформенности).

Создаем папку C:\data\db (можно переконфигурировать).

Запускаем из консоли mongod.exe, это сервер. По пути http://localhost:28017 можно насладиться аскетичным activity-монитором.

Запустим mongo.exe и попробуем сделать пару запросов. Тут царство демократии. Создавать ничего не нужно, база и коллекции появятся, когда вы в них что-то запишете.

Например: 

use testdb
db.Movie.save({ Name: "Fight Club" Year: 1999 })
db.Movie.save({ Name: "Avatar", Year: 2010, Director: "James Cameron" })

Только что мы создали два документа в коллекции Movie. Структура аналогична JSON, и называется BSON (Binary JSON). Обратите внимание, заодно создалась и база в C:\data\db

Попробуем выбрать данные:

db.Movie.find()
{ "_id" : ObjectId("4bc37626a20c0000000072fd"), "Name" : "Fight Club", "Year" : 1999 }
{ "_id" : ObjectId("4bc37633a20c0000000072fe"), "Name" : "Avatar", "Year" : 2010, "Director" : "James Cameron" }

Как видите, идентификаторы документы получили автоматически.

Теперь выберем конкретную запись:

db.Movie.find({Name:"Avatar"})
{ "_id" : ObjectId("4bc37633a20c0000000072fe"), "Name" : "Avatar", "Year" : 2010, "Director" : "James Cameron" }

Использвонание MongoDB в .NET

Поддержка С# и .NET осуществляется сообществом. Наиболее функциональный драйвер - mongodb-csharp. Он еще далек от аналогов для других языков, однако это лучшее, что у нас есть.

С его помощью подключение к базе выглядит следующим образом:

var mongo = new Mongo();
mongo.Connect();
var db = mongo.getDB("testdb");

Добавление нового документа:

var movies = db.GetCollection("Movie");
var movie = new Document();
movie["title"] = "Star Wars";

movies.Insert(movie);

Поиск документов:

var criteria = new Document();
criteria ["title"] = "Star Wars";
var result = movies.FindOne(criteria);

Итак, спартанский функционал у нас уже есть. Стоит также отметить, что среди текущего функционала присутствует «Basic Linq Support», что, в общем, не спасает этот драйвер как продукт, учитывая что официальная вики состоит из трёх предложений и шести строчек кода.

Также стоит обратить внимание на проект NoRM. Проект еще очень молод, первый коммит был сделан 30 января 2010. Однако уже сейчас он предлагает более удобный доступ к данным.

Обьявим класс Movie:

public class Movie

   public Movie() 
   { 
      this.Id = ObjectId.NewObjectId(); 
   } 
   public ObjectId Id { get; set; } 
   public string Name { get; set; } 
   public int Year { get; set; } 
   public string Director { get; set; }
}

ObjectId – класс, представляющий уникальный идентификатор MongoDB из библиотеки Norm.

После чего добавить данные можно следующим образом:

var provider = new MongoQueryProvider(dbName);
provider. DB.GetCollection().Insert(new Movie {Name = "Star Wars", Director = "George Lucas"});

Выбрать данные можно с помощью Linq:

var movie = new MongoQueryProvider(provider).Where(m => m.Name == "Star Wars").FirstOrDefault();

В данном случае взаимодействие с хранилищем приобретает удобоваримый вид, близкий .NET разработчикам.

Программная модель вносит некоторые ограничение на формат данных в базе. Название коллекции должно совпадать с именем класса, а сам класс должен содержать все существующие свойства документов коллекции. Если документ содержит лишь часть свойств, остальные просто не будут заполнены.

Избавиться от этих ограничений можно с помощью Flyweight объектов:

var flys = provider. DB.GetCollection("collectionOfUnknowns");
foreach(var fly in flys)
{
    //проверим наличие значения 
   var value = fly["apropertyname"] ?? "свойство не задано"
   Console.Writeline(value);
}

Выводы

NoSQL хранилища становятся все более популярными благодаря гибкости хранения данных и масштабируемости. Основная их ниша – это проекты на динамических языках программирования, а также проекты с очень большими объемами данных. В статических языках программирования использования NoSQL не так удобно, а С#, возможно, наименее подходящий из современных языков ввиду скудности API драйверов. Однако, с появлением DLR и динамических возможностей C# 4.0 ситуация может существенно измениться в лучшую сторону. К тому же, последнее время начали появляться интересные проекты, делающие взаимодействие все более удобным.

С другой стороны, стоит дождаться, когда Windows Azure станет не будущим, а настоящим. Эта платформа предоставляет различные способы хранения данных, как SQL так и не SQL. Интересно проверить на практике, смогут ли NoSQL хранилища выдержать конкуренцию на платформе .NET?

Опубліковані Friday, April 16, 2010 2:26 PM від Anton Vidishchev
Помічено як: , , , , ,

Коментарі

 

Twitter Trackbacks for Anton Vidishchev : NoSQL ?????????????????? ???????????? ?? ???? ?????????????????????????? ?? .NET [dev.net.ua] on Topsy.com сказав:

April 16, 2010 6:29 AM
 

progg.ru сказав:

Thank you for submitting this cool story - Trackback from progg.ru

April 16, 2010 8:00 AM
 

Ekaterina сказав:

Спасибо за интересный материал.

April 16, 2010 1:38 PM
Анонімні коментарі деактивовані. Увійдіть або Зареєструйтесь щоб мати доступ до ресурсів Спільноти.

About Anton Vidishchev

MCPD: ASP.NET Developer