вторник, 4 февраля 2014 г.

Пост 31. Многопользовательский доступ к данным. Чтение LOB.

В ходе тестироавния так же было интересно проверить поведение системы при многопользовательском доступе. Для это было проведено следующее испытание: последовательно раз в 2 минуты запускался поток на чтение данных из базы. При этом как и в предыдущих тестах снимались все нагрузочные показатели. 

На подсистеме ввода-вывода наблюдается инкрементальный рост до некоторой величины, которая является пределом пропускной способности.

IO (Kb/sec) как функция от времени для всех узлов кластера (для увеличения кликните на картинку).

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

Интересен и следующий график - на нем представлена зависимость времени выполнения операции (ось Y) в зависимости от колличества одновременных пользователей (ось X).

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

Видно, что на уровне12 пользователей мы достигаем предела пропускной способности системы и затем наблюдается линейная деградация производительности.
Обращу внимание, что в данном случае исследовалось поведение системы в случае с LOB объектами.

пятница, 10 января 2014 г.

Пост 30. Результыты тестирования Oracle NoSQL Database. Поведение системы во время расширения.

Итак, как показало тестирование, описанное в предыдущем посте Oracle NoSQL Database - масштабируемая база данных. Как же система ведет себя во время расширения? Давайте рассмотрим следующий тест кейс.

Описание тест кейса:Кластер расширяется с 6 узлов до 9
10:37 Добавление трех узлов в кластер
10:45 Старт нагрузки на чтение
11:43 Стоп нагрузки на чтение
11:50 Старт нагрузки на запись
12:10 Стоп нагрузки на запись


IO (Kb/sec) как функция от времени для всех узлов кластера (для увеличения кликните на картинку).


Network (MBytes/sec) как функция от времени для всех узлов кластера (для увеличения кликните на картинку).


CPU (Idle %) как функция от времени для всех узлов кластера (для увеличения кликните на картинку).

Выводы:
1)Вновь добавленные сервера утилизируют все имеющиеся ресурсы для достижения консистентного состояния
2)Уже имеющиеся сервера так же используют значительную часть ресурса для достижения кластером консистентного состояния
3)Данные для чтения на новых серверах доступны как только они были туда перенесены
4) Запись файлов равномерно нагружает «новые» и «старые» узлы
5) Нулевое время простоя системы

четверг, 9 января 2014 г.

Пост 29. Результыты тестирования Oracle NoSQL Database. Масштабируемость.

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

Описание тестовой нагрузки на БД:
17:15 Запись нагрузки на чтение (20 потоков)
17:24 Выведение из строя 6 серверов
17:30 Возвращение в строй ранее выведенных серверов



IO (Kb/sec) как функция от времени для всех узлов кластера (для увеличения кликните на картинку).



Network (Bytes/sec) как функция от времени для всех узлов кластера (для увеличения кликните на картинку)



CPU (Idle %) как функция от времени для всех узлов кластера (для увеличения кликните на картинку).

Выводы:
Oracle NoSQL Database пытается равномерно распределить нагрузку между серверами. Чем больше серверов – тем меньше нагрузка на каждый из них.
В случае добавления новых узлов в кластер (расширение) – часть нагрузки перейдет на них.

Пост 28. Результыты тестирования Oracle NoSQL Database. Восстановление после сбоев.

Доброго времени суток!
Итак, я прождолжаю серию постов посвященную тестированию базы данных NoSQL.

В этом тесте хотелось посмотреть поведение базы данных при сбое серверов и последующемм вводе их обратно в кластер.

Описание тестовой нагрузки на БД:
15:11 – Старт записи в NoSQL DB в 5 потоков (18 узлов кластера доступно)
15:37, 15:42 – Последовательное выведение из строя 6 узлов
15:47 – Возврат нод в кластер
15:50 – Конец восстановления



IO (Kb/sec) как функция от времени для всех узлов кластера (для увеличения кликните на картинку).Во время восстановления на каждой ноде нагрузка было около 850 Mbytes/sec


Network (Bytes/sec) как функция от времени для всех узлов кластера (для увеличения кликните на картинку)
Во время восстановления сеть утилизирована на 18 Gbit/sec.


CPU (Idle %) как функция от времени для всех узлов кластера (для увеличения кликните на картинку).
Во время восстановления используется 50% процессорного ресурса.

"Всплески" обусловлены тем, что база данных копировала данные, записанные после вывода из строя серверов на вновьпоявившиеся ноды.

Выводы:
Oracle NoSQL Database затрачивает все имеющиеся ресурсы для достижения консистентного состояния
В ходе данного теста:
-Дисковая система использовала максимальный ресурс около 850 Мбайт/сек
-Сеть была загружена на 18 Гбит/сек. Сеть Infiniband (интерконект) необходима для скорейшего восстановления системы после сбоя одного из узлов или дисков
-Процессоры загружены на 50% во время репликации недостающих данных на вновь появившиеся сервера

Пост 27. Результыты тестирования Oracle NoSQL Database. Чтение файлов.

Доброго вермени суток!
Как я писал ранее не так давно удалось поучавствовать в одном крупном тестированни базы данных NoSQL. Подробности тут. А в этом посте я хотел бы описать что происходило с базой во время чтения.

Чтение файлов из базы

Описание нагрузки на БД: 10:00 – 11:30 старт чтения из базы в 240 потоков
Конфигурация:15 узлов BDA использовались под Oracle NoSQL DB, 3 ноды использовались под сервер приложений

В коде программы использовались следующие настройки:

1)Порция чтения:
byte[] bytes = new byte[1024];

2) Consistency на чтение
Consistency.NONE_REQUIRED
Использовалось потому что запись производилась с опцией
Durability.ReplicaAckPolicy.ALL
3) Один поток – один экземпляр Java программы который вычитывает 1 Гб из базы в цикле


Зависимость ввода вывода KB/sec в зависимости от времени для каждого узла (для увеличения кликните на картинку).
IO каждого сервера 450 Mbytes/sec


Загруженность сети для каждого узла BDA (bytes/sec) в зависимости от времени (для увеличения кликните на картинку).
Сеть загружена равномерно на 3,8 Gbit/sec


Зависмость процессорной нагрузки для каждого из сервров (процент занятого ресурса) в зависимости от времени (для увеличения кликните на картинку).
CPU на всех узлах нагружено примерно на 20 %.

Выводы:
1)Во время записи файлов нагрузка ложится равномерно на все узлы кластера (IO, Network, CPU)
2)Пропускная способность на чтение 4 Gbytes/sec на одну стойку BDA
Во время максимальной нагрузки:
- IO каждого сервера примерно 450 Mbytes/sec
- Сеть на всех узлах нагружена равномерно на 3,8 Gbit/sec (репликация данных по интерконнекту).
В данном случае используются преимущества Infiniband.
- CPU равномерно загружена на всех узлах кластера на 20%
Пост 26. Результыты тестирования Oracle NoSQL Database. Запись файлов.

Доброго времени суток!
Не так давно мне посчастливилось поучавствовать в тестировании базы данных Oracle NoSQL Database на достаточно большом кластере, для достаточно интересной задачи. Пользуясь случаем хотел бы поделиться с широкой публикой результатами тестирования.

Итак, для начала постановка задачи:
1.Заказчик изготавливает авиадвигатели
2. В ходе испытаний двигателя генерится большое количество телеметрии
3. Эти данные требуются экспертам для анализа сразу после проведения испытания
4. Уже есть приложение для анализа этих данных

Теперь подробности:
- Ожидаемый объем хранилища 2.5 Pb
- Ожидаемое количество файлов 1-2милиарда
- Размер одного файла 1 Mb – 2 Gb
- Вся информация критична. Потери данных невозможны
- Требуется поддержка 20 одновременных пользователей на чтение
- Требуется поддержка 50 одновременных пользователей на запись
- Пропускная способность на запись не ниже 200 MBytes/sec
- Пропускная способность на чтение не ниже 500 MBytes/sec
- Сервер приложений работает под Windows
- Решение должно быть масштабируемым. Планируется докупать оборудование без изменений программной части
- Высокая скорость восстановления после сбоев

На данный исторический момент заказчик хранит все в СУБД Oracle. Файлы испытаний хранятся в BLOB колонках. Сама структура базы данных весьма запутана, содержит множество таблиц и связей между ними. Поисковое приложение позволяет достаточно гибко осуществлять поиск по файлам испытаний. Переделать все в структуу ключ-значение было достаточно сложно.

Поэтому предлагалась следующая архитектура:


От пользователя запрос по-прежнему уходил в СУБД, но вместо BLOB приложению возвращалась ссылка на ключ в файлом (varchar2), по которому приложение вытягивало файл и обрабатывало.

Используемое оборудование для кластера NoSQL:

Big Data Appliance x2-2:
18 узлов для вычислений и хранения данных
Для каждого узла:2 шестиядерных процессора Intel ® Xeon ® 5675 (3,06 ГГц)
48 Гб оперативной памяти
12 дисков SAS емкостью 3 Тбайт и скоростью 7200 RPM
Сеть Infiniband (40 Гбит/с)

Сервер приложений:
Sun Server X3-2L Server
CPU: Intel Xeon E5-2690 2 шт, 8 ядер, 2.9GHz
Память: 256 Гбайт
Storage: 8x 600Гбайт 10K
Сеть: 1 Гбит/сек, Infiniband 40 Гбит/сек

Запись в NoSQL производилась в LOB пары ключ - значение.

Теперь собственно тесты.

1.Запись файлов в базу
Описание нагрузки на БД:
16:05 – 16:45 запись фалов в 120 потоков (имитация 120одновременных пользователей).
15 серверов BDA использовались для NoSQL хранилища, 3 BDA узла для серверов приложений.
В коде программы использовались следующие настройки:

1) Durability
Durability.SyncPolicy.WRITE_NO_SYNC, on masterDurability.SyncPolicy.WRITE_NO_SYNC, on replicasDurability.ReplicaAckPolicy.ALL

2) Использовалось LOB API
putLOB(myKey, fis, durability, 30, TimeUnit.SECONDS)

3) Replication factor = 3

4) Один поток – один экземпляр Javaпрограммы который записывает 1 Гб данных в базу в цикле (ключи различные)



Зависимость ввода вывода KB/sec в зависимости от времени для каждого узла (для увеличения кликните на картинку).
Подсистема ввода-вывода серверов кластера базы данных NoSQL при записи фалов в базу.
Среднее значение IO для каждой ноды BDAоколо 750 Mb/sec


Загруженность сети для каждого узла BDA (bytes/sec) в зависимости от времени для каждого узла  (для увеличения кликните на картинку)
Сеть равномерно загружена на всех узлах кластера на 18,6 Gbit/sec (репликация данных по интерконнекту).


Зависмость процессорной нагрузки для каждого из сервров (процент занятого ресурса) в зависимости от времени  (для увеличения кликните на картинку).
CPU равномерно загружена на всех узлах кластера на 40 – 50%

Выводы:1) Во время записи файлов нагрузка ложится равномерно на все узлы кластера (IO, Network, CPU)
2) Пропускная способность на запись 4 Gbytes/sec на одну стойку BDA
3) Во время максимальной нагрузки:
- IO каждого сервера примерно 2700 операций/сек или 750 Mbytes/sec
- Сеть на всех узлах нагружена равномерно на18,6 Gbit/sec (репликация данных по интерконнекту).
В данном случае используются преимущества Infiniband.
-CPU равномерно загружена на всех узлах кластера на 40 – 50%
4) Узким местом системы являются диски.

Продолжение следует!
Пост 25. Добавление новых узлов в кластер. Увеличение репликационного фактора для увеличения пропускной способности на чтение.

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

Создавалась такая конфигурация следующим скриптом:
[root@datanode1 ~]# cat deploy_rf2.txt
configure -name "FilDB"
plan deploy-datacenter -name "FilDC" -rf 2 -wait
plan deploy-sn -dc dc1 -host datanode1 -port 5011 -wait
plan deploy-admin -sn sn1 -port 5001 -wait
plan deploy-sn -dc dc1 -host datanode2 -port 5012 -wait
plan deploy-sn -dc dc1 -host datanode3 -port 5013 -wait
plan deploy-sn -dc dc1 -host datanode4 -port 5014 -wait
pool create -name FilPool
pool join -name FilPool -sn sn1
pool join -name FilPool -sn sn2
pool join -name FilPool -sn sn3
pool join -name FilPool -sn sn4
topology create -name topo -pool FilPool -partitions 300
plan deploy-topology -name topo -wait
[root@datanode1 ~]# kvadmin load -file deploy_rf2.txt

Теперь из этой схемы мы хотим сделать следующую:

Просто  выполним скрипт:
[root@datanode1 ~]# cat change_rf.txt
plan deploy-sn -dc dc1 -host datanode5 -port 5015 -wait
plan deploy-sn -dc dc1 -host datanode6 -port 5016 -wait
pool join -name FilPool -sn sn5
pool join -name FilPool -sn sn6
topology clone -current -name NewTopo
topology change-repfactor -name NewTopo_chrf -pool FilPool -rf 3 -dc dc1
plan deploy-topology -name NewTopo_chrf -wait
[root@datanode1 ~]# kvadmin load -file change_rf.txt

Таким образом мы добавили 2 ноды в кластер и увеличили репликационный фактор системы до 3х (тем самым увеличив пропускную способность на чтение). Колличество шардов, при этом не поменялось. Новые ноды будут отрабытывать запросы на чтение.

четверг, 18 апреля 2013 г.

Пост 24. Добавление новых узлов в кластер. Увеличение колличества шардов.

Доброго времени суток!
Сегодня хотел бы рассказать как происходит процесс добавления новых узлов в кластер  Oracle NoSQL Database. А точнее как происходит наращивание шардов. Это поможет нам решить 2 задачи:
- Увеличит емкость базы данных
- Увеличит пропускную способность на запись (мы помним, что один шард - один мастер, который пишет).

Предположим у нас есть двухшардовая конфигурация состоящая из 6 серверов  (2х3), которая была раздеплоена следующим образом:


kv-> configure -name "FilDB"
kv-> plan deploy-datacenter -name "FilDC" -rf 3 -wait
kv-> plan deploy-sn -dc dc1 -host datanode1 -port 5011 -wait
kv-> plan deploy-admin -sn sn1 -port 5001 -wait
kv-> plan deploy-sn -dc dc1 -host datanode2 -port 5012 -wait
kv-> plan deploy-sn -dc dc1 -host datanode3 -port 5013 -wait
kv-> plan deploy-sn -dc dc1 -host datanode4 -port 5014 -wait
kv-> plan deploy-sn -dc dc1 -host datanode5 -port 5015 -wait
kv-> plan deploy-sn -dc dc1 -host datanode6 -port 5016 -wait
kv-> pool create -name FilPool
kv-> pool join -name FilPool -sn sn1
kv-> pool join -name FilPool -sn sn2
kv-> pool join -name FilPool -sn sn3
kv-> pool join -name FilPool -sn sn4
kv-> pool join -name FilPool -sn sn5
kv-> pool join -name FilPool -sn sn6
kv-> topology create -name topo -pool FilPool -partitions 300
kv-> plan deploy-topology -name topo -wait

Визуально это будет выглядеть как то так:


Если есть желание посмотреть подобное состояние из командной строки надо набрать команду ping из kvadmin:

[root@datanode1 ~]# kvadmin
kv-> ping
Pinging components of store FilDB based upon topology sequence #315
FilDB comprises 300 partitions and 6 Storage Nodes
Storage Node [sn1] on datanode1:5011    Datacenter: FilDC [dc1]    Status: RUNNING   Ver: 11gR2.2.0.26 2013-01-28 12:19:21 UTC  Build id: 99ef986805a3
        Rep Node [rg1-rn1]      Status: RUNNING,MASTER at sequence number: 321 haPort: 8101
Storage Node [sn2] on datanode2:5012    Datacenter: FilDC [dc1]    Status: RUNNING   Ver: 11gR2.2.0.26 2013-01-28 12:19:21 UTC  Build id: 99ef986805a3
        Rep Node [rg1-rn2]      Status: RUNNING,REPLICA at sequence number: 321 haPort: 8200
Storage Node [sn3] on datanode3:5013    Datacenter: FilDC [dc1]    Status: RUNNING   Ver: 11gR2.2.0.26 2013-01-28 12:19:21 UTC  Build id: 99ef986805a3
        Rep Node [rg1-rn3]      Status: RUNNING,REPLICA at sequence number: 321 haPort: 8300
Storage Node [sn4] on datanode4:5014    Datacenter: FilDC [dc1]    Status: RUNNING   Ver: 11gR2.2.0.26 2013-01-28 12:19:21 UTC  Build id: 99ef986805a3
        Rep Node [rg2-rn1]      Status: RUNNING,MASTER at sequence number: 321 haPort: 8400
Storage Node [sn5] on datanode5:5015    Datacenter: FilDC [dc1]    Status: RUNNING   Ver: 11gR2.2.0.26 2013-01-28 12:19:21 UTC  Build id: 99ef986805a3
        Rep Node [rg2-rn2]      Status: RUNNING,REPLICA at sequence number: 321 haPort: 8500
Storage Node [sn6] on datanode6:5016    Datacenter: FilDC [dc1]    Status: RUNNING   Ver: 11gR2.2.0.26 2013-01-28 12:19:21 UTC  Build id: 99ef986805a3
        Rep Node [rg2-rn3]      Status: RUNNING,REPLICA at sequence number: 321 haPort: 8600

kv->


Теперь возникла необходимость увеличить емкость базы данных путем добавления новых серверов.
Нет ничего проще для этого надо выполнить ряд команд в админской консоли (добавление серверов в пул и перебалансировка):

kv-> pool join -name FilPool -sn sn7
kv-> pool join -name FilPool -sn sn8
kv-> pool join -name FilPool -sn sn9
kv-> topology clone -current -name toponew
kv-> topology redistribute -name toponew  -pool FilPool
kv-> plan deploy-topology -name toponew  -wait

После чего начнется перебалансировка партиций (тех самых число которых не меняется).

То есть первоначально я создал 2 шарда и 300 партиций. Они равномерно распределились между партициями. Теперь я добавил 3 шард. Произошла перебалансировка партиций - у каждого шарда осталось по 100 партиций.

Для того что бы убедиться можно дать следующую команду:

kv-> show topology
............................
............................
  shard=[rg1] num partitions=100
    [rg1-rn1] sn=sn1
    [rg1-rn2] sn=sn2
    [rg1-rn3] sn=sn3
  shard=[rg2] num partitions=100
    [rg2-rn1] sn=sn4
    [rg2-rn2] sn=sn5
    [rg2-rn3] sn=sn6
  shard=[rg3] num partitions=100
    [rg3-rn1] sn=sn7
    [rg3-rn2] sn=sn8
    [rg3-rn3] sn=sn9

kv->

Любите технологии, не бойтесь экспериментировать и если у вас появятся какие-либо вопросы касаемо этого поста - не стеснятесь их задавать!
Пост 23. Инсталяция Oracle NoSQL Database.

Доброго времени суток! Наверное давно было пора написать о том как инсталировать NoSQL базу данных производства Oracle. Официальнцую документацию можно найти здесь. Документация написана качественно и основательно и должна являться первоисточником для проверки всех догадок и теорий касаемо процесса инсталяции Oracle NoSQL Database. Здесь же я постараюсь изложить квинтэсценцию своего опыта. Итак, для инсталяции мною были взяты 10 серверов. 9 из них были отданы под базу данных, 1 под сервер приложения и management сервер (прим. на этих серверах так же установлен hadoop - отсюда и названия: cdh, datanode1...).

На подготовительном этапе вам предстоит сделать следующее:
1) Обеспечить беспарольный ssh между серверами кластера (не обязательно - но удобно с точки зрения администрирования). В интернете оооочень много статей на данный счет я обычно делаю так:

создаю файл servers.list в который помещаю IP всех серверов с которыми я хочу установить беспарольное соединение, а затем использую нехитрые команды, представленные ниже:

# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa 
# cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
# cat ~/servers.list | while read i ; do ssh-copy-id -i ~/.ssh/id_rsa.pub root@"$i" ; done

2) Скачать и установить pdsh.
3) Я создал для простоты работы я создал в /usr/bin/ файл pdsh_hdfs (как упоминалось ранее здесь так же установлен hadoop, отсюда и название), следующего содержания:
#!/bin/bash
pdsh -w root@192.168.1.[110-120] $*

Теперь команда pdsh_hdfs применяется ко всем серверам кластера.

Теперь мы готорвы к процессу инсталяции:

1) Скачиваем дистрибутив Oracle NoSQL Database и раскидываем его на все сервера 
2) Распаковываем его на всех серверах и создаем переменную окружения $KVHOME, которая указывает на папку с распакованным дистрибутивом (в моем случае на всех серверах это было 
/home/oracle/nosql/kv-2.0.26).
3) Если у нас была инсталяция до этого "подчищаем" ее:
for i in `seq 1 9`; do ssh datanode$i rm -rf $KVHOME/kvroot; done;
for i in `seq 1 9`; do ssh datanode$i "pkill -f 'java -jar'"; done;
4) Создаем папки на всех серверах для базы данных:
do ssh datanode$i mkdir $KVHOME/kvroot; done;
5) Oracle NoSQL Database очень чувствительна к временному расхождению внутри серверов кластера. Если расхождение больше 2 секунд - база данных не раздеплоится.
Используем команду ntpdate, для синхронизации. Я засунул в crontab временую синхронизацию:
 pdsh_hdfs "echo "*/1 * * * * ntpdate ntp.server.my.company.com" >> /var/spool/cron/root"

Прим.: ntpdate не работает поверх proxy (как было в моем случае) - поэтому я использовал ntp server моей компании. Если же есть непроксеванный интеренет - можно использовать публичные ntp сервера.

6) Далее необходимо описать начальную конфигурацию базы данных (создать bootconfig) на каждом из серверов.
Один сервер сделаем admin сервером (т.е.с него мы в последствии и будем осуществлять админские операции):

ssh datanode1 "java -jar /home/oracle/nosql/kv-2.0.26/lib/kvstore.jar makebootconfig -root /home/oracle/nosql/kv-2.0.26/kvroot -host datanode1 -port 5011 -admin 5001 -harange 8100,8101 -config conf1.xml"; done;

7) Создаем конфиги на всех остальных серверах:
for i in `seq 2 9`; do ssh datanode$i "java -jar /home/oracle/nosql/kv-2.0.26/lib/kvstore.jar makebootconfig -root /home/oracle/nosql/kv-2.0.26/kvroot -host datanode$i -port 501$i -harange 8${i}00,8${i}01 -config conf1.xml"; done;

Здесь мне следует остановится и дать некие пояснения по поводу портов указанных в конфигах:
registry port - основной порт, на который "садится" база и по которому она доступна для клиента.
Admin Console port - порт для админконсоли.
HA Range - порты для коммуникации между собой (hand for "replication) узлов кластера.

Эта команда создает конфиг, который будет использоваться на следующем шаге:
<config version="2">
  <component name="params" type="bootstrapParams" validate="true">
    <property name="adminHttpPort" value="0" type="INT"/>
    <property name="hostingAdmin" value="false" type="BOOLEAN"/>
    <property name="storeName" value="FilDB" type="STRING"/>
    <property name="storageNodeId" value="4" type="INT"/>
    <property name="memoryMB" value="2091" type="INT"/>
    <property name="hostname" value="datanode4" type="STRING"/>
    <property name="numCPUs" value="2" type="INT"/>
    <property name="rootDir" value="/home/oracle/nosql/kv-2.0.26/kvroot" type="STRING"/>
    <property name="haPortRange" value="8400,8401" type="STRING"/>
    <property name="registryPort" value="5014" type="INT"/>
  </component>
  <component name="mountPoints" type="bootstrapParams" validate="false">
  </component>
</config>

8) Стартуем на всех серверах экземпляр, используя конфиг, созданный на предыдущем шаге:
for i in `seq 1 9`; do ssh datanode$i "nohup java -jar /home/oracle/nosql/kv-2.0.26/lib/kvstore.jar start -root /home/oracle/nosql/kv-2.0.26/kvroot -config conf1.xml &" && echo $i ; done;

9) Теперь у нас есть материал для конфигурации базы данных (нечто вроде пластилина из которого мы будем лепить что то), создании топологии

Если зайти на datanode1:5001 (админский порт - можно увидеть "пустую" топологию).

Теперь приступим к конфигурации нашей БД. 
Тут у меня будет просьба к читателю пожалуйста освещите в памяти архитектуру БД Oracle NoSQL и понятийный аппарат, который будет использоваться
Из 9 серверов "так и хочется" создать базу данных состоящую из трех шардов с репликационным фактором 3 (шард будет содержать по 3 копии данных).
Сказано - селано.

10) Переходим на сервер, который был скорфигурирован как admin (в моем случае это datanode1)
[root@cdh ~]# ssh datanode1
Last login: Thu Apr 18 13:50

Здесь я создал alias, позволяющий мне одной командой запускать admin консоль:
alias kvadmin='java -jar /home/oracle/nosql/kv-2.0.26/lib/kvstore.jar runadmin -port 5011 -host datanode1'

[root@datanode1 ~]# kvadmin
kv->

11) Создаем базу данных:
kv-> configure -name "FilDB"

12) создаем дата центр, указываем репликационный фактор:
kv-> plan deploy-datacenter -name "FilDC" -rf 3 -wait

13) Создаем storage node, после чего на ней же деплоим админ сервис:
kv-> plan deploy-sn -dc dc1 -host datanode1 -port 5011 -wait
kv-> plan deploy-admin -sn sn1 -port 5001 -wait

14) Создаем остальные storage node
kv-> plan deploy-sn -dc dc1 -host datanode2 -port 5012 -wait
kv-> plan deploy-sn -dc dc1 -host datanode3 -port 5013 -wait
kv-> plan deploy-sn -dc dc1 -host datanode4 -port 5014 -wait
kv-> plan deploy-sn -dc dc1 -host datanode5 -port 5015 -wait
kv-> plan deploy-sn -dc dc1 -host datanode6 -port 5016 -wait
kv-> plan deploy-sn -dc dc1 -host datanode7 -port 5017 -wait
kv-> plan deploy-sn -dc dc1 -host datanode8 -port 5018 -wait
kv-> plan deploy-sn -dc dc1 -host datanode9 -port 5019 -wait

Заглянем после этого в нашу web админ-консоль:


Видим, что "пластелин" приобрел более конкретные очертания:)

15) Создаем пул серверов и "закидываем" туда все 9 нод

kv-> pool create -name FilPool
kv-> pool join -name FilPool -sn sn1
kv-> pool join -name FilPool -sn sn2
kv-> pool join -name FilPool -sn sn3
kv-> pool join -name FilPool -sn sn4
kv-> pool join -name FilPool -sn sn5
kv-> pool join -name FilPool -sn sn6
kv-> pool join -name FilPool -sn sn7
kv-> pool join -name FilPool -sn sn8
kv-> pool join -name FilPool -sn sn9

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

kv-> topology create -name topo -pool FilPool -partitions 300

17) Конечная команда, котрой развертываем наш пул:

kv-> plan deploy-topology -name topo -wait

Теперь еще раз заходим в web консоль и смотрим, на топологию нашей базы:
Ура! База инсталирована. Если будут вопросы - пишите! В дальнейшем мы проведем несколько экспериментов!

среда, 17 апреля 2013 г.

Пост 22. Версионность в Oracle NoSQL Database. Тесты.

Решил я вот вернуться на 2 поста назад и написать еще про версионность. Давайте посмотрим на то как ведет себя Oracle NoSQL база при обработке версионных исключений.
Конкретный пример - инкрементальное увеличение счетчика.
Допустим у нас есть своя социальная сеть. И мы хотим знать сколько пользователей нашей соц. сети существует. Заводим специальный ключ /user/count/ и при добавлении нового пользователя инкрементально увеличиваем его на 1. Достаем старое значение, увеливаем на 1, записаваем. Сказано - сделано. Написали для этого целый класс:

package test;

import java.io.FileNotFoundException;
import java.io.IOException;
import oracle.kv.KVStore;
import CRUD.Create;
import CRUD.Delete;
import Support.OraStore;
import CRUD.Retrieve;
import oracle.kv.Durability;
import oracle.kv.Value;
import oracle.kv.ValueVersion;

public class test_version_badcode {
static String[] hhost = {"localhost:5000"};
static String store = "kvstore";
public static void main(String[] args) throws FileNotFoundException, IOException, InterruptedException {
OraStore orastore = new OraStore(store, hhost);
KVStore myStore = orastore.getStore();
for (int i = 1; i < 10001; i++) {
ValueVersion vv = CRUD.Retrieve.SelectRowVV("user/count", myStore);
Value v = vv.getValue();
String cntr = new String(v.getValue());
int num_users = Integer.parseInt(cntr) + 1;
CRUD.Create.put("user/count", Integer.toString(num_users), myStore);
}
myStore.close();
System.out.println("Store closed");
}
}


И запустили метод main доторый "добавляет" 10 000 пользователей в 2х разных сессиях, ожидая увидить 20 000 в итоге.

И о "чудо" их 15796... Думаю уже на 25 строчке кода вы подумали что в хорошем обществе так делать не принято. Дейсвительно одна сессия "затирала" результаты другой. Давайте договоримся, что так как показано в примере выше вы делать никогда не будете.
Для решения этой задачи создадим метод который вытаскивает Value и Version по ключу:

public static ValueVersion SelectRowVV(String sKey, KVStore myStore) {

Key myKey = ParseKey.ParseKey(sKey);
ValueVersion vv = null;
try {
vv = myStore.get(myKey);
} catch (RequestTimeoutException re) {
System.out.println(re.getTimeoutMs());
} catch (FaultException fe) {
System.out.println("Unknown error");
} catch (NullPointerException ne) {
System.out.println("Key does not exist");
}
return vv;
}

Так же метод на основе putIfVersion. На вход мы будет передавать версию только что прочитанной пары. Метод будет пытаться сделать Update записи. Если версия поменялась (после чтения другая сессия изменила значение по этому ключу), метод выдаст ошибку (вернет строку состояния операции):
public static String UpdateIfNotchange(String sKey, String data, Version OldVersion, KVStore myStore)
 throws FileNotFoundException, IOException, InterruptedException
{
retdata = null;
Key myKey = ParseKey.ParseKey(sKey);
Value myValue = Value.createValue(data.getBytes());
try {
Version NewVersion = myStore.putIfVersion(myKey, myValue, OldVersion);
if (NewVersion == null) {
System.out.println("Operation Failed! Vesion error");
retdata = "Operation Failed";
} else {
System.out.println("Record created in the kvstore.");
retdata = "Record created in the kvstore";
}
} catch (NullPointerException np) {
System.out.println("KV pair doesn't exist!");
}
return retdata;
}

Имея все это великолепие методов мы можем написать финльный класс, которым протестируем работу версионности в NoSQL (подобно первому случаю):

package test;
import java.io.FileNotFoundException;
import java.io.IOException;
import oracle.kv.KVStore;
import CRUD.Create;
import CRUD.Delete;
import Support.OraStore;
import CRUD.Retrieve;
import oracle.kv.Durability;
import oracle.kv.Value;
import oracle.kv.ValueVersion;

public class test_version {
static String[] hhost = {"localhost:5000"};
static String store = "kvstore";

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

OraStore orastore = new OraStore(store, hhost);
KVStore myStore = orastore.getStore();
String retcode;
for (int i = 1; i < 10001; i++) {
retcode = "Operation Failed";
while (retcode.equals("Operation Failed")) {
ValueVersion vv = CRUD.Retrieve.SelectRowVV("user/count", myStore);
Value v = vv.getValue();
String cntr = new String(v.getValue());
int num_users = Integer.parseInt(cntr) + 1;
retcode = CRUD.Update.UpdateIfNotchange("user/count", Integer.toString(num_users), vv.getVersion(), myStore);
}
}
myStore.close();
System.out.println("Store closed");
}
}

Запускаем 2 параллельные сессии каждая из которых будет добавлять по 10 000 пользователей. Переодически в вывод программы будут падать ошибки:

Operation Failed! Vesion error
Record created in the kvstore.
Record created in the kvstore.
Record created in the kvstore.
Record created in the kvstore.
Operation Failed! Vesion error
Operation Failed! Vesion error
Operation Failed! Vesion error
Operation Failed! Vesion error
Record created in the kvstore.
Record created in the kvstore.

Ничего страшного - после этого exception произойдет повторная попытка чтения update.
В итоге после окончания работы этих 2х методов по ключу /user/count/ мы можем найти ожидаемые 20 000. Ура!

Если будут вопросы - пишите!

пятница, 12 апреля 2013 г.

Пост 21. Large Object в Oracle NoSQL Database (LOB).

Доброго времени суток!
В Oracle NoSQL DB версии 2 появилась поддержка Large Object.

Когда то совсем давно я писал, что Oracle NoSQL – хорошая платформа для хранения больших файлов: видео и аудио, например. Но вот как то получилось так, что я не рассказал как это делать.
Во-первых, давайте договоримся о том какой объект считать большим более 1 Мб (так рекомендует Oracle). LOB объект хранится как набор chunk-ов (сами chunk могут быть разного размера).
Во-вторых, давайте посмотрим как записывать LOB в базу. Давайте запишем некоторый файл.
По традиции создадим метод:

    public static void putLob(String sKey, String pathToFile, KVStore myStore)
            throws FileNotFoundException, IOException {
        final Key myKey = ParseKey.ParseKey(sKey);
        File lobFile = new File(pathToFile);
        FileInputStream fis = new FileInputStream(lobFile);
        Version version = myStore.putLOB(myKey, fis, Durability.COMMIT_WRITE_NO_SYNC, 5, TimeUnit.SECONDS);
    }

Прим.: префикс ключа LOB должен заканчиваться на .lob (например: test/image/1.lob).
Прим2.: файлы для тестов удобно генерить командой dd
Например, dd if=/dev/zero of=big.file bs=100M count=20 - сгенерит 2 Гб файл.

Чтение происходит по chunk (порциям). В ходе чтения может поменяться сервер чтения chunk.
Давайте возьмем программу из документации, которая читает lob файл и выводит колличество байт:

    public static int SelectLOB(String sKey, KVStore myStore) throws IOException {
        data = null;
        int byteCount = 0;
        Key myKey = ParseKey.ParseKey(sKey);
        try {
            InputStreamVersion istreamVersion =
                    myStore.getLOB(myKey, Consistency.NONE_REQUIRED, 5, TimeUnit.SECONDS);
            InputStream stream = istreamVersion.getInputStream();
            while (stream.read() != -1) {
                byteCount++;
            }
        } catch (RequestTimeoutException re) {
            System.out.println(re.getTimeoutMs());
        } catch (FaultException fe) {
            System.out.println("Unknown error");
        } catch (NullPointerException ne) {
            System.out.println("Key does not exist");
        } finally {
        }

        return byteCount;
    }


Запускаем чтение, при этом у нас открыта консоль мониторинга (dstat -tdn 1) всех трех машин из шарда.
Смотрим и видим:


Чтение началось с одной машины, а продолжилось с другой. Т.е. при чтении несколькими агентами данных NoSQL страхует нас от "перекоса" в пользу какого-либо из шардов.

Любите технологии, пытливого ума вам, ну а если будут вопросы по Oracle NoSQL - welcome!

Пост 20. Версионность в Oracle NoSQL Database.

В Oracle NoSQL DB есть понятие версии значения. Версия всегда возвращается методу который осуществляет запись в базу KVStore.put() (и ему подобных: putIfpresent, putIfabsent…) и методам, которые получают значение по ключу.

Когда идет операция изменения или удаления бывает очень важно выполнить ее только в том случае, если значение не изменилось. В NoSQL есть следующие методы KVStore.putIfVersion() or KVStore.deleteIfVersion(). В принципе добавить к этому больше нечего – привожу пример кода, который из меняет пару ключ – значение, только в том случае если значение не изменилось (например у нас есть некий счетчик который инкрементально увеличивается при каждом событии, а события могут идти в несколько потоков). Вот здесь метод putIfVersion придется как никогда кстати. Давайте создадим еще один медод, который будет выполнять все вышеописанное.
Метод назовем UpdateIfNotchange – изменять, если не изменилосьJ

public static void UpdateIfNotchange(String sKey, String data, KVStore myStore)
throws FileNotFoundException, IOException {

Key myKey = ParseKey.ParseKey(sKey);
Value myValue = Value.createValue(data.getBytes());
try {
ValueVersion vv = myStore.get(myKey);
Version OldVersion = vv.getVersion();
Version NewVersion = myStore.putIfVersion(myKey, myValue, OldVersion);
if (NewVersion == null) {
System.out.println("Operation Failed! Vesion error");
} else {
System.out.println("Record created in the kvstore.");
}
} catch (NullPointerException np) {
System.out.println("KV pair doesn't exist!");
}
}


Как то так. Если будут вопросы - welcome!

воскресенье, 17 марта 2013 г.


Пост 19. Сериализатор AVRO и Oracle NoSQL Database. Практика

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

Как и обещал сейчас мы рассмотрим конкретный пример AVRO сериализации в базе данных Oracle.

Итак:
1)Рассмотрим объект: человек. У него есть атрибуты имя и возраст.
Пример файла схемы данных (допустим он лежит в /home/oracle/nosql/avro/member-schemas_new.avsc)
{
    "type": "record",
    "name": "userProfile",
    "namespace": "my.example",
    "fields": [
        {"name": "name", "type": "string", "default" : ""},
        {"name": "age", "type": "int", "default": -1}
            ]
}

2)Добавьте файл схемы данных в базу данных Oracle NoSQL Database

java -jar /home/cloudera/nosql/kv-2.0.23/lib/kvstore-2.0.23.jar runadmin -port 5000 -host localhost ddl add-schema -file /home/oracle/nosql/avro/member-schemas_new.avsc
3) Напишем код, который работает со схемой данных. 

import Support.OraStore;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import javax.sound.sampled.Port;
import oracle.kv.*;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.Schema;

import oracle.kv.avro.AvroCatalog;
import oracle.kv.avro.GenericAvroBinding;

public class a_AvroGenericBind {

    static String port = "5000";
    static String host = "localhost";
    static String store = "kvstore";
    private static Schema personSchema;
    private static GenericRecord member;
    private static String SchemaFile = "/home/oracle/nosql/avro/member-schemas_new.avsc";
    private static String SchemaName = "my.example.userProfile";
    private static KVStore myStore;
    static String UserName = "Alexey";

    public static void main(String[] args) throws IOException {
        RunExample();
    }

    public static void RunExample() throws IOException {
        OraStore orastore = new OraStore(store, host, port);
        KVStore myStore = orastore.getStore();

        final Schema.Parser parser = new Schema.Parser();
        parser.parse(new File(SchemaFile));
        personSchema = parser.getTypes().get(SchemaName);
        final AvroCatalog catalog = myStore.getAvroCatalog();
        final GenericAvroBinding binding = catalog.getGenericBinding(personSchema);
        final Key key = Key.createKey(Arrays.asList("userProfile", UserName));
        final ValueVersion valueVersion = myStore.get(key);
        final int age;
        if (valueVersion != null) {
            member = binding.toObject(valueVersion.getValue());
            System.out.println("INITIAL VALUE:\n" + member.toString());
            final int oldAge = (Integer) member.get("age");
            age = oldAge + 1;
            member.put("age", age);
            myStore.put(key, binding.toValue(member));
        } else {
            System.out.println("NO INITIAL VALUE");
            member = new GenericData.Record(personSchema);
            System.out.println(personSchema.toString());
            member.put("name", UserName);
            member.put("age", 24);
        }
        System.out.println("NEW VALUE");
        myStore.put(key, binding.toValue(member));
        System.out.println(member.toString());
        myStore.close();
    }
}

Если есть запись - идет апдейт части value, если нет - создается новая пара. Как то так.
Если кто то хочет получить виртуалку с примерами, в том числе и этим - пишите на oracle.nosql@gmail.com
Пост 18. Сериализатор AVRO и Oracle NoSQL Database. Теория.

Доброго времени суток!
Как было сказно ранее Oracle NoSQL Database начиная со второй версии позволяет сериализовать value протоколом AVRO. Давайте попробуем это сделать!

Для того что бы использовать AVRO сериализацию в Oracle NoSQL Database необходимо:

1)Добавить схему в хранилище.
2)Идентифицировать ее в приложении
3)Сериализовать/десериализовать values (сериализуются только значения, ключи не сереализуются!). Для выполнения данной функции используются Avro bindings

Код AVRO сериализаторов применяется только при работе с Value. На остальное приложение влияния не оказывается!
Bind могут быть разного типа. Рассмотрим generic (общий).

Работа с сериализатором в коде приложения (с помощью GenericBind)

1) Создать объект парсер и прочитать им файл схемы данных.
final Schema.Parser parser = new Schema.Parser();
parser.parse(new File(SchemaFile));

2) Создать объект типа “схема данных”, прочитать тип данных в схеме:
Schema personSchema = parser.getTypes().get(SchemaName);

3) Создать объект типа AVRO каталог
final AvroCatalog catalog = myStore.getAvroCatalog();

4) На основе этого каталога и полученных ранее типов данных схемы получаем переменные для связки value и AVRO
final GenericAvroBinding binding = catalog.getGenericBinding(personSchema);

5) Создаем запись для работы с bind. Читаем в нее объект.
GenericRecord member = binding.toObject(valueVersion.getValue());

6) Изменения производятся с помощью метода:
member.put("age", age);

7) Чтение атрибута объекта производится следующим образом:
member.get("age").toString()

В следующем посте мы рассмотрим конкретный пример - думаю все будет намного понятнее!

суббота, 16 марта 2013 г.

Пост 17. Сериализатор AVRO.

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

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

Сериализация (в программировании) — процесс перевода какой-либо структуры данных в последовательность битов. Обратной к операции сериализации является операция десериализации(структуризации) — восстановление начального состояния структуры данных из битовой последовательности.

Сериализация это процесс перевода структуры с поток битов. Где же может применяться сериализация/десериализация в NoSQL базах? Если Вы предположили, что при хранении value - вы совершенно правы! Иногда хочется положить в value какую то запись, которая хранила бы в себе более "осознанный" набор байт. Ну например, личная инормация человека. Можно хранить в виде XML или JSON и разбирать их на уровне приложения, тогда мы будем иметь что то вроде: {name:Ivan, surname: Petrov, age:33}... А если записей будет много? Тогда я буду хранить большое колличетво "лишней" информации:

/key1/ : {name: Ivan, surname: Petrov, age:33}
/key2/ : {name:Vasiliy, surname: Smirnov, age:32}
/key3/ : {name: Sergey, surname: Sidorov, age:40}
/key4/ : {name: Alexey, surname: Kuznethov, age:25}

Здорово было бы описать один раз какую то схему, а внутри хранить только указатели или разделители! Ну например вот так:

/key1/ : Ivan, : Petrov, :33
/key2/ : Vasiliy, Smirnov, 32
/key3/ : Sergey, Sidorov, 40
/key4/ : Alexey, Kuznethov,25

Так вот нечто подобное делает AVRO - это очень компактный протокол сериализации. На самом деле есть еще ряд причин использовать AVRO:

1) Возможность изменять схему. Ну тут как говорится ни отнять ни прибавить. Вы можете эволюционировать уже созданную схему данных
2) Быстрая десериализация (доступ к отдельным полям в данных) и компактное хранение (не хранятся теги - что значительно сокращает занимаемое пространство). Это как раз таки в копилку компактности
3) Динамическая типизация.

Итак, небольшой блок теории закончился, давайте посмотрим как это будет на практике в Oracle NoSQL Database!

+ напоминание - кто хочет получить виртуалку c примерами: пишите на oracle.nosql@gmail.com

суббота, 9 февраля 2013 г.


Пост 16. Oracle RDBMS External tables, как способ прочитать данные из NoSQL.

Доброго времени суток!
Продолжаю рассказывать об интеграции Oracle NoSQL Database и Oracle RDBMS.
Сегодня речь пойдет о новой возможности появившейся во второй версии Oracle NoSQL database - возможность чтения NoSQL данных из реляционки.
Осуществляется это через механизм Oracle RDBMS External Tables. Если в двух словах внешняя таблица - это технология, которая позволяет читать файл с файловой системы сервера базы данных. Лежит, например, csv файл на серваке, описываю я его в базе данных (create table my_tab_ext ...), а потом могу прочитать эти даные обыкновенным select (очень удобный и быстрый способ загружать данные, например). В Oracle  11.2g добавили пропроцессор. В этом случае,я так же описываю поток данных, только прежде чем прочитать файл могу провеси над ним некие преобразования. Например лежит у меня заархивированный csv, до того как гнать поток данных  в базу, необходимо его распаковать. Все это возможно с помощью препроцессора (в этом случае препроцессором будет команда unzip).
Ноу-хау NoSQL v2 заключается в создании програмы пропроцессора.
Наверное я Вас окончательно запутал? Вот тут действительно лучше один раз увидеть.
Давайте разберем конкретный пример. Наберитесь терпения и шаг за шагом внимательно прочтите последовательность действий.

1) Подготовительный этап - создание дирректорий, назначение прав в RDBMS

-Создание необходимых директорий
SQL> CREATE DIRECTORY ext_tab AS '/home/oracle/nosql/data/';
SQL> CREATE DIRECTORY nosql_bin_dir AS '/home/oracle/nosql/bin/'; 

-Назначение пользователю Oracle RDBMS необходимых прав:
SQL> GRANT READ, WRITE ON DIRECTORY ext_tab TO nosql;
SQL> GRANT READ, EXECUTE ON DIRECTORY nosql_bin_dir TO nosql;

В файл препроцессора nosql_stream прописываем переменные окружения:
export KVHOME= ...
export CLASSPATH= ...

Cам файл необходимо взять из архива дистрибутива Oracle NoSQL Database.
В моем случае я его переложил в /home/oracle/nosql/bin/nosql_stream

2) Подготовим данные в NoSQL базе, которые мы потом будет считывать из Oracle.
Загрузим данные в формате “/profile/Имя/Фамилия/-/phone/:номер телефона” (несколько строчек).
Если не знаете как это делать смотрите вот здесь

3) Cоздайте свой собственный formatter, который будет преобразовывать входную пару ключ-значение в формат внешней таблицы (string с разделителями, указанными при создании внешней таблицы). Java код ниже:


import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import oracle.kv.Key;
import oracle.kv.KeyValueVersion;
import oracle.kv.KVStore;
import oracle.kv.Value;
import oracle.kv.exttab.Formatter;

public class b_NewFormatter implements Formatter {

    private static final String USER_OBJECT_TYPE = "profile";

    public b_NewFormatter() {
    }

    @Override
    public String toOracleLoaderFormat(final KeyValueVersion kvv,
            final KVStore kvStore) {
        final Key key = kvv.getKey();
        final Value value = kvv.getValue();
        final String sValue = new String(value.getValue());

        final List<String> majorPath = key.getMajorPath();
        final List<String> minorPath = key.getMinorPath();

        final String objectType = majorPath.get(0);

        if (!USER_OBJECT_TYPE.equals(objectType)) {
            throw new IllegalArgumentException("Unknown object type: " + key);
        }

        final String Name = majorPath.get(1);
        final String Surname = majorPath.get(2);
        final String atr = minorPath.get(0);

        final StringBuilder sb = new StringBuilder();
        sb.append(Name).append("|");
        sb.append(Surname).append("|");
        sb.append(atr).append("|");
        sb.append(sValue).append("|");
        return sb.toString();

    }

    private String readString(final DataInput in)
            throws IOException {

        if (!in.readBoolean()) {
            return null;
        }

        return in.readUTF();
    }
}


4) В Oracle RDBMS создаем внешнюю таблицу


CREATE TABLE profile_external (name VARCHAR2(64),
                                surname varCHAR2(64),
                                atr VARCHAR2(64),
                                sValue varchar2(256))
        ORGANIZATION EXTERNAL
            (type oracle_loader
             default directory ext_tab
             access parameters (records delimited by newline
             preprocessor nosql_bin_dir:'nosql_stream'
            fields terminated by '|')
       LOCATION ('profile.dat'))
       PARALLEL;

5) Создаем конфигурационный файл для описания NoSQL базы и Oracle
В моем примере:


[oracle@localhost ~]$ cat /home/oracle/nosql/conf/config2.xml
<config version="1">
  <component name="publish" type="params">
    <!-- Fill in appropriate values for
        oracle.kv.exttab.connection.url and oracle.kv.exttab.connection.user
       -->
    <property name="oracle.kv.exttab.connection.url"
              value="jdbc:oracle:thin:/@//localhost:1521/XE"
              type="STRING"/>
    <property name="oracle.kv.exttab.connection.user"
              value="nosql" type="STRING"/>
    <property name="oracle.kv.exttab.tableName" value="profile_external"
              type="STRING"/>
    <!-- If you use a wallet to access your Oracle Instance, uncomment
         this and fill in a suitable value for the

              oracle.kv.exttab.connection.wallet_location

         property. -->
    <!--
    <property name="oracle.kv.exttab.connection.wallet_location"
              value="PATHNAME TO YOUR WALLET DIRECTORY" type="STRING"/>
    -->
  </component>
  <component name="nosql_stream" type="params">
    <!-- Fill in appropriate values for
        oracle.kv.kvstore and oracle.kv.hosts
       -->
    <property name="oracle.kv.kvstore"
              value="kvstore"
              type="STRING"/>
    <property name="oracle.kv.hosts"
              value="LOCALHOST:5000"
              type="STRING"/>
    <property name="oracle.kv.batchSize"
              value="100"
              type="INT"/>
    <property name="oracle.kv.depth"
              value="PARENT_AND_DESCENDANTS"
              type="STRING"/>
    <property name="oracle.kv.parentKey"
              value="/profile"
              type="STRING"/>
    <property name="oracle.kv.formatterClass"
              value="Answers_part3.b_NewFormatter"
              type="STRING"/>
    <!-- Other properties that are not needed for the cookbook example. -->
    <!--
    <property name="oracle.kv.subRange"
              value="I/login/"
              type="STRING"/>
    <property name="oracle.kv.consistency"
              value="tIme(10 seconds, 10 seconds)"
              type="STRING"/>
    <property name="oracle.kv.keyDelimiter"
              value="|"
              type="STRING"/>
    <property name="oracle.kv.variableSizeBytes"
              value="0"
              type="INT"/>
    <property name="oracle.kv.timeout"
              value="10 seconds"
              type="STRING"/>
    -->
  </component>
</config>


6) Используя утилиту publisher создаем конфигурационный файл на который указывает внешняя таблица

[oracle@localhost ~]$ cat /home/oracle/nosql/sh/publish_config.sh
#!/bin/bash
source ~/.bash_profile
java -classpath $KVHOME/lib/*:$ORACLE_HOME/jdbc/lib/ojdbc6.jar oracle.kv.exttab.Publish -config /home/oracle/nosql/conf/config2.xml -publish

7) Добавьте в конфиг препроцессора (/home/oracle/nosql/bin/nosql_stream) путь к новому Formatter.

[oracle@localhost ~]$ cat /home/oracle/nosql/bin/nosql_stream
#!/bin/bash
export PATH=$PATH
export KVHOME=/home/cloudera/nosql/kv-2.0.23
export CLASSPATH=$KVHOME/lib/kvstore-2.0.23.jar:$KVHOME/lib/kvstore-ee-2.0.23.jar:/home/cloudera/nosql/kv-2.0.23/examples/:/home/oracle/nosql/jar/DeveloperDay.jar
/usr/java/jdk1.7.0_02/bin/java oracle.kv.exttab.Preproc $*


8) Пишем SQL для доступа к данным!

select * from profile_external

Вот вроде бы и все. Если внимательно выполнить шаг за шагом здесь описанное - все получится. Если будут вопросы - не стесняйтесь их задавать!

пятница, 8 февраля 2013 г.


Пост 15. Гибридная архитектура. NoSQL + SQL

Когда я только делал первые шаги по дороге NoSQL и Hadoop, мне всегда хотелось посмотреть на них с точки зрения базы данных Oracle, т.к. я всегда был (и остаюсь) верным членом клуба любителей Oracle RDBMS (как можно не любить лучшую реляционную базу в мире)?
Хотелось оставаться в Oracle RDBMS центральной системе мира (в центре всего Oracle, остальное "сателиты"). Теперь это возможно. Начиная со 2 версии Oracle NoSQL database позволяет читать данные из своей базы как из внешней таблицы. Как писалось в моем самом первом посте не стоит злоупотреблять с NoSQL. Надо использовать их только там где это действительно оправдано. Или в тех "кусках" приложения где он подходит. Если вы начинаете новый проект - возможно не стоит выбирать между NoSQL и SQL,просто комбинируйте!
Давайте рассмотрим пример - есть у нас приложение к "крутым" поиском (куча фильттов, релевантность, предиктовые прогнозы и.т.п.). Крутой поиск может с легкостью взять на себя реляционная база данных, а что делать с хранением файлов? Можно конечно засунуть все в эту базу данных... Но получится достаточно дорогое решение... Да и если колличество пользователей будет измеряться десятками тысяч, это тоже будет достаточно проблемно... Тут как раз кстати пришлось бы гибридное решение:

                                             Рис 1. Возможная архитектура.

Итак, представим, что пользователь формирует запрос (через браузер, например): говорит, что хочет фотографии, сделанную определенным фотографом в определенном месте с рейтингом не ниже определенного, ну и еще много чего. Далее этого запрос отправляется на сервер приложений (шаг 1). Сервер приложений обрабатывает его формирует запрос к реляционной базе(шаг 2), которая отработав его возвращает одну колонку типа varchar2 (шаг 3). Приложение формирует на основе возвращенных данных запрос к NoSQL базе (шаг 4), типа: дай мне набор байт по этому ключу. Приложение знает что этот набор байт картинка. Эту картинку он и возвращает клиенту (шаг 5). Вот как то так. Не бойтесь использовать вместе традиционные технлогии и NoSQL!

Далее я расскажу о возможности добраться до NoSQL данных из базы данных Oracle.

Пост 14. Oracle NoSQL Database v2.

"Давненько не брал я в руки шашек!" - говаривал Ноздрев Чичикову. "Давненько ничего я тут не писал" - скажу я Вам. За время моего "молчания" Oracle NoSQL Database разразился второй версией. Вторая версия принесла много приятных сюрпризов. Но обо всем по порядку.

                           
                                          Рис.1 Новшества Oracle NoSQL Database v2.

Итак, по порядку.
1) Масштабируемость и управляемость.
 - Эластичность
Добавлена возможность добавлять "на лету" новые репликационные группы (шарды).
Теперь из вот такогой топологии можно на лету:


сделать вот такую:

- Перебалансировка данных между шардами
Теперь данные с нагруженых шардов могут быть перенесены на менее нагруженые.
Из вот такого расположения:

можно сделать:

2) Новые API
- Добавлено С API
- Добавлен сериализатор AVRO (сериализация value)
- Добавлена поддержка больших объектов (LOB).

3) Интеграция и мониторинг
- Внешние таблицы. Теперь данные из Oracle NoSQL Database можно читать с помощью внешних таблиц Oracle RDBMS.
- Возможность использования Oracle NoSQL Database как источник для OEP (CEP).
- Поддержка SNMP/JMX
- Интеграция с RFD (опция базы данных Oracle)

Далее я буду подробнее описывать все выше описанное!
Успехов всем!