Статьи

NoSQL с Apache Cassandra и Mule

Apache Cassandra — это распределенная база данных NoSQL на основе столбцов . До недавнего времени единственным способом взаимодействия с базами данных Cassandra от Mule было повторное использование одного из существующих Java-клиентов, таких как Hector или Astyanax , в компоненте. Модуль БД Cassandra от Mule  теперь предоставляет процессоры сообщений для вставки, обновления, запроса и удаления данных в Cassandra.

Чтобы продемонстрировать некоторые функции модуля Cassandra, я покажу, как реализовать простой API управления учетными записями . Этот API позволит клиентам выполнять CRUD-операции с учетными записями, ведя себя подобно каталогу LDAP.

Вставка столбцов

Модуль Cassandra использует карты Java в качестве механизма для определения того, как данные вставляются и извлекаются из пространства ключей Cassandra. В этом примере мы будем использовать JSON-преобразователи Mule для перемещения данных назад и вперед по HTTP. Давайте посмотрим, как выглядят данные аккаунта.

{
    "Accounts":{
        "engineering":{
            "[email protected]":{
                "Name":"Joe Developer",
                "Password":"286755fad04869ca523320acce0dc6a4",
                "passwordAge": 731400
            },
            "[email protected]":{
                "Name":"Jane Developer",
                "Password":"10b222970537b97919db36ec757370d2",
                "passwordAge": 10082400

            },
            "[email protected]":{
                "Name":"Jane Developer",
                "Password":"10b222970537b97919db36ec757370d2",
                "passwordAge": 1080000
            }
        },
        "operations":{
            "[email protected]":{
                "Name":"Bill SysAdmin",
                "Password":"f1f16683f3e0208131b46d37a79c8921",
                "passwordAge": 4343100
            },
            "[email protected]":{
                "Name":"Jill NetworkAdmin",
                "Password":"32a3571fa12b39266a58d42234836839",
                "passwordAge": 41923143
            }
        }
    }
}

Когда мы сохраняем этот JSON для Cassandra, семейство столбцов будет «Учетные записи», каждая организационная единица будет ключом строки (т. Е. «Проектирование» и «Операции») и такими данными учетной записи, как имя пользователя, пароль и время с момента последнего пароля. изменение будет содержаться в супер колонке.

Давайте настроим поток Mule для сохранения этих данных через HTTP.

<flow name="AccountCreate" doc:name="AccountsCreate">
        <http:inbound-endpoint 
            exchange-pattern="request-response" 
            host="localhost" 
            port="8081"
            path="account/create" 
            mimeType="application/json" />
        <json:json-to-object-transformer 
               returnClass="java.util.Map"/>
        <cassandradb:insert config-ref="CassandraDB" />
        <json:object-to-json-transformer />        
</flow>

Этот поток примет данные учетной записи JSON, которые мы только что видели по HTTP, преобразует их в карту, использует обработчик сообщений «вставка» коннектора Cassandra для сохранения данных, а затем возвращает полезную нагрузку обратно в JSON для возврата клиенту.

Сериализация колонки

Одним из преимуществ, а также проблем, с Cassandra является то, что все данные хранятся в виде байтовых массивов. Это делает его чрезвычайно гибким с точки зрения хранения данных, но также означает, что информация о типах теряется. Модуль Cassandra использует  сериализаторы Hector, чтобы вы могли указать, как данные преобразуются при извлечении данных из столбца.

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

 <flow name="AccountGet" doc:name="AccountGet">
        <http:inbound-endpoint 
              exchange-pattern="request-response"
              host="localhost"
              port="8081" 
              path="account/get"   
              doc:name="HTTP"/>            
        <cassandradb:get config-ref="CassandraDB" 
               columnPath=
"Accounts:#[message.inboundProperties['http.relative.path'].split('/')[1]]"
                rowKey=
"#[message.inboundProperties['http.relative.path'].split('/')[0]]"/>         
        <json:object-to-json-transformer doc:name="Object to JSON"/>
</flow>

Этот поток примет данные учетной записи JSON, которые мы только что видели по HTTP, преобразует их в карту, использует обработчик сообщений «вставка» коннектора Cassandra для сохранения данных, а затем возвращает полезную нагрузку обратно в JSON для возврата клиенту.

Сериализация колонки

Одним из преимуществ, а также проблем, с Cassandra является то, что все данные хранятся в виде байтовых массивов. Это делает его чрезвычайно гибким с точки зрения хранения данных, но также означает, что информация о типах теряется. Модуль Cassandra использует  сериализаторы Hector, чтобы вы могли указать, как данные преобразуются при извлечении данных из столбца.

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

 <flow name="AccountGet" doc:name="AccountGet">
        <http:inbound-endpoint 
              exchange-pattern="request-response"
              host="localhost"
              port="8081" 
              path="account/get"   
              doc:name="HTTP"/>            
        <cassandradb:get config-ref="CassandraDB" 
               columnPath=
"Accounts:#[message.inboundProperties['http.relative.path'].split('/')[1]]"
                rowKey=
"#[message.inboundProperties['http.relative.path'].split('/')[0]]"/>         
        <json:object-to-json-transformer doc:name="Object to JSON"/>
</flow>

Мы используем язык  выражений Mule   для анализа URI. Вот как мы выводим columnPath и rowKey. В этом случае columnPath будет «операторы», а rowKey будет «[email protected]». Теперь мы можем запросить учетную запись Билла следующим образом:

HTTP: // локальный: 8081/account/get/operations/[email protected]

Хотя есть одна проблема. Когда ответ возвращается, он выглядит так:

{
   "[email protected]":{
      "passwordAge":"\u0000BE<",
      "Name":"Bill SysAdmin",
      "Password":"f1f16683f3e0208131b46d37a79c8921"
   }
}

Возраст пароля — это строка, а не целое число. Это связано с тем, что модуль Cassandra по умолчанию использует сериализацию строк, если не указан явный столбец-сериализатор. Давайте добавим один, чтобы исправить поток.

<flow name="AccountGet" doc:name="AccountGet">
        <http:inbound-endpoint 
           exchange-pattern="request-response"
           host="localhost" 
           port="8081" 
           path="account/get" />            
        <cassandradb:get config-ref="CassandraDB" 
          columnPath="Accounts:#[message.inboundProperties['http.relative.path'].split('/')[1]]"
         rowKey="#[message.inboundProperties['http.relative.path'].split('/')[0]]" doc:name="Cassandradb">
           <cassandradb:column-serializers>
                <cassandradb:column-serializer 
                     key="passwordAge" 
                     type="java.lang.Integer"/>
            </cassandradb:column-serializers>
         </cassandradb:get>       
        <json:object-to-json-transformer/>
    </flow>

Теперь, когда мы обновляем URL, должно появиться что-то вроде этого:

{
   "[email protected]":{
      "passwordAge":4343100,
      "Name":"Bill SysAdmin",
      "Password":"f1f16683f3e0208131b46d37a79c8921"
   }
}

Сериализация столбцов доступна для всех типов данных, поддерживаемых Hector.

Ломтики колонны

Модуль Cassandra дополнительно позволяет выполнять запросы по срезу столбца. Следующий поток вернет все учетные записи для данной организационной единицы (ключ строки):

 <flow name="AccountList" doc:name="AccountsList">
        <http:inbound-endpoint 
             exchange-pattern="request-response" 
             host="localhost" port="8081"
             path="account/list"/>          
         <cassandradb:get-slice 
              config-ref="CassandraDB" 
              rowKey="#[message.inboundProperties['http.relative.path'].split('/')[0]]" 
columnParent="Accounts" count="100">
         	<cassandradb:column-serializer 
               key="passwordAge" type="java.lang.Integer"/>        
         </cassandradb:get-slice>                  
        <json:object-to-json-transformer/>
</flow>

Это вернет до 100 столбцов из предоставленной строки. Например, этот URL:  http: // localhost: 8081 / account / list / operations  Возвращает что-то следующее:

[
   {
      "[email protected]":{
         "passwordAge":4343100,
         "Name":"Bill SysAdmin",
         "Password":"f1f16683f3e0208131b46d37a79c8921"
      }
   },
   {
      "[email protected]":{
         "passwordAge":41923143,
         "Name":"Jill NetworkAdmin",
         "Password":"32a3571fa12b39266a58d42234836839"
      }
   }
]

Удаление столбца

Удалить столбцы так же просто. Следующий поток демонстрирует, как удалить столбец из строки:

<flow name="AccountDelete" doc:name="AccountGet">
        <http:inbound-endpoint 
              exchange-pattern="request-response" 
              host="localhost" 
              port="8081" 
              path="account/delete"/>            
        <cassandradb:remove config-ref="CassandraDB" 
              columnPath="Accounts:#[message.inboundProperties['http.relative.path'].split('/')[1]]"
             rowKey="#[message.inboundProperties['http.relative.path'].split('/')[0]]" doc:name="Cassandradb"/>         
        <json:object-to-json-transformer />
</flow>

Таким образом, чтобы удалить учетную запись Билла, мы использовали бы следующий URL:

HTTP: // локальный: 8081/account/delete/operations/[email protected]

Резюме и что дальше

Кассандра — сильный соперник в среде NoSQL. Он особенно подходит для больших наборов данных, которые должны охватывать несколько центров обработки данных. Некоторые функции, которые мы надеемся добавить в модуль и которые мы рассмотрим здесь, включают поддержку хранилища объектов Mule с поддержкой Cassandra,  а также поддержку  CQL  в качестве альтернативного механизма запросов.