Статьи

Героку и Кассандра

Вступление

В прошлый раз я писал о  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: address@example.com
Password (typing will be hidden): 
Authentication successful.

$ heroku create
Creating glacial-badlands-1234... done, stack is cedar
http://glacial-badlands-1234.herokuapp.com/ | git@heroku.com: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:AccountId@api.cassandra.io/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.