Вступление
В прошлый раз я писал о Hadoop на Heroku, который является надстройкой от Treasure Data — на этот раз я собираюсь рассказать о NoSQL на Heroku.
Существуют различные службы хранилища данных — дополнения в терминах Heroku — от MongoDB (MongoHQ) до CouchDB (Cloudant) и Cassandra (Cassandra.io). Этот пост посвящен Cassandra.io.
Cassandra.io
Cassandra.io — это управляемое и управляемое кольцо Cassandra, основанное на Apache Cassandra, которое делает его доступным через RESTful API. На момент написания этой статьи клиентские вспомогательные библиотеки Cassandra.io доступны на Java, Ruby и PHP, а также имеется версия Objective-C в закрытой бета-версии. Библиотеки можно скачать с github. Я использую библиотеку Java в своих тестах.
Heroku — и дополнение Cassandra.io — построено на Amazon Elastic Compute Cloud (EC2) и поддерживается во всех местоположениях Amazon. Примечание: надстройка Cassandra.io теперь находится в публичной бета-версии, что означает, что у вас есть только одна опция под названием Test — это бесплатно.
Установка дополнения Cassandra.io
Для установки дополнения Cassandra.io вам просто нужно следовать стандартному способу добавления дополнения в приложение:
$ heroku login Enter your Heroku credentials. Email: [email protected] Password (typing will be hidden): Authentication successful. $ heroku create Creating glacial-badlands-1234... done, stack is cedar http://glacial-badlands-1234.herokuapp.com/ | [email protected]:glacial-badlands-1234.git $ heroku addons:add cassandraio:test --app glacial-badlands-1234 Adding cassandraio:test on glacial-badlands-1234... done, v2 (free) Use `heroku addons:docs cassandraio:test` to view documentation.
Вы можете проверить конфигурацию через консоль администратора Heroku:
Затем вам нужно клонировать клиентские вспомогательные библиотеки из github:
$ git clone https://github.com/m2mIO/cassandraio-client-libraries.git
В случае клиентской библиотеки Java вам также понадобится библиотека gson Google (gson-2.0.jar).
Написание приложения Cassandra.io
Библиотека Java RESTful API имеет один простой файл конфигурации с именем sdk.properties. В нем хранится очень мало параметров — URL-адрес API и версия. Исходный файл sdk.properties, клонированный из github, имеет неправильную версию (v0.1), его необходимо изменить на 1. Вы можете проверить необходимые параметры конфигурации с помощью команды heroku config .
$ heroku config --app glacial-badlands-1234 === glacial-badlands-1234 Config Vars CASSANDRAIO_URL: https://Token:[email protected]/1/welcome
Вы можете проверить те же параметры конфигурации из консоли администратора Heroku, хотя URL вводит в заблуждение:
Файл sdk.properties должен выглядеть следующим образом:
apiUrl = https://api.cassandra.io version = 1
Код Java — CassandraIOTest.java — выглядит следующим образом:
package io.cassandra.tests; import java.util.ArrayList; import java.util.List; import io.cassandra.sdk.StatusMessageModel; import io.cassandra.sdk.column.ColumnAPI; import io.cassandra.sdk.columnfamily.ColumnFamilyAPI; import io.cassandra.sdk.constants.APIConstants; import io.cassandra.sdk.data.DataAPI; import io.cassandra.sdk.data.DataBulkModel; import io.cassandra.sdk.data.DataColumn; import io.cassandra.sdk.data.DataMapModel; import io.cassandra.sdk.data.DataRowkey; import io.cassandra.sdk.keyspace.KeyspaceAPI; public class CassandraIOTest { // credentials private static String TOKEN = "<Token>"; private static String ACCOUNTID = "<AccountId>"; // data private static String KS = "AAPL"; private static String CF = "MarketData"; private static String COL1 = "Open"; private static String COL2 = "Close"; private static String COL3 = "High"; private static String COL4 = "Low"; private static String COL5 = "Volume"; private static String COL6 = "AdjClose"; private static String RK = "18-05-2012"; public static void main(String[] args) { try { StatusMessageModel sm; // Create Keyspace KeyspaceAPI keyspaceAPI = new KeyspaceAPI(APIConstants.API_URL, TOKEN, ACCOUNTID); sm = keyspaceAPI.createKeyspace(KS); System.out.println(sm.getMessage() + " | " + sm.getDetail() + " | " + sm.getError()); // Create ColumnFamily ColumnFamilyAPI columnFamilyAPI = new ColumnFamilyAPI(APIConstants.API_URL, TOKEN, ACCOUNTID); sm = columnFamilyAPI.createColumnFamily(KS, CF, APIConstants.COMPARATOR_UTF8); System.out.println(sm.getMessage() + " | " + sm.getDetail() + " | " + sm.getError()); // Add Columns (High, Low, Open, Close, Volume, AdjClose) ColumnAPI columnAPI = new ColumnAPI(APIConstants.API_URL, TOKEN, ACCOUNTID); sm = columnAPI.upsertColumn(KS, CF, COL1, APIConstants.COMPARATOR_UTF8, true); System.out.println(sm.getMessage() + " | " + sm.getDetail() + " | " + sm.getError()); sm = columnAPI.upsertColumn(KS, CF, COL2, APIConstants.COMPARATOR_UTF8, true); System.out.println(sm.getMessage() + " | " + sm.getDetail() + " | " + sm.getError()); sm = columnAPI.upsertColumn(KS, CF, COL3, APIConstants.COMPARATOR_UTF8, true); System.out.println(sm.getMessage() + " | " + sm.getDetail() + " | " + sm.getError()); sm = columnAPI.upsertColumn(KS, CF, COL4, APIConstants.COMPARATOR_UTF8, true); System.out.println(sm.getMessage() + " | " + sm.getDetail() + " | " + sm.getError()); sm = columnAPI.upsertColumn(KS, CF, COL5, APIConstants.COMPARATOR_UTF8, true); System.out.println(sm.getMessage() + " | " + sm.getDetail() + " | " + sm.getError()); sm = columnAPI.upsertColumn(KS, CF, COL6, APIConstants.COMPARATOR_UTF8, true); System.out.println(sm.getMessage() + " | " + sm.getDetail() + " | " + sm.getError()); //Add Bulk Data DataAPI dataAPI = new DataAPI(APIConstants.API_URL, TOKEN, ACCOUNTID); List columns = new ArrayList(); DataColumn dc = new DataColumn(COL1, "533.96"); columns.add(dc); dc = new DataColumn(COL2, "530.38", 12000); columns.add(dc); dc = new DataColumn(COL3, "543.41", 12000); columns.add(dc); dc = new DataColumn(COL4, "522.18", 12000); columns.add(dc); dc = new DataColumn(COL5, "26125200", 12000); columns.add(dc); dc = new DataColumn(COL6, "530.12", 12000); columns.add(dc); List rows = new ArrayList(); DataRowkey row = new DataRowkey(RK, columns); rows.add(row); DataBulkModel dataBulk = new DataBulkModel(rows); sm = dataAPI.postBulkData(KS, CF, dataBulk); System.out.println(sm.getMessage() + " | " + sm.getDetail() + " | " + sm.getError()); // Get Data DataMapModel dm = dataAPI.getData(KS, CF, RK, 0, null); System.out.println(dm.toString()); // Delete Keyspace sm = keyspaceAPI.deleteKeyspace(KS); System.out.println(sm.getMessage() + " | " + sm.getDetail() + " | " + sm.getError()); } catch(Exception e) { System.out.println(e.getMessage()); } } }
Результат выполнения:
09-Sep-2012 22:59:18 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/keyspace/AAPL/ Success | Keyspace added successfully. | null 09-Sep-2012 22:59:21 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/columnfamily/AAPL/MarketData/UTF8Type/ Success | MarketData ColumnFamily created successfully | null 09-Sep-2012 22:59:24 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/column/AAPL/MarketData/Open/UTF8Type/?isIndex=true Failed | Unable to create Column: Open | Cassandra encountered an internal error processing this request: TApplicationError type: 6 message:Internal error processing system_update_column_family 09-Sep-2012 22:59:24 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/column/AAPL/MarketData/Close/UTF8Type/?isIndex=true Success | Close Column upserted successfully | null 09-Sep-2012 22:59:26 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/column/AAPL/MarketData/High/UTF8Type/?isIndex=true Success | High Column upserted successfully | null 09-Sep-2012 22:59:27 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/column/AAPL/MarketData/Low/UTF8Type/?isIndex=true Success | Low Column upserted successfully | null09-Sep-2012 22:59:29 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/column/AAPL/MarketData/Volume/UTF8Type/?isIndex=true Success | Volume Column upserted successfully | null 09-Sep-2012 22:59:30 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/column/AAPL/MarketData/AdjClose/UTF8Type/?isIndex=true Success | AdjClose Column upserted successfully | null Posting JSON: {"rowkeys":[{"rowkey":"18-05-2012","columns":[{"columnname":"Open","columnvalue":"533.96","ttl":0},{"columnname":"Close","columnvalue":"530.38","ttl":12000},{"columnname":"High","columnvalue":"543.41","ttl":12000},{"columnname":"Low","columnvalue":"522.18","ttl":12000},{"columnname":"Volume","columnvalue":"26125200","ttl":12000},{"columnname":"AdjClose","columnvalue":"530.12","ttl":12000}]}]} 09-Sep-2012 22:59:32 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/data/AAPL/MarketData/ Success | Bulk upload successfull. | null 09-Sep-2012 22:59:32 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/data/AAPL/MarketData/18-05-2012/ {Volume=26125200, Open=533.96, Low=522.18, High=543.41, Close=530.38, AdjClose=530.12} 09-Sep-2012 22:59:32 io.cassandra.sdk.CassandraIoSDK constructAPIUrl INFO: API URL: https://api.cassandra.io/1/keyspace/AAPL/ Success | Keyspace dropped successfully. | null
Анализ
Шаг 1. / Код создает пространство ключей с именем AAPL, используя HTTP POST, URL: https://api.cassandra.io/1/keyspace/AAPL/
Он использует класс KeySpaceAPI с Token и AccountId в качестве параметров для конструктора. Токен используется как имя пользователя, а AccountID — пароль. (Помните: эти атрибуты можно получить с помощью команды настройки heroku или через консоль администратора Heroku)
Шаг 2. / Затем код создает семейство столбцов с именем MarketData. Он использует ColumnFamilyAPI — с указанными выше учетными данными — и URL-адрес REST — https://api.cassandra.io/1/columnfamily/AAPL/MarketData/UTF8Type/.
Шаг 3. / Затем код вставляет кумны, называемые Open, Close, High, Low, Volume и AjdClose. Он использует ColumnAPI — те же учетные данные, которые мы уже знаем — и URL REST — https://api.cassandra.io/1/column/AAPL/MarketData/Open/UTF8Type/?isIndex=true, где AAPL — это пространство ключей, MarketData — это семейство столбцов и Open — столбец.
Шаг 4. / Затем код подготавливает данные в виде пар имя / значение (Open = «533.96 ″, Close =« 530.38 ″ и т. Д.), Определяет ключ строки («18-05-2012 ″) и использует метод DataAPI postBulkData для загрузить данные в Cassandra.io. Учетные данные DataAPI такие же, как указано выше.
Шаг 5. / Затем код извлекает данные, используя HTTP GET с URL: https://api.cassandra.io/1/data/AAPL/MarketData/18-05-2012/. Ответ в формате JSON: {Volume = 26125200, Open = 533,96, Low = 522,18, High = 543,41, Close = 530,38, AdjClose = 530.12}
Шаг 6. / Наконец код уничтожает пространство ключей, используя HTTP DELETE, URL: https://api.cassandra.io/1/keyspace/AAPL/.
Резюме
Если вы хотите опробовать надежный, высокодоступный хранилище данных Casssandra без каких-либо предварительных инвестиций в инфраструктуру и с простым в использовании API, вы, безусловно, можете ближе познакомиться с Cassandra.io на Heroku. Запуск занимает всего несколько минут, и API предлагают разработчикам Java, Ruby и PHP простое управление данными на основе REST.