5
3

More than 3 years have passed since last update.

【Golang】はじめての Cassandra DB

Posted at

概要

GolangでCassandraをセッション管理用のDBとして使ってみたので、記事にしました。Cassandraは、複数台でクラスターを組んで分散DBを作成し、スケールアウトすることが容易にできる構造になっています。また処理性能も構成するノード数に比例します。そのためサーバー管理者としては、比較的安価にスケーラビリティを確保できます。

Cassandraは テーブルにデータを格納しCQLというSQLのようなクエリ言語を利用してデータのやりとりをすることができるため、直観的にはリレーショナルDBを使っているかのように操作ができます。以前、 【Golang】 mysql データベース処理として、SQLライブラリを用いたGolangによる処理を記事にしましたが、Cassandra DBに関しても、CQLを用いてほとんど同じような処理になります。

※環境は、Macで行っています。
※Golangの基本的な設定や使い方は、はじめてのGolang Webアプリケーション ~ テスト, Dockerコンテナ化までを参考にしてください。

Cassandraの基礎 (インストールとDB, テーブル作成)

以下のコマンドでインストールします。

brew install cassandra
sudo pip install cql

以下のコマンドで、oauthというDBとaccess_tokenというテーブルを作成しています。

describe keyspaces;
>system_traces  system_schema  system_auth  system  system_distributed

CREATE KEYSPACE oauth WITH REPLICATION = {'class':'SimpleStrategy', 'replication_factor':1};

describe keyspaces;
>system_schema  system_auth  system  system_distributed  oauth  system_traces

USE oauth;

CREATE TABLE access_tokens( access_token varchar PRIMARY KEY, user_id bigint, expires bigint);

describe tables;
>access_tokens

SELECT * from access_tokens where access_token='doNaDonaEtc';

 access_token | expires | user_id
--------------+---------+---------

Golang gocql パッケージのインストール

gocqlのパッケージをインストールします。

go get github.com/gocql/gocq

本記事で行う処理例

本記事では、以下の通り処理に対しての例を示す。また、以下に、この処理を行うプログラムを示しています。

  1. access_tokenというデータを作成。
  2. dbRepoにCassandraDBのインターフェースを注入(DB処理のpkgは分離している)
  3. Create methodでデータを挿入
  4. Get methodでデータを取得

※accessTokenは、access_tokenの構造体や処理を集めたパッケージです。本記事の流れとは関係ないため、説明で省略します。

package main

import (
    "fmt"

    access_token "github.com/k-washi/golang-cookbook/cassandraDB/c1/c1/accessToken"

    "github.com/k-washi/golang-cookbook/cassandraDB/c1/c1/oauthdomain"
)

func main() {
    at := access_token.GetAccessToken()
    at.AccessToken = "doNaDonaEtc"
    at.UserID = 123

    dbRepo := oauthdomain.NewRepo()
    err := dbRepo.Create(at)
    if err != nil {
        fmt.Println(err)
    }

    accessToken, err := dbRepo.GetID(at.AccessToken)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(accessToken) //&{doNaDonaEtc 123 1580498041}
    /*
            cqlsh:oauth> SELECT * from access_tokens where access_token='doNaDonaEtc';

         access_token | expires    | user_id
        --------------+------------+---------
            doNaDonaEtc | 1580498041 |     123
    */
}

Cassandraの設定

Golang でCassandraの設定を行うプログラムを示す。GetSession()によるSessionを、DBの各メソッドにて接続する際に用いる。

package cassandra

import (
    "fmt"
    "github.com/gocql/gocql"
)

var (
    session *gocql.Session
)

func init() {
    // connect to Cassandra
    cluster := gocql.NewCluster("127.0.0.1")
    cluster.Keyspace = "oauth"
    cluster.Consistency = gocql.Quorum

    var err error
    if session, err = cluster.CreateSession(); err != nil {
        panic(err)
    }
    fmt.Println("cassandra config success")
}

func GetSession() *gocql.Session {
    return session
}

Cassandra DBのメソッド

以下にGET, CREATE, UPDATEメソッドを実装しています。queryとして、SQLに似たCQLを書いています。Cassandraの設定を受け取って、それに対して、Queryを送信に、その結果を受け取っています。

package oauthdomain

import (
    "errors"

    access_token "github.com/k-washi/golang-cookbook/cassandraDB/c1/c1/accessToken"

    "github.com/gocql/gocql"

    "github.com/k-washi/golang-cookbook/cassandraDB/c1/c1/cassandra"
)

const (
    queryGetAcessToken     = "SELECT access_token, user_id, expires FROM access_tokens WHERE access_token=?;"
    queryCreateAccessToken = "INSERT INTO access_tokens(access_token, user_id, expires) VALUES (?, ?, ?);"
    queryUpdateExpires     = "UPDATE access_tokens SET expires=? WHERE access_token=?;"
)

func NewRepo() DbRepo {
    return &dbRepo{}
}

type DbRepo interface {
    GetID(string) (*access_token.AccessToken, error)
    Create(access_token.AccessToken) error
    UpdateExpirationTime(access_token.AccessToken) error
}

type dbRepo struct{}

func (r *dbRepo) GetID(at string) (*access_token.AccessToken, error) {
    session := cassandra.GetSession()

    var result access_token.AccessToken
    if err := session.Query(queryGetAcessToken, at).Scan(
        &result.AccessToken,
        &result.UserID,
        &result.Expires,
    ); err != nil {
        if err == gocql.ErrNotFound {
            return nil, errors.New("no access token found with given id")
        }
        return nil, err
    }

    return &result, nil

}

func (r *dbRepo) Create(at access_token.AccessToken) error {
    session := cassandra.GetSession()

    if err := session.Query(queryCreateAccessToken,
        at.AccessToken,
        at.UserID,
        at.Expires,
    ).Exec(); err != nil {
        return err
    }
    return nil
}

func (r *dbRepo) UpdateExpirationTime(at access_token.AccessToken) error {
    session := cassandra.GetSession()

    if err := session.Query(queryUpdateExpires,
        at.Expires,
        at.AccessToken,
    ).Exec(); err != nil {
        return err
    }
    return nil
}
5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3