четверг, 31 мая 2012 г.

Пост 4. CRUD.CREATE.Начинаем работу с Oracle NoSQL DB.

Пока что хватит теории. Давайте немного попрактикуемся. Oracle NoSQL DB поддерживает CRUD (создать, получить, изменить, удалить) операции (позволю себе отвлечься, лучшего ответа на вопрос,что такое база данных я не видел). Итак, хорошие новости! Для того что бы начать работать с NoSQL базой, нам не потребуется много усилий, затраченых на установку оной. Просто качаем небольшой дистрибутив и запускаем версию light. Распаковываем архив, заходим в папочку в случае винды создаем bat файл со следующим содержанием:
java -jar D:\Distr\Linux\NoSQL\kv-2.0.23\lib\kvstore-2.0.23.jar kvlite
и запускаем его.  Собственно все, база запущена! У меня под виндами это выглядит как то так:

Рис 1. Запуск базы.


Теперь нам понадобится какой-либо инструмент для разработки. В моем случае это будет NetBeans (причина выбора оного - личные предпочтения). Итак, база запущена NetBeans открыт, приступим. Прежде чем выполнять какие-либо операции в БД, надо к ней подключится. Делать это мы будем часто, так что давайте создадим отдельный класс, ответственный за это, который будет входить в пакет simpleoperation.


package simpleoperation;

import oracle.kv.KVStore;
import oracle.kv.KVStoreConfig;
import oracle.kv.KVStoreFactory;
public class OraStore {

    private final KVStore oraStore;
    public OraStore(String sname, String host, String port) {
        KVStoreConfig kconfig = new KVStoreConfig(sname, host + ":" + port);
        oraStore = KVStoreFactory.getStore(kconfig);
        System.out.println("Store Opened");
    }
    public KVStore getStore() {
        return oraStore;
    }
}

Как видно для подключения к базе нам потребуется имя хоста, порт базы и имя хранилища(все прям как в RDBMS).
А в главном методе это будет выглядеть как то так:

public class SomeMainClass{


    static String port = "5000";
    static String host = "localhost";
    static String store = "kvstore";

  public static void main(String[] args) throws FileNotFoundException, IOException, InterruptedException {


       OraStore orastore = new OraStore(store, host, port);
        KVStore myStore = orastore.getStore();
        ................... 
        ................... 
       myStore.close();
     }
}

Так подключаться к базе мы умеем. Давайте попробуем создать класс, который будет создавать записи в нашей БД. В документации приведен вот такой вот пример:


package kvstore.basicExample;
import oracle.kv.Key;
import oracle.kv.Value;
import java.util.ArrayList;
...
List<String> majorComponents = new ArrayList<String>();
List<String> minorComponents = new ArrayList<String>();
...
majorComponents.add("Smith");
majorComponents.add("Bob");

minorComponents.add("phonenumber");
Key myKey = Key.createKey(majorComponents, minorComponents);
String data = "408 555 5555";
Value myValue = Value.createValue(data.getBytes());
kvstore.put(myKey, myValue); 

Как видно в этом примере мы сначала создаем два массива для major и minor части. Затем заполняем их (в итоге получается: Smith/Bob/-/phonenumber/). Потом объявляем переменную типа String, называем ее value и присваиваем ей какое-нибудь значение, далее в переменную типа Value выдавливаем поток байтов из String (да, кстати, не забудте добавить в библиотеку kvclient-1.2.123.jar). Давайте автоматизируем процесс записи (это действительно сумашествие, каждый раз проделывать такие выкрутасы, для записи одной строки). Для этого:

1) Достигнем неких договоренностей, а именно: ключ будем записывать в виде: major1/major2/-/minor1/minor2/
2) Создадим вспомогательные классы и методы.

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


    public static Key ParseKey(String keysString2) {
        int endstring;
        if (keysString2.indexOf(":") != -1) {
            endstring = keysString2.indexOf(":") - 1;            
        } else {
            endstring = keysString2.length();
        }
        String keysString = keysString2.substring(0, endstring);
        List<String> majorComponents = new ArrayList<>();
        List<String> minorComponents = new ArrayList<>();

        String[] keysArray = keysString.split("/");
        boolean isMajor = true;
        for (int i = 0; i < keysArray.length; i++) {
            if (keysArray[i].equals("-")) {
                isMajor = false;
                continue;
            }
            if (isMajor) {
                majorComponents.add(keysArray[i]);
            } else {
                minorComponents.add(keysArray[i]);
            }
        }
        if ((majorComponents.size() > 0) && (minorComponents.size() > 0)) {
            myKey = Key.createKey(majorComponents, minorComponents);
        } else if ((majorComponents.size() > 0) & (minorComponents.size() <= 0)) {
            myKey = Key.createKey(majorComponents);
        } else {
            System.out.println("Error");
        }
        return myKey;
    }

Отлично! Давайте теперь создадим метод с помощью которого мы можем записать пару ключ-значение:


    public static void put(String sKey, String data, KVStore myStore)
            throws FileNotFoundException, IOException {
        Key myKey = ParseKey.ParseKey(sKey);
        Value myValue = Value.createValue(data.getBytes());
        myStore.put(myKey, myValue);
    }

Понятно, что в этом случае записывать возможно только переменные типа String. Пока остановимся на этом, чуть позже я приведу пример с другими типами данных(фото, видео). Да и обработки исключений здесь нет, все это мы добавим позже (слона как говорится надо есть по частям). В методе mail это будет выглядеть как то так:


public class SomeMainClass{

    static String port = "5000";
    static String host = "localhost";
    static String store = "kvstore";

  public static void main(String[] args) throws FileNotFoundException, IOException, InterruptedException {

       OraStore orastore = new OraStore(store, host, port);
        KVStore myStore = orastore.getStore();
        SimpleOperations.Create.put("first/key/-/in/db/","Oracle",myStore);
       myStore.close();
     }
}

В завершении поста хотел бы заметить, что помимо метода put поддерживаются еще 3 схожих метода. putIfAbsent запишет пару только в случае отсутствия подобного ключа в базе, putIfPresent запишет только если указанный ключ существует(аналог update) и,наконец, putIfVersion запишет, если версия пары эквивалентна указанной. Про версии мы поговорим немного позже!

Если у вас есть какие-либо вопросы по Oracle NoSQL - задавайте в комментах, постараюсь ответить, либо пишите на oracle.nosql@gmail.com.

вторник, 29 мая 2012 г.

Пост 3. Архитектура Oracle NoSQL Database.

Доброго времени суток!

В данной статье хотел бы рассказать об архитектуре Oracle NoSQL Database. Oracle NoSQL DB - кластерная база данных (информация хранится на множестве серверов, распределена по принципу партишенинга). Данные задублированы на нескольких серверах (количество копий называется Replication factor). Сервера содержащие одинаковые данные объединяются в Replication  Groups (Shard). Внутри шарда реализована мастер-слейв репликация (пишет один, читают со всех). Если Мастер умирает - кто то из слейвов становится мастером (подробнее про master - slave репликацию можно посмотреть здесь). Чем больше мастеров(читай shard-ов) - тем быстрее система работает на запись.



   Рис. 1. Пример топологии NoSQL базы.

Минимальная еденица данной системы - Storage Node (применительно к картинке выше - один из девяти серверов). Каждый  Storage Node состоит из партиций (помните в самой первой статье говорилось, что на высшем уровне абстракции можно понимать Oracle NoSQL DB как одну огомную таблицу,на самом деле сегментируемую по хэшу от ключа на несколько частей). Секционирование - способ разделения инормации на независимые сегменты. Каждая секция имеет локальный B-Tree индекс. Соответственно, если у нас будет мало секций мы получим большие локальные индексы, а как известно чем больше индекс, тем выше стоимость добавления нового элемента.
Если секций будет очень много - мы получим высокую стоимость накладных расходов на вычисление нужной секции. В общем надо искать компромисс.

Рис.2. Key - Value Store в реляционном мышлении.

Строго говоря, Storage Node - логическая еденица(процесс в ОС), то есть один сервер может включать в себя несколько Storage Node. К примеру, если у нас есть 3 сервера и мы хотим обеспечить 3 репликацию данных - без проблем. Это будет выглядеть как то так:

Рис 3. Пример топологии NoSQL базы. 

Но все же не рекомендуется держать всю базу на одном очень мощном сервере. Идея NoSQL баз в разнесении хранилища на множество дешевых серверов.

Это касаемо топологии хранилища. Теперь хотелось бы сделать одно маленькое, но весьма значительное замечание по поводу ключа. Ключ состоит из 2х частей major и minor (пример: /Smith/Bob/-/foto/, /Smith/Bob - это major составляющая ключа, а /foto/ - minor). Major part + Minor part = Key. Minor составляющей может и не быть. Major составляющая влияет на распределение ключа по партициям (и как следствие по серверам), minor - просто вспомогательная составляющая.

Пример:
Key:  /Mijatovic/foto/                               Value: здесь будет аватар
Key:  /Mijatovic/foto/-/album1/My_dog      Value: здесь будет фотография собаки
Key:  /Mijatovic/foto/-/album1/My_Саt      Value: здесь будет фотография кошки

В первом примере Minor составляющая отсутствует. У всех трех записей одинаковый Major key => все записи попадут в одну партицию (ну и конечно же в одну репликационную группу).

Key:  /Mijatovic/foto/                                 Value: здесь будет аватар
Key:  /Mijatovic/foto/album1/ - /My_dog      Value: здесь будет фотография собаки
Key:  /Mijatovic/foto/album1/ - /My_Саt      Value: здесь будет фотография кошки


В этом случае Major key у второй и третей записи будет отличаться от первой. Скорее всего 1 запись попадет в партицию отличную от партиции 2 и 3 записи. Вот как то так...

Если у вас есть какие-либо вопросы по Oracle NoSQL - задавайте в комментах, постараюсь ответить, либо пишите на oracle.nosql@gmail.com.

Продолжение следует!

четверг, 24 мая 2012 г.

Пост 2. Oracle NoSQL DB основные понятия.

Доброго времени суток!

Как и обещал продолжаю свой блог, посвященный продукту Oracle NoSQL.
Это NoSQL база данных типа ключ-значение. Ключ - это указатель на некий набор байт (value).
Как можно понимать ключ? Давайте возьмем пример прямо из документации этого продукта:

/Mijatovic/address/
/Mijatovic/Phone/
/Mijatovic/Phone/-/Mobile/MTS/
/Mijatovic/Phone/-/Mobile/BeeLine/
/Mijatovic/Phone/-/Work/


Ключ представлен как путь в файловой системе. Признаюсь честно, когда я только начал погружаться в мир NoSQL у меня было ошибочное представление о том, что ключ это нечто монолитное и негибкое. От этого у меня сложилось неверное представление о том, как можно выбирать значения по ключу (от чего я хочу застраховать читателя)... К примеру, когда у меня стояла задача обеспечить хранение и доступ к данным весьма подходящим для концепции key-value, я никак не мог понять что же мне использовать как ключ: идентификатор пользователя, либо UNIX-time события. Правильный ответ:и то и то (/UserId/13800....).
Так же можно понимать ключ в виде иерархического дерева(отдаленно напоминает глобал), как то так:


Рис 1. Понимание ключа

Важно: в приведенном примере система имеет 5 пар ключ-значение. То есть каждый ключ указанный выше имеет значение, например:

Key: /Mijatovic/address/                             Value: г.Москва
Key: /Mijatovic/Phone/                               Value: с кнопочками, чёренький :)
Key: /Mijatovic/Phone/-/Mobile/MTS/        Value +7985....
Key: /Mijatovic/Phone/-/Mobile/BeeLine/    Value: +7909....
Key: /Mijatovic/Phone/-/Work/                   Value: +7495...


Так же стоит заметить, что у некоторых ключей может не существовать явного "предка" (ключа /Mijatovic/Phone/-/Mobile/ нет). В Oracle NoSQL ключ - всегда string.
А что же такое Value? Тут еще проще - набор байт. Вот уж действительно не отнять не прибавить.
На языке Java это будет как то вот так:

String data = "Тут какой-то текст, может XML-ка, может еще какой-то текст...";
Value myValue = Value.createValue(data.getBytes());


Вашей базе абсолютно все - равно что вы храните в value, никаких типов просто напросто нет. Вы удивитесь и спросите почему, это же шаг назад(а то и несколько шагов)? Ответ прост. Идея NoSQL: чем проще система, тем она быстрее. И действительно мы живем в реальном мире и не можем прыгнуть выше возможностей этого мира (например, позицонирование головки диска ~ 5 мкс, последовательное чтение 100 мб/сек). Каждый функциональные "наворот" все дальше и дальше отдаляет нас от заветных 15 мкс. Хотите накрученную систему блокировок - получите, а вместе с тем и скорость произвольного чтения 100 мкс, вместо 15. Хотите парсер запросов + крутой оптимизатор? Пожалуйста, получите и вместе с тем 200 мкс, вместо 15...



Рис.2. Чем сложнее, тем медленнее

Вот скажите зачем все это системе, которая использует как правило запросы типа дай строчку по первичному ключу(см.ниже)?

select id from tab1 where PrimaryKey= :v1
Вот именно, незачем. Простой системе простая архитектура хранилки. Реляционные базы конечно же более универсальны, но за универсальность приходится платить скоростью. Если Вам нужен одна-две фичи из сотен которые предоставляет реляционка - реализуйте ее на уровне приложения (ну например, определение типа value, что бы для определенных ключей value было бы не просто набором байт, а переменной типа number).

NoSQL, хорошо или плохо?
В конце поста хотел бы привести некоторую аллегорию. Существуют палочки для суши. Созданы они для того что бы есть суши и замечательно для этого подходят. А как быть с супом? Для этого создана ложка, строго говоря, ложкой можно есть все, вопрос на сколько она к этому подходит.

NoSQL не замена реляционным базам (которые жили, живут и будут жить). Это очень узкоспециализированный инструмент, который подходит под некий(достаточно узкий) класс задач.


Рис.3. Oracle NoSQL DB - очень узкоспециализированный инструмент.

пятница, 18 мая 2012 г.

Пост 1. NoSQL вводная.

Доброго времени суток!

Этим постом хотел бы открыть серию посвященную новому продукту компании Oracle : Oracle NoSQL Database.
Сперва хотел бы внести свои 5 копеек про NoSQL.
В моем понимании это новое семейство баз данных, которое ориентирована на быструю работу с большим объемом данных и экстремальным колличеством пользователей, расплатой за это становится функционал(ни join, ни count...). Произошло движение от сложного к простому. И действительно чем сложнее система, тем она медленнее, чем больше наворотов, тем дальше мы от возможностей физического мира (случайное чтение ~ 15 мкс, последовательное чтение ~ 100 Мб/c), добавляя все новый и новый слой функционала мы отдаляемся от заветных 15 мкс...

Спорить о том "хорошо или плохо NoSQL" я не хочу. Для каждой задачи есть свой инструмент, многие вещи (за исключением проектов крупных интернет гигантов типа Google, facebook...) можно было то сделать и на привычных реляционных БД, но тут встает вопрос что проще и целесообразнее? Возьмем к примеру палочки для суши, ими замечательно можно есть суши! А суп? А пиццу? Наверно не очень удобно :) С другой стороны есть столовая ложка, которой при некой доле снаровки можно съесть все что угодно (и суши и суп), только в некоторых случаях это будет с большое долей извращения. Это сугубо мое личное мнение и мое видение технологии, которое не претендует на истину в последней инстанции.
Мне вспоминается всем известный стишок из всеми любимого фильма "...по миру идет не спеша хорошая девочка Лида. Да чем же она хороша?", так чем же хороши эти базы данных?

Для начала стоит оговориться, что среди NoSQL выделяют 4 типа:
1) Key - value
2) Column famaly
3) Документоориентированные
4) Графориентированные
Подробнее вот тут
Я остановлюсь на БД типа ключ - значение (Key - value). В основу этого подхода положено то, что все данные разбиваются на пары ключ -значения, где ключ - это просто индекс, а значение набор байтов, расшифровывать которое будет приложение.
В реляционном мире это выглядело бы вот так:



Рис 1. Представление Key - Value в реляционном мышлении
Так все-таки где могут быть полезны такие БД? В первую очередь для хранения неструктурированной информации или полуструктурированной (фото, XML, JSON...). Для получения быстрого отклика на простые запросы (дай значение по ключу). Для хранения большого объема данных (терабайты, петабайты...). Для поддержания большого количества одновременно работающих пользователей. Ну и впринципе везде где использование реляционок не целесообразно (если не использутеся 99% функционала, а тот 1 процент есть в NoSQL альтернативе).

Постараюсь привести ряд примеров:
• Facebook
Почему? Данных очень много
• Google
Почему? Данных очень много
• Twitter
Почему? Данных очень много
Ну а если у меня нет ни гугла, ни твитера, ни фейсбука? :)

Тогда:
• LDAP подобные системы - простой ответ на простой вопрос
Почему? Это быстро!
• Хранилище USSD запросов мобильных пользователей
Почему? Нет четкой структуры исходных данных
• Персоонализация пользователей
Почему? Нет четкой стрктуры данных, постоянные доработки системы
• Сбор разнотипных данных со счетчиков
Почему? Требуется поддержка большого колличества одновременных сессий
• Логирование интернет трафика (CDR GPRS, web logs)
Почему? Данных очень много
• Хранилище файлов (фотографии, видео, текст)
Почему? Данных может быть очень много и к ним требуется быстрый доступ (системы аналогичные drop box, Google disk)
• Интернет магазины
Почему? Нет четкой структуры данных. Данных может быть много
• Антиспам системы
Почему? Очень много простых запросов (пример: Mollom)

Вот наверное и все что я хотел сказать про NoSQL.
В следующем посте будет рассмотрен конкретный продукт - Oracle NoSQL